Siscall Pro Logo
SISCALL PRO
Hardware & Firmware Technical Specification • Siscall Station Protocol
📄 Full Spec 📖 Register Map ⚡ Summary & C Code

1. Physical & Data Link Communication Parameters

The Wall Unit and Corridor Door Dome LEDs operate as high-reliability Station Nodes on an industrial half-duplex communication network.

Parameter Value Hardware Engineering Notes
Physical Wiring A+, B-, GND (2-Wire Half-Duplex) TVS surge suppression diodes recommended on lines.
Baud Rate 19200 bps Standard default (Configurable: 9600, 19200, 38400, 115200).
Framing 8-N-1 8 Data Bits, No Parity, 1 Stop Bit.
CRC Checksum CRC-16 IBM (0xA001) Standard Modbus RTU CRC (Low Byte transmitted first).
Factory Default Slave ID 255 (0xFF) Unit ships in unprovisioned state out of the box.
Assigned Slave ID Range 1 to 247 Written into EEPROM during Interactive Discovery.
Broadcast Address 0 (0x00) Used by Master to trigger Discovery Mode.
Turnaround Response Time < 20 ms Microcontroller response delay after receiving Master request.
RS-485 DE/~RE Pin Control Hardware GPIO Pin Set DE High ≥ 1ms before TX. Drive DE Low only after TX Complete (TC flag).

2. Physical Button Layout & Numbering Standard

Buttons are indexed in standard reading order (Top-Left → Top-Right → Bottom-Left → Bottom-Right):

4-BUTTON WALL UNIT
BUTTON 1Top-Left (Bit 0/1)
BUTTON 2Top-Right (Bit 2/3)
BUTTON 3Bottom-Left (Bit 4/5)
BUTTON 4Bottom-Right (Bit 6/7)
🚽 TOILET BTN 1 (Bit 8/9)
🚽 TOILET BTN 2 (Bit 10/11)
📞 HANDSET BTN 1 (Bit 12/13)
📞 HANDSET BTN 2 (Bit 14/15)

Numbering & Auxiliary Sensor Inputs:

  • 1-Button Unit: Single center button = Button 1 (Bit 0/1).
  • 2-Button Unit: Top = Button 1 (Bit 0/1), Bottom = Button 2 (Bit 2/3).
  • 4-Button Unit: Standard 4-button faceplate (Bits 0–7 for SP/LP).
  • 2-Button Toilet Unit: Button 1 (Pull) triggers Bit 8/9; Button 2 (Cancel) triggers Bit 10/11.
  • 2-Button Remote Handset: Button 1 (Call) triggers Bit 12/13; Button 2 (Cancel/Extra) triggers Bit 14/15.
  • Continuous Hardware Status (Register 40008): Dedicated non-clearing register: Bit 0 = Bed Occupancy Sensor (1 = Occupied, 0 = Vacant), Bit 1 = Tamper Switch (1 = Open/Tampered).

3. Digital 7-Color RGB Truth Table (Codes 0 to 7)

The hardware uses 3 microcontroller GPIO pins (Red, Green, Blue) to produce 7 pure digital colors (Simple ON/OFF logic):

Color Code Color Name Red GPIO Pin Green GPIO Pin Blue GPIO Pin Hospital Visual Use Case
0 OFF 0 (LOW) 0 (LOW) 0 (LOW) LED turned off / Clean mode
1 RED 1 (HIGH) 0 (LOW) 0 (LOW) Code Blue / Emergency SOS
2 GREEN 0 (LOW) 1 (HIGH) 0 (LOW) Care Started / Nurse Present
3 BLUE 0 (LOW) 0 (LOW) 1 (HIGH) Extra Help / Active Idle Heartbeat Glow
4 YELLOW 1 (HIGH) 1 (HIGH) 0 (LOW) Normal Nurse Call
5 CYAN 0 (LOW) 1 (HIGH) 1 (HIGH) Call Acknowledged (Nurse En-Route) / Doctor Assist
6 MAGENTA 1 (HIGH) 0 (LOW) 1 (HIGH) Code Pink / Staff Assist
7 WHITE 1 (HIGH) 1 (HIGH) 1 (HIGH) All Pins High / Self-Test

4. Wall Unit Command & Register Reference

Station Function Codes:
• FC 03 (`0x03`): Read Holding Registers
• FC 06 (`0x06`): Write Single Holding Register
• FC 16 (`0x10`): Write Multiple Holding Registers

A. Real-Time Inputs & Status (Read / Write Registers)

Register Address Hex Address Dec Access Parameter Name Description / Bit Allocation
40001 0x0000 0 READ Live Button Status Bitmask Bit = 1 when pressed / latched (Cleared by Register 40009 Handled Clear-Mask):
• Bit 0: Button 1 Single Press (< 2s)
• Bit 1: Button 1 Long Press (> 2s)
• Bit 2: Button 2 Single Press
• Bit 3: Button 2 Long Press
• Bit 4: Button 3 Single Press
• Bit 5: Button 3 Long Press
• Bit 6: Button 4 Single Press
• Bit 7: Button 4 Long Press
• Bit 8: Toilet Button 1 (Pull Cord) Single Pull
• Bit 9: Toilet Button 1 (Pull Cord) Long Pull (>2s)
• Bit 10: Toilet Button 2 (Cancel Key) Single Press
• Bit 11: Toilet Button 2 (Cancel Key) Long Press
• Bit 12: Remote Handset Button 1 Single Press
• Bit 13: Remote Handset Button 1 Long Press
• Bit 14: Remote Handset Button 2 Single Press
• Bit 15: Remote Handset Button 2 Long Press
40008 0x0007 7 READ Continuous Hardware Status Continuous sensor states (NOT clear-on-read):
• Bit 0: Bed Occupancy Sensor (1 = Bed Occupied, 0 = Vacant)
• Bit 1: Enclosure Tamper Switch (1 = Open / Tampered, 0 = Secured)
• Bits 2–15: Reserved (0)
40009 0x0008 8 R/W Handled Bits Clear-Mask Gateway writes bitmask of handled bits here to atomically clear acknowledged latched events in Register 40001 (e.g. write 0x0001 to clear Button 1 SP). Note: Reading this register returns 0x0000. Prevents lost events on noisy RS-485 buses.
40010 0x0009 9 R/W Nurse Station Remote & Diagnostic Command Central Nurse Station control & diagnostic command bitmask (executed then auto-reset to 0):
• 0x0001: Remote Clear (Reset all active calls & turn OFF LEDs)
• 0x0004: Remote Acknowledge (HOLD LED ON, mutes buzzer)
• 0x0008: Remote Mute Buzzer (Snooze active alarm)
• 0x0100: LED Diagnostic Self-Test (Cycles Red, Green, Blue, White for 3s)
• 0x0200: Buzzer Diagnostic Chirp Test (Sounds a 200ms audible test chirp)
• 0x0400: EEPROM Integrity Verification (Re-reads and checks 53-byte struct checksum)
• 0x0000: Idle / No Command
Note: Diagnostic bits (0x0100, 0x0200, 0x0400) may be combined in a single write (e.g. 0x0300 runs LED + Buzzer test). High byte is dedicated to diagnostics, avoiding collisions with button action bits.

B. Configuration & Button LED Registers (Saved in Non-Volatile EEPROM)

When the Gateway commissions a device, it writes this complete configuration block into the unit's EEPROM:

🎯 System-Defined Action Codes Reference (Bitmask: Value = ∑ (1 << Code)):
• 0x0000 (0) - DISABLED / NO ACTION: Button press ignored by firmware; no call registered.
• 0x0001 (1) - CLEAR_ALL: Reset all LEDs, turn OFF HOLD LED, mute buzzer, return to standby.
• 0x0002 (2) - CALL_SOLID: Assigned button LED turns SOLID ON with configured color.
• 0x0004 (4) - ACKNOWLEDGE: Turn ON Acknowledge (`HOLD`) LED, active call solid, mute call buzzer.
• 0x0008 (8) - MUTE_BUZZER: Mutes local buzzer sound only; visual call LEDs and remote alerts stay 100% active.
• 0x0010 (16) - STAFF_CHECKIN: Turns ON confirmation LED for 3s, then automatically clears (logs nurse presence).
• 0x0020 (32) - CALL_BLINK: Assigned button LED BLINKS continuously with configured color.
• 0x0040 (64) - MULTI_CALL_CYCLE: Modifier bit (combine with 0x0002 or 0x0020; not a standalone action). When 2+ buttons are pressed: alternates active call colors in sequence.
Validation Rules: Valid action range is 0x00 to 0x7F (bits 0–6). Writes above 0x7F are rejected with Modbus Exception 03 (Illegal Data Value). The following combinations are invalid and must be blocked by the configuring tool: CLEAR_ALL + call bits, ACKNOWLEDGE + call bits, and CALL_SOLID + CALL_BLINK. Should such a value already be present in EEPROM from an earlier configuration, firmware resolves it deterministically: CALL_SOLID + CALL_BLINK renders BLINK; CLEAR_ALL + call bits performs the clear and ignores the call bits; ACKNOWLEDGE + call bits registers the call and ignores the acknowledge.
🏆 System-Defined Priority Ranking (Registers 40061 to 40076):
• Priority Scale: 1 to 16 where 1 = Highest Emergency Priority (Code Blue) and 16 = Lowest Priority.
• Non-Call Actions: ACKNOWLEDGE, CLEAR_ALL, MUTE_BUZZER, and STAFF_CHECKIN store 0 (0 = not a call / bypass arbitration to act unconditionally on current winning call).
• Priority Override Rule: Highest priority (lowest number) overrides lower priority calls on LEDs and buzzer. On tie, latest pressed button wins.
PLC Address Hex Address Dec Access Storage Parameter Name Default Description / Hardware Mapping
40002 0x0001 1 R/W EEPROM Single-Press Key Enable Mask 0xFFFF 16-bit mask: Bit N = 1 enables single press. Only even bits (0, 2, 4, 6, 8, 10, 12, 14) map to single-press events in 40001.
40003 0x0002 2 R/W EEPROM Long-Press Key Enable Mask 0xFFFF 16-bit mask: Bit N = 1 enables long press. Only odd bits (1, 3, 5, 7, 9, 11, 13, 15) map to long-press events in 40001.
40004 0x0003 3 R/W EEPROM Long-Press Threshold (ms) 2000 Time in ms required to hold button for Long Press (500–5000ms).
40005 0x0004 4 R/W EEPROM Debounce Time (ms) 50 Hardware debounce filter duration in ms (10–200ms).
40006 0x0005 5 R/W EEPROM Idle / Clean Glow Color 3 (Blue) Standby backlight color (3=Blue, 0=OFF). Rule: No call color may equal idle glow color!
40011 0x000A 10 R/W EEPROM Button 1 SP Action Bitmask 2 (0x0002) Bitmask for Button 1 Single Press (Default: CALL_SOLID)
40012 0x000B 11 R/W EEPROM Button 1 LP Action Bitmask 32 (0x0020) Bitmask for Button 1 Long Press (Default: CALL_BLINK)
40013 0x000C 12 R/W EEPROM Button 2 SP Action Bitmask 32 (0x0020) Bitmask for Button 2 Single Press (Default: CALL_BLINK - Code Blue)
40014 0x000D 13 R/W EEPROM Button 2 LP Action Bitmask 32 (0x0020) Bitmask for Button 2 Long Press (Default: CALL_BLINK - CPR)
40015 0x000E 14 R/W EEPROM Button 3 SP Action Bitmask 2 (0x0002) Bitmask for Button 3 Single Press (Default: CALL_SOLID)
40016 0x000F 15 R/W EEPROM Button 3 LP Action Bitmask 2 (0x0002) Bitmask for Button 3 Long Press (Default: CALL_SOLID)
40017 0x0010 16 R/W EEPROM Button 4 SP Action Bitmask 4 (0x0004) Bitmask for Button 4 Single Press (Default: ACKNOWLEDGE)
40018 0x0011 17 R/W EEPROM Button 4 LP Action Bitmask 1 (0x0001) Bitmask for Button 4 Long Press (Default: CLEAR_ALL)
40019 0x0012 18 R/W EEPROM Toilet Btn 1 (Pull) SP Action 32 (0x0020) Bitmask on Toilet Pull Cord Single Pull (CALL_BLINK)
40020 0x0013 19 R/W EEPROM Toilet Btn 1 (Pull) LP Action 32 (0x0020) Bitmask on Toilet Pull Cord Long Pull (CALL_BLINK)
40037 0x0024 36 R/W EEPROM Toilet Btn 2 (Cancel) SP Action 1 (0x0001) Bitmask on Toilet Cancel Key Single Press (CLEAR_ALL)
40038 0x0025 37 R/W EEPROM Toilet Btn 2 (Cancel) LP Action 1 (0x0001) Bitmask on Toilet Cancel Key Long Press (CLEAR_ALL)
40021 0x0014 20 R/W EEPROM Button 1 SP Color 4 (Yellow) Color code (0..7) shown on Button 1 Single Press
40022 0x0015 21 R/W EEPROM Button 1 LP Color 1 (Red) Color code (0..7) shown on Button 1 Long Press
40023 0x0016 22 R/W EEPROM Button 2 SP Color 1 (Red) Color code (0..7) shown on Button 2 Single Press (Code Blue)
40024 0x0017 23 R/W EEPROM Button 2 LP Color 1 (Red) Color code (0..7) shown on Button 2 Long Press (CPR Emergency)
40025 0x0018 24 R/W EEPROM Button 3 SP Color 5 (Cyan) Color code (0..7) shown on Button 3 Single Press (Assist)
40026 0x0019 25 R/W EEPROM Button 3 LP Color 1 (Red) Color code (0..7) shown on Button 3 Long Press
40027 0x001A 26 R/W EEPROM Button 4 SP Color 2 (Green) Color code (0..7) shown on Button 4 Single Press (Care / Ack)
40028 0x001B 27 R/W EEPROM Button 4 LP Color 0 (OFF) Reset action on Button 4 Long Press
40029 0x001C 28 R/W EEPROM Toilet Pull Cord & Aux Call Color 4 (Yellow) Color code (0..7) for all Toilet call inputs (40019, 40020, 40037, 40038 when configured as call). Non-call actions (0x0001 Clear) ignore color.
40030 0x001D 29 R/W EEPROM Remote Handset Call Color 4 (Yellow) Color code (0..7) for all Remote Handset call inputs (40031..40034 when configured as call). Non-call actions (0x0004 Ack, 0x0001 Clear) ignore color.
40035–40036 0x0022–23 34–35 R/W — Reserved (Wall Units) 0x0000 Reserved on wall units: Read returns 0x0000; writes silently ignored with NO exception. (On corridor dome units, 40007 is Color Bed Slot 6).
40031 0x001E 30 R/W EEPROM Remote Btn 1 SP Action 2 (0x0002) Bitmask on Remote Button 1 Single Press (Default: CALL_SOLID)
Supports multiple combined actions (∑ 2code):
• 2 (0x0002): Standard Call Solid
• 10 (0x000A): Call Solid + Mute Buzzer (Silent Patient Call)
• 18 (0x0012): Call Solid + Staff Checkin Pulse
• 74 (0x004A): Call Solid + Mute Buzzer + Multi-Call Cycle
40032 0x001F 31 R/W EEPROM Remote Btn 1 LP Action 32 (0x0020) Bitmask on Remote Button 1 Long Press (Default: CALL_BLINK)
Supports multiple combined actions (∑ 2code):
• 32 (0x0020): Urgent Emergency Call Blink
• 40 (0x0028): Call Blink + Mute Buzzer (Silent Urgent Call)
• 96 (0x0060): Call Blink + Multi-Call Alternating Cycle
• 104 (0x0068): Call Blink + Mute Buzzer + Multi-Call Cycle
40033 0x0020 32 R/W EEPROM Remote Btn 2 SP Action 4 (0x0004) Bitmask on Remote Button 2 Single Press (Default: ACKNOWLEDGE)
Supports multiple combined actions (∑ 2code):
• 4 (0x0004): Acknowledge (Turns ON ACK LED, mutes active beeper)
• 12 (0x000C): Acknowledge + Mute Buzzer (Ensures total local silence)
• 20 (0x0014): Acknowledge + Staff Checkin (Care Started Attendance)
40034 0x0021 33 R/W EEPROM Remote Btn 2 LP Action 1 (0x0001) Bitmask on Remote Button 2 Long Press (Default: CLEAR_ALL)
Supports multiple combined actions (∑ 2code):
• 1 (0x0001): Clear / Reset all active calls (turns OFF LEDs, stops sound)
• 9 (0x0009): Clear All + Mute Buzzer (Immediate 0ms local silence)
• 17 (0x0011): Clear All + Staff Checkin (End of Care Attendance)
40050 0x0031 49 R/W RAM Global Emergency Broadcast Alarm 0 • 1: Blink ALL 4 Wall Unit LEDs RED at the same time + Continuous Beeping Alarm.
• 0: Stop alarm & return to normal operation.
40061 0x003C 60 R/W EEPROM Button 1 SP Priority Rank 3 Priority Rank (1..16, 1=Highest). Overrides lower priority on LED.
40062 0x003D 61 R/W EEPROM Button 1 LP Priority Rank 2 Priority Rank (1..16, 1=Highest) on Button 1 Long Press.
40063 0x003E 62 R/W EEPROM Button 2 SP Priority Rank 1 Priority Rank (1..16, 1=Highest - Code Blue Emergency).
40064 0x003F 63 R/W EEPROM Button 2 LP Priority Rank 1 Priority Rank (1..16, 1=Highest - Critical CPR).
40065 0x0040 64 R/W EEPROM Button 3 SP Priority Rank 4 Priority Rank (1..16, 1=Highest) on Button 3 Single Press.
40066 0x0041 65 R/W EEPROM Button 3 LP Priority Rank 4 Priority Rank (1..16, 1=Highest) on Button 3 Long Press.
40067 0x0042 66 R/W EEPROM Button 4 SP Priority Rank 0 0 = Non-call action (Acknowledge bypasses priority arbitration).
40068 0x0043 67 R/W EEPROM Button 4 LP Priority Rank 0 0 = Non-call action (Clear All bypasses priority arbitration).
40069 0x0044 68 R/W EEPROM Toilet Btn 1 (Pull) SP Priority 2 Priority Rank (1..16) on Toilet Pull Cord Single Pull.
40070 0x0045 69 R/W EEPROM Toilet Btn 1 (Pull) LP Priority 1 Priority Rank (1..16) on Toilet Pull Cord Long Pull (>2s).
40071 0x0046 70 R/W EEPROM Toilet Btn 2 (Cancel) SP Priority 0 0 = Non-call action (Toilet Cancel bypasses priority arbitration).
40072 0x0047 71 R/W EEPROM Toilet Btn 2 (Cancel) LP Priority 0 0 = Non-call action (Toilet Cancel bypasses priority arbitration).
40073 0x0048 72 R/W EEPROM Remote Btn 1 SP Priority 3 Priority Rank (1..16) on Remote Button 1 Single Press.
40074 0x0049 73 R/W EEPROM Remote Btn 1 LP Priority 2 Priority Rank (1..16) on Remote Button 1 Long Press.
40075 0x004A 74 R/W EEPROM Remote Btn 2 SP Priority 0 0 = Non-call action (Remote Acknowledge bypasses priority arbitration).
40076 0x004B 75 R/W EEPROM Remote Btn 2 LP Priority 0 0 = Non-call action (Remote Clear bypasses priority arbitration).
40250 0x00F9 249 READ FLASH Hardware Model & Type Code 104 104 = 4-Button Bedside Wall Unit
102 = 2-Button Bedside Wall Unit
101 = 1-Button Bedside Wall Unit
200 = Corridor Over-Door Dome Light
40251 0x00FA 250 READ FLASH Firmware Version (BCD / Hex) 0x0200 Embedded firmware version (e.g. 0x0200 = v2.00, 0x0210 = v2.10).
40252 0x00FB 251 READ FLASH Device Serial Number (Batch ID) 1001 Unique 16-bit factory serial number / production batch identifier.
40253 0x00FC 252 R/W RAM Pairing Selection Flag 0 Dedicated pairing flag: 1 = Physically selected by technician (Button 1 held > 3s). Only the selected unit responds to address 255 during pairing.
40254 0x00FD 253 R/W EEPROM Commissioning Status Flag 0 (Pending) 0: Factory / Uncommissioned State (Pending Setup)
1: Commissioned by Gateway (Production Active)
40255 0x00FE 254 R/W RAM System Discovery Command 0x0000 0x00AA: Discover Uncommissioned Only (Reg 253 == 0)
0x00FF: Force Discover ALL Units on Bus
0x0000: Normal Operating Mode
40256 0x00FF 255 R/W EEPROM Modbus Slave ID 255 Assigned Slave ID (1..247). Saved in EEPROM. Echoes reply first, sets Reg 253 = 1, switches ID, & turns Solid Green 3s.
ℹ️ Reserved / Undefined Registers Behavior:
On wall units, registers 40007, 40035, and 40036 are reserved. Reading returns 0x0000. Writing is accepted and silently ignored with NO Modbus exception, allowing continuous block writes (e.g. FC 16 writing 40002 to 40038 in one single transaction). (Note: on corridor dome units, register 40007 is assigned to Color Bed Slot 6.)

💡 Combining Multiple Action Codes (Bitwise Flags) on Wall Unit Buttons (Registers 40011 to 40018)

A single Modbus register can manage multiple simultaneous action codes using bitwise flags (1 << code):

  • Example A — Silent Nurse Call: CALL_SOLID (2) + MUTE_BUZZER (8) = 10 (0x000A) → 01 06 00 0A 00 0A 29 CF
  • Example B — Call + Nurse Attendance: CALL_SOLID (2) + STAFF_CHECKIN (16) = 18 (0x0012) → 01 06 00 0A 00 12 29 C5
  • Example C — Muted Urgent Multi-Call: CALL_BLINK (32) + MUTE_BUZZER (8) + MULTI_CALL_CYCLE (64) = 104 (0x0068) → 01 06 00 0A 00 68 A8 26

📱 Combining Multiple Action Codes on Remote Bedside Handset (Registers 40031 to 40034)

Bedside handset buttons can also combine multiple actions into one register value:

  • Example D — Remote Btn 1 SP Silent Call (Reg 40031): CALL_SOLID (2) + MUTE_BUZZER (8) = 10 (0x000A) → 01 06 00 1E 00 0A 69 CB
  • Example E — Remote Btn 1 LP Urgent Multi-Call (Reg 40032): CALL_BLINK (32) + MULTI_CALL_CYCLE (64) = 96 (0x0060) → 01 06 00 1F 00 60 B8 24
  • Remote Btn 2 SP Ack + Attendance (Reg 40033): ACKNOWLEDGE (4) + STAFF_CHECKIN (16) = 20 (0x0014) → Acknowledges active call and registers nurse room presence.
  • Remote Btn 2 LP Silent Clear (Reg 40034): CLEAR_ALL (1) + MUTE_BUZZER (8) = 9 (0x0009) → Cancels all calls with instant local 0ms buzzer silence.

5. Microcontroller Firmware Logic & Implementation Guide (Action Bitmasks & Priorities)

This section provides the complete reference implementation and exact state machine rules for the wall unit microcontroller firmware developer:

🔊 MUTE_BUZZER (0x0008) Semantics, Snooze Persistence & Dynamic Buzzer Evaluation:
• Suppresses Local Buzzer Sound Only: 0x0008 mutes the local audible sounder and nothing else. It never suppresses the call state, 40001 bit latch, button LED, priority arbitration, Corridor Dome light, or Nurse Station alert.
• Every Enabled Press Latches 40001: Every physical button press latches its assigned bit in Register 40001 regardless of action codes (including non-call presses: Acknowledge, Clear, Mute, Checkin). The central gateway always sees what was physically pressed.
• Mute Alone (Snooze) vs. Combined Mute (Silent Call):
  — Mask 0x0008 alone without call bits (Snooze): Silences the currently active winning call by setting its internal muted = true flag without creating a new call.
  — Mask 0x0002 | 0x0008 or 0x0020 | 0x0008 with call bits (Silent Call): Creates a new call that stays inherently quiet when it wins arbitration, but NEVER snoozes or silences other existing calls (e.g. an active Code Blue).
• Snooze Persists on the Active Call Record: Snooze is stored on the active call record in RAM, not as a temporary one-shot glitch. Subsequent presses (e.g. nurse attendance or another call check) will NOT un-mute a snoozed call.
• Events that Reset / Clear the Snooze Flag:
  1. Active call is cleared (via CLEAR_ALL 0x0001 button press or Nurse Station Remote Clear 40010 = 0x0001).
  2. A new higher-priority call arrives (which arbitrates as the new winning call with muted = false, sounding its alarm normally). If that higher call is later cleared, the underlying snoozed call remains quiet.
  3. Acknowledge (0x0004) mutes the alarm and keeps it silenced.
Action Bitmask Action Name Microcontroller Firmware Implementation & Execution Logic
0x0000 (0) DISABLED / NO_ACTION • Button press ignored by firmware; no internal call registered, no LED change.
• Register 40001 bit is NOT latched.
0x0001 (1) CLEAR_ALL (Reset) • Instantly turns OFF all button LEDs on the wall unit.
• Turns OFF the Acknowledge (`HOLD`) LED.
• Mutes the buzzer (stops all active sound).
• Clears all active internal calls and resets their snooze states, returning unit to standby idle.
• Priority: Bypasses priority arbitration (stores priority 0). Does not block subsequent actions (e.g. Staff Check-in).
0x0002 (2) CALL_SOLID (Regular) • Turns the assigned button LED SOLID ON using configured color.
• Sounds periodic call buzzer (unless 0x0008 MUTE_BUZZER is set in mask or call is snoozed).
• Participates in Priority Arbitration (Scale 1–16).
0x0004 (4) ACKNOWLEDGE (Care Started) • When pressed as an acknowledge action (without call bits): If an active call exists, turns ON the Acknowledge (`HOLD`) LED Solid with assigned Cyan color, active winning call stays solid, sets muted = true, and instantly mutes buzzer.
• If pressed when no call is active: HOLD LED remains OFF (guarded in firmware).
• Priority: Bypasses priority arbitration (stores priority 0).
0x0008 (8) MUTE_BUZZER (Snooze) • When pressed alone as a snooze action (without call bits): Marks active winning call as snoozed (muted = true) and stops buzzer completely.
• Silent calls (containing 0x0008 + call bits) register as silent calls without muting other active alarms.
• Priority: Bypasses priority arbitration (stores priority 0).
0x0010 (16) STAFF_CHECKIN (Attendance) • Turns ON confirmation LED for 3.0 seconds, then automatically clears itself.
• Plays 1 short 100ms chirp confirmation beep.
• Priority: Bypasses priority arbitration (stores priority 0).
0x0020 (32) CALL_BLINK (Blinking Call) • Assigned button LED BLINKS continuously using configured color.
• Sounds urgent call buzzer (unless 0x0008 MUTE_BUZZER is set in mask or call is snoozed).
• Participates in Priority Arbitration (Scale 1–16).
0x0040 (64) MULTI_CALL_CYCLE (Modifier) • Modifier bit (combine with 0x0002 or 0x0020; not a valid standalone action). When 2+ buttons are pressed with 0x0040 assigned: Alternates active colors in sequence.
• If Acknowledge was previously active, a new call clears ACK and resumes cycling until re-acknowledged.
Reg 40050 GLOBAL HOSPITAL EMERGENCY (Fire / SOS) • Triggered when Gateway writes Register 40050 = 1.
• ALL Wall Unit LEDs BLINK RED simultaneously + Continuous Rapid Alarm Sound.
• Gateway writes Register 40050 = 0 to restore normal operation.

Microcontroller Button Handler (Single-Pass Pipeline with Call Snooze & Dynamic Buzzer Evaluation):

/* Microcontroller Button Press Handler with Multi-Action Bitmask Pipeline (Single-Pass, No Early Returns) */
void handle_button_event(uint8_t btn_index, bool is_long_press) {
    // 0. Read configured Action Bitmask, Color, and Priority Rank from EEPROM
    uint8_t action_mask = get_action_mask_from_eeprom(btn_index, is_long_press);
    uint8_t led_color   = get_color_code_from_eeprom(btn_index, is_long_press);
    uint8_t prio_rank   = get_priority_rank_from_eeprom(btn_index, is_long_press); // Regs 40061..40076 (1..16, 0 for non-calls)

    // Ignore if action code is 0 (0 = Disabled / No Action)
    if (action_mask == 0) {
        return;
    }

    // 1. CLEAR_ALL (0x0001): Immediate local 0ms call reset
    bool has_clear = (action_mask & 0x0001) != 0;
    if (has_clear) {
        turn_off_all_button_leds();
        set_hold_led(false);
        stop_buzzer();
        clear_all_active_calls(); // Clears all call records and their snooze states
        // Do NOT return: allow subsequent non-call actions (e.g. Staff Check-in 0x0010) to execute!
    }

    // 2. Call Actions (0x0002 Solid, 0x0020 Blink, 0x0040 Cycle)
    // Only register call if not cleared in step 1 (Clear All takes precedence over call bits)
    if (!has_clear && (action_mask & (0x0002 | 0x0020 | 0x0040))) {
        register_button_call(btn_index, action_mask, led_color, prio_rank); // Initializes call->muted = false
    }

    // 3. Evaluate Winning Active Call after any registration or clear
    uint8_t win_btn = evaluate_highest_priority_active_call(); // Returns winning button index or NO_ACTIVE_CALL
    if (win_btn != NO_ACTIVE_CALL) {
        uint8_t win_mask  = get_action_mask(win_btn);
        uint8_t win_color = get_color(win_btn);

        // Visual rendering: BLINK (0x0020) takes precedence over SOLID (0x0002)
        if (win_mask & 0x0020) {
            set_button_led_blink(win_btn, win_color);
        } else if (win_mask & 0x0002) {
            set_button_led_solid(win_btn, win_color);
        }

        // Multi-call alternating cycle (0x0040) runs concurrently if active
        if (win_mask & 0x0040) {
            start_color_alternating_loop();
        }
    }

    // 4. ACKNOWLEDGE (0x0004): Acknowledges active winning call (only when pressed as non-call action)
    if ((action_mask & 0x0004) && !(action_mask & (0x0002 | 0x0020 | 0x0040))) {
        if (win_btn != NO_ACTIVE_CALL) {
            set_hold_led(true);
            set_active_call_led_solid();
            ActiveCall_t *call = get_active_call(win_btn);
            if (call) call->muted = true; // Acknowledge silences the active call
        }
        stop_buzzer();
    }

    // 5. MUTE_BUZZER (0x0008) when pressed alone as a snooze action (without call bits)
    if ((action_mask & 0x0008) && !(action_mask & (0x0002 | 0x0020 | 0x0040))) {
        if (win_btn != NO_ACTIVE_CALL) {
            ActiveCall_t *call = get_active_call(win_btn);
            if (call) call->muted = true; // Mark active winning call as snoozed
        }
        stop_buzzer();
    }

    // 6. Dynamic Buzzer Evaluation from Winning Call
    // Sound buzzer ONLY if winning call exists, is not configured as silent (0x0008 in mask), and is not snoozed
    if (win_btn != NO_ACTIVE_CALL) {
        ActiveCall_t *win_call = get_active_call(win_btn);
        if (win_call && !(win_call->action_mask & 0x0008) && !win_call->muted) {
            start_buzzer_beep();
        } else {
            stop_buzzer(); // Silent call stays silent while on top; snoozed call remains quiet
        }
    } else {
        stop_buzzer();
    }

    // 7. STAFF_CHECKIN (0x0010): 3.0s visual confirmation + 100ms short chirp
    if (action_mask & 0x0010) {
        flash_confirmation_led(3000);
        play_short_chirp();
    }

    // 8. Latch Modbus Live Status Register 40001 once at the end for all enabled presses
    latch_live_status_bit(btn_index, is_long_press);
}

/* Modbus Write Callback for Global Emergency Register 40050 */
void on_modbus_reg_40050_written(uint16_t value) {
    if (value == 1) {
        start_all_4_leds_red_flash_with_continuous_alarm();
    } else {
        stop_emergency_alarm_and_restore_standby();
    }
}

6. Corridor Over-Door Dome LED (Ward Room Light — Up to 6 Active Calls)

The Corridor Door Light is an independent Modbus Slave that displays active calls for the room/ward and automatically alternates colors when multiple beds call at once. Gateway rules: 1 active call → Mode 1; 2+ active calls → Mode 3 (skipping color 0 slots); Any Priority 1 call → Mode 2 (emergency red flash). The Gateway writes Registers 40001–40007 in a single FC 16 write to eliminate visual flicker:

PLC Address Hex Address Dec Access Parameter Name Description
40001 0x0000 0 R/W Display Mode 0: Idle / Clean Glow (Shows heartbeat color)
1: Single Static Color (Shows Color 1)
2: Fast SOS Blinking (Emergency)
3: Multi-Call Alternating Cycle (Cycles between active Bed slots 1..6)
40002 0x0001 1 R/W Color 1 (Bed Slot 1) Color code (0 to 7) for Bed Slot 1 active call
40003 0x0002 2 R/W Color 2 (Bed Slot 2) Color code (0 to 7) for Bed Slot 2 active call
40004 0x0003 3 R/W Color 3 (Bed Slot 3) Color code (0 to 7) for Bed Slot 3 active call
40005 0x0004 4 R/W Color 4 (Bed Slot 4) Color code (0 to 7) for Bed Slot 4 active call
40006 0x0005 5 R/W Color 5 (Bed Slot 5) Color code for Bed Slot 5 call (6-bed ward)
40007 0x0006 6 R/W Color 6 (Bed Slot 6) Color code for Bed Slot 6 call (6-bed ward)
40011 0x000A 10 R/W Cycle Time (ms) Time to display each color before alternating (Default: 1500ms)
40012 0x000B 11 R/W Idle Heartbeat Color Color shown when all calls cleared (3=Blue, 0=OFF)
40250 0x00F9 249 READ Hardware Model Type 200 (Corridor Over-Door Dome Light)
40251 0x00FA 250 READ Firmware Version 0x0200 (v2.00)
40252 0x00FB 251 READ Device Serial Number Unique 16-bit factory serial number / batch ID
40253 0x00FC 252 R/W Pairing Selection Flag 1 = Dome pairing trigger activated (internal service button or magnetic reed switch held >3s during discovery); 0 = Standby
40254 0x00FD 253 R/W Commissioning Status Flag 0 = Factory Uncommissioned, 1 = Commissioned (EEPROM)
40255 0x00FE 254 R/W Discovery Command 0x00AA (New Only), 0x00FF (Force All), 0x0000 (Normal). Flashes White/Cyan during discovery.
40256 0x00FF 255 R/W Slave ID Modbus Slave ID (1..247, Factory Default: 255 / 0x00FF [Uncommissioned]; Example Assigned: 20). Saved in EEPROM.

Corridor Dome EEPROM Memory Layout (8 Bytes Total):

EEPROM Offset Modbus Register Hex Addr Data Type Factory Default Description
0x00 Reg 255 (40256) 0x00FF uint8_t 255 (0xFF) Slave ID: Modbus address (1..247, Factory Default 255 uncommissioned).
0x01 Reg 253 (40254) 0x00FD uint8_t 0 (Pending) Commissioned Flag: 0 = Uncommissioned, 1 = Commissioned.
0x02..0x03 Reg 10 (40011) 0x000A uint16_t 1500 ms Cycle Interval: Display duration per active bed color.
0x04 Reg 11 (40012) 0x000B uint8_t 3 (Blue) Idle Heartbeat Color: Standby glow (3=Blue, 0=OFF).
0x05..0x07 — — uint8_t[3] [0, 0, 0] Reserved / Future Expansion

7. Detailed Discovery Mode & Zero-DIP-Switch Slave ID Assignment Specification

Protocol Rule: Both regular runtime communication AND discovery mode use the EXACT SAME standard Modbus RTU protocol (19200 baud, 8-N-1, Function Codes FC 03 and FC 06). No special baud rate switches or proprietary protocols are required.

A. The Two Discovery Modes (Handling Factory-Tested Devices with Duplicate IDs)

Even if devices arrive from the factory with identical temporary test IDs (e.g. all set to ID 1), our Commissioned Status Flag (Reg 253) guarantees zero collisions:

Option 1: Discover New / Pending Only (`0x00AA`)

Only units with Reg 253 == 0 (uncommissioned) will blink. Existing commissioned units ignore the broadcast, ensuring active hospital rooms are not disturbed.

Option 2: Force Discovery on ALL Units (`0x00FF`)

Every unit on the bus blinks regardless of previous state. Used for new ward installations or full re-addressing.

1
Admin Triggers Discovery from Gateway UI

The Gateway sends a standard Modbus RTU Write command to Broadcast Address 0 (`0x00`) writing value 0x00AA or 0x00FF into Register 254 (0x00FE):

Gateway Master Request (New Only):  00 06 00 FE 00 AA 69 94  (Broadcast 0x00, Reg 254 = 0x00AA)
Gateway Master Request (Force All): 00 06 00 FE 00 FF A9 AB  (Broadcast 0x00, Reg 254 = 0x00FF)
Microcontroller Action: Target units receive this broadcast, enter discovery mode, and start flashing all button LEDs rapidly at 2.5 Hz (200ms ON / 200ms OFF). Normal call events are suppressed during discovery. Target units auto-exit discovery mode if no commissioning activity occurs for 10 minutes. Slaves DO NOT reply on RS-485 to broadcast address 0 (0% bus collision).
2
Technician Physically Selects the Target Bed

The technician walks over to the specific bed (e.g. Bed 101) and presses and holds Button 1 (Top-Left) for 3 seconds.

Microcontroller Action: That specific wall unit detects the 3-second hold on Button 1. It immediately:
  • Stops flashing other LEDs and turns Button 1 SOLID YELLOW.
  • Sets dedicated pairing flag Register 40253 = 1 (STATE_PAIRING_SELECTED).
3
Gateway Reads the Selected Unit

While discovery is active, the Gateway polls unassigned address 255 for the pairing flag. Rule: Only the unit with Register 40253 == 1 is permitted to respond at address 255; all other uncommissioned units stay completely silent:

Gateway Master Request: FF 03 00 FC 00 01 51 E4  (Read Reg 252/40253 on Slave 255)
Selected Slave Response: FF 03 02 00 01 50 50     (Reg 40253 = 1 -> Unit is Selected!)
4
Gateway Assigns the New Slave ID (e.g. ID 101)

The Gateway sends a standard Write Single Register command to Register 255 (0x00FF) with the desired new Slave ID (e.g. 101 / 0x0065):

Gateway Master Request: FF 06 00 FF 00 65 6C 0F  (Write Reg 255 = 101 to Slave 255)
Slave Echo Response:    FF 06 00 FF 00 65 6C 0F  (Slave echoes back confirmation from current address)
5
Microcontroller Burns ID to EEPROM & Sets Commissioned Flag
Microcontroller Execution Order:
  1. Sends Modbus echo reply immediately from current address.
  2. Saves new Slave ID 101 into internal non-volatile EEPROM memory.
  3. Sets `Commissioned Flag (Reg 253) = 1` in EEPROM.
  4. Switches its active Modbus RS-485 listening address to `101`.
  5. Turns ALL BUTTON LEDs SOLID GREEN for 3.0 Seconds on a non-blocking timer and emits a 200ms beep.
  6. Resets pairing flag Register 40253 = 0 and returns to normal operating mode.
6
Gateway Pushes Full EEPROM Configuration to Slave 101

The Gateway immediately writes the full button RGB colors, action code bitmasks, key enable masks, and priorities (Registers 40002 to 40038 and 40061 to 40076) to Slave 101 using standard Modbus Function Code 0x10 (Write Multiple Registers). The unit saves all registers to EEPROM and enters Clean Idle Glow mode.

🚪 Corridor Over-Door Dome LED Commissioning Specification

Corridor Over-Door Dome lights participate in the exact same zero-collision discovery architecture as wall units:

  • Factory Default Address: Fresh / uncommissioned dome lights ship with factory default Slave ID 255 (0x00FF) and Reg 40254 = 0.
  • Discovery Indication: Upon receiving the Discovery Broadcast (Reg 40255 = 0x00AA / 0x00FF), uncommissioned dome lights flash White / Cyan at 2.5 Hz.
  • Pairing Trigger:
    • Hardware Trigger (Primary): Technician presses the internal PCB service button (or touches an installer magnet against the external dome housing to close an internal magnetic reed switch) for 3.0 seconds. The dome illuminates SOLID YELLOW and sets Register 40253 = 1.
    • Sequential Isolated Mode (Alternative): For over-door fixtures where physical ladder access is inconvenient, new uncommissioned domes can be attached to the bus one unit at a time during initial installation; the Gateway discovers and addresses each new unit at ID 255 without physical button holds.
  • Address Assignment: The Gateway polls address 255 for Reg 40253 == 1, writes the assigned Slave ID (e.g. 20 or 120) into Register 255 (40256), the dome echoes the reply, burns the ID to its 8-byte EEPROM, illuminates SOLID GREEN for 3.0 seconds, and the Gateway pushes Registers 40011 (Cycle Interval) and 40012 (Idle Glow Color).

B. Complete Microcontroller Discovery State Machine (C Code)

// =========================================================================
// MICROCONTROLLER DISCOVERY & SLAVE ID STATE MACHINE (C / C++)
// =========================================================================

enum DeviceState {
    STATE_NORMAL_RUNNING,       // Normal hospital operation
    STATE_DISCOVERY_FLASHING,   // Rapid LED blink after receiving Broadcast
    STATE_PAIRING_SELECTED,     // Technician held Button 1 for 3s (Reg 40253 = 1)
    STATE_ID_CONFIRMED          // Green 3s non-blocking confirmation after ID write
};

enum DeviceState current_state = STATE_NORMAL_RUNNING;
uint32_t blink_timer = 0;
uint32_t discovery_timeout_timer = 0;
uint32_t green_confirm_timer = 0;
bool blink_led_toggle = false;

// 1. In your Main Loop (called continuously):
void loop_discovery_handler() {
    // A. Auto-exit discovery mode after 10-minute timeout
    if (current_state == STATE_DISCOVERY_FLASHING || current_state == STATE_PAIRING_SELECTED) {
        if (millis() - discovery_timeout_timer >= 600000) { // 10 min
            current_state = STATE_NORMAL_RUNNING;
            reg_40253_pairing_selected = 0;
            set_all_leds_idle();
        }
    }

    // B. If in Discovery Flashing Mode -> Blink all LEDs at 2.5Hz (200ms ON / 200ms OFF)
    if (current_state == STATE_DISCOVERY_FLASHING) {
        if (millis() - blink_timer >= 200) {
            blink_timer = millis();
            blink_led_toggle = !blink_led_toggle;
            set_all_leds(blink_led_toggle ? COLOR_CYAN : COLOR_OFF);
        }
    }

    // C. Non-blocking Green 3-second confirmation
    if (current_state == STATE_ID_CONFIRMED) {
        if (millis() - green_confirm_timer >= 3000) {
            current_state = STATE_NORMAL_RUNNING;
            set_all_leds_idle();
        }
    }
}

// 2. In your Button ISR / Polling Routine:
void on_button1_held_3_seconds() {
    // If unit is in Discovery Mode and Button 1 is held 3s -> Select this unit!
    if (current_state == STATE_DISCOVERY_FLASHING) {
        current_state = STATE_PAIRING_SELECTED;
        reg_40253_pairing_selected = 1; // Dedicated pairing flag
        set_button_led(0, COLOR_YELLOW); // Solid Yellow on Button 1
    }
}

// 3. In your Modbus Register Write Callback:
void handle_modbus_register_write(uint8_t slave_addr, uint16_t reg_addr, uint16_t write_val) {
    // A. Broadcast Discovery Command (Reg 254 / 0x00FE)
    if (reg_addr == 0x00FE) {
        if (write_val == 0x00AA) {
            if (config.is_commissioned == 0) {
                current_state = STATE_DISCOVERY_FLASHING;
                discovery_timeout_timer = millis();
            }
        } else if (write_val == 0x00FF) {
            current_state = STATE_DISCOVERY_FLASHING;
            discovery_timeout_timer = millis();
        } else if (write_val == 0x0000) {
            current_state = STATE_NORMAL_RUNNING;
            reg_40253_pairing_selected = 0;
            set_all_leds_idle();
        }
    }
    
    // B. Slave ID Assignment (Reg 255 / 0x00FF)
    else if (reg_addr == 0x00FF) {
        // At address 255, only accept write if this unit is selected
        if (slave_addr == 255 && current_state != STATE_PAIRING_SELECTED) {
            return; // Ignore write to prevent multi-device collisions
        }

        if (write_val >= 1 && write_val <= 247) {
            // 1. Send Modbus echo reply FIRST from current address before switching
            send_modbus_echo_reply(slave_addr, reg_addr, write_val);

            // 2. Burn new Slave ID and mark as Commissioned in EEPROM
            config.slave_id = (uint8_t)write_val;
            config.is_commissioned = 1;
            reg_40253_pairing_selected = 0;
            save_config_to_eeprom();
            
            // 3. Switch active Modbus listening address
            modbus_set_slave_address(config.slave_id);

            // 4. Visual & Audible Non-Blocking Confirmation
            current_state = STATE_ID_CONFIRMED;
            green_confirm_timer = millis();
            set_all_leds(COLOR_GREEN);
            buzzer_beep(200);
        }
    }
}

8. Summary: Exactly What Registers & Values Each Wall Unit Stores in EEPROM (53 Bytes Total)

To make it 100% simple for the microcontroller firmware developer, here is the complete packed 53-Byte EEPROM memory layout that must be allocated in non-volatile Flash/EEPROM:

EEPROM Offset Modbus Register Hex Addr Data Type Factory Default What It Stores & Why
0x00 Reg 255 (40256) 0x00FF uint8_t 255 Slave ID: Modbus address of the device (1 to 247).
0x01 Reg 253 (40254) 0x00FD uint8_t 0 (Pending) Commissioned Flag: 0 = Factory/Unassigned, 1 = Commissioned by Siscall.
0x02..0x03 Reg 1 (40002) 0x0001 uint16_t 0xFFFF Single-Press Key Mask: Bitmask enabling short presses.
0x04..0x05 Reg 2 (40003) 0x0002 uint16_t 0xFFFF Long-Press Key Mask: Bitmask enabling long presses.
0x06..0x07 Reg 3 (40004) 0x0003 uint16_t 2000 ms Long-Press Hold Time: Milliseconds required to hold (500–5000ms).
0x08..0x09 Reg 4 (40005) 0x0004 uint16_t 50 ms Debounce Time: Hardware debounce filter in ms (10–200ms).
0x0A Reg 5 (40006) 0x0005 uint8_t 3 (Blue) Idle Glow Color: Backlight color in clean idle state (3=Blue, 0=OFF).
0x0B..0x0E Reg 10,12,14,16 0x000A.. uint8_t[4] [2, 32, 2, 4] Button 1..4 SP Action Codes: Bitmasks for single-press actions.
0x0F..0x12 Reg 11,13,15,17 0x000B.. uint8_t[4] [32, 32, 2, 1] Button 1..4 LP Action Codes: Bitmasks for long-press actions.
0x13..0x14 Reg 18, 19 0x0012.. uint8_t[2] [32, 32] Toilet Btn 1 (Pull) SP / LP Action Codes (40019, 40020)
0x15..0x16 Reg 36, 37 0x0024.. uint8_t[2] [1, 1] Toilet Btn 2 (Cancel) SP / LP Action Codes (40037, 40038)
0x17..0x1A Reg 30..33 0x001E.. uint8_t[4] [2, 32, 4, 1] Remote Pendant Btn 1..2 SP / LP Action Codes (40031..40034)
0x1B..0x1E Reg 20,22,24,26 0x0014.. uint8_t[4] [4, 1, 5, 2] Button 1..4 SP Colors: 4=Yellow, 1=Red, 5=Cyan, 2=Green.
0x1F..0x22 Reg 21,23,25,27 0x0015.. uint8_t[4] [1, 1, 1, 0] Button 1..4 LP Colors: 1=Red, 1=Red, 1=Red, 0=OFF.
0x23 Reg 28 (40029) 0x001C uint8_t 4 (Yellow) Toilet Pull Cord Color
0x24 Reg 29 (40030) 0x001D uint8_t 4 (Yellow) Remote Handset Call Color
0x25..0x28 Reg 60,62,64,66 0x003C.. uint8_t[4] [3, 1, 4, 0] Button 1..4 SP Priorities (40061,63,65,67): 3=Normal, 1=Code Blue, 4=Assist, 0=Ack.
0x29..0x2C Reg 61,63,65,67 0x003D.. uint8_t[4] [2, 1, 4, 0] Button 1..4 LP Priorities (40062,64,66,68): 2=Emergency, 1=CPR, 4=Assist, 0=Clear.
0x2D..0x2E Reg 68, 69 0x0044.. uint8_t[2] [2, 1] Toilet Btn 1 (Pull) SP / LP Priorities (40069, 40070)
0x2F..0x30 Reg 70, 71 0x0046.. uint8_t[2] [0, 0] Toilet Btn 2 (Cancel) SP / LP Priorities (40071, 40072 - 0=Non-Call)
0x31..0x34 Reg 72..75 0x0048.. uint8_t[4] [3, 2, 0, 0] Remote Pendant Btn 1..2 SP / LP Priorities (40073..40076)
Total EEPROM Size Needed: Exactly 53 Bytes of internal non-volatile EEPROM/Flash storage per microcontroller.

9. Microcontroller Firmware Boilerplate (C / C++ Full Reference)

Complete C/C++ packed firmware structure and state handler for the hardware microcontroller:

// =========================================================================
// SISCALL PRO - MICROCONTROLLER FIRMWARE REFERENCE IMPLEMENTATION (C / C++)
// =========================================================================

#include <stdint.h>
#include <stdbool.h>

// --- EEPROM Non-Volatile Memory Storage Structure (53 Bytes Total, Packed) ---
typedef struct __attribute__((packed)) {
    uint8_t  slave_id;                  // 0x00: Reg 255 (Default 255 / 0xFF)
    uint8_t  is_commissioned;           // 0x01: Reg 253 (0 = Factory/Uncommissioned, 1 = Commissioned)
    uint16_t single_press_mask;         // 0x02..0x03: Reg 1 (Default 0xFFFF)
    uint16_t long_press_mask;           // 0x04..0x05: Reg 2 (Default 0xFFFF)
    uint16_t long_press_hold_ms;        // 0x06..0x07: Reg 3 (Default 2000 ms)
    uint16_t debounce_ms;               // 0x08..0x09: Reg 4 (Default 50 ms)
    uint8_t  idle_glow_color;           // 0x0A: Reg 5 (Default 3 = Blue)
    
    // Action Code Bitmasks (16 Bytes: 0x0B..0x1A)
    uint8_t  btn_sp_action[4];          // 0x0B..0x0E: Reg 10,12,14,16 (Default: 2, 32, 2, 4)
    uint8_t  btn_lp_action[4];          // 0x0F..0x12: Reg 11,13,15,17 (Default: 32, 32, 2, 1)
    uint8_t  toilet_btn1_action[2];     // 0x13..0x14: Reg 18,19 (Default: 32, 32)
    uint8_t  toilet_btn2_action[2];     // 0x15..0x16: Reg 36,37 (Default: 1, 1)
    uint8_t  remote_action[4];          // 0x17..0x1A: Reg 30..33 (Default: 2, 32, 4, 1)

    // RGB Color Codes (10 Bytes: 0x1B..0x24)
    uint8_t  btn_sp_color[4];           // 0x1B..0x1E: Reg 20,22,24,26 (Default: 4, 1, 5, 2)
    uint8_t  btn_lp_color[4];           // 0x1F..0x22: Reg 21,23,25,27 (Default: 1, 1, 1, 0)
    uint8_t  toilet_color;              // 0x23: Reg 28 (Default 4 = Yellow)
    uint8_t  handset_color;             // 0x24: Reg 29 (Default 4 = Yellow)

    // Priority Ranks (16 Bytes: 0x25..0x34, 1..16, 0 for non-calls)
    uint8_t  btn_sp_priority[4];        // 0x25..0x28: Reg 60,62,64,66 (Default: 3, 1, 4, 0)
    uint8_t  btn_lp_priority[4];        // 0x29..0x2C: Reg 61,63,65,67 (Default: 2, 1, 4, 0)
    uint8_t  toilet_btn1_priority[2];   // 0x2D..0x2E: Reg 68,69 (Default: 2, 1)
    uint8_t  toilet_btn2_priority[2];   // 0x2F..0x30: Reg 70,71 (Default: 0, 0)
    uint8_t  remote_priority[4];        // 0x31..0x34: Reg 72..75 (Default: 3, 2, 0, 0)
} DeviceConfig_t;

DeviceConfig_t config;
uint16_t live_status_reg40001 = 0x0000; // Latched bits cleared by Reg 40009
uint16_t continuous_status_reg40008 = 0x0000; // Bit 0 = Bed Occ, Bit 1 = Tamper

// --- GPIO Pin Output Function for 7-Color Digital RGB ---
void set_rgb_pins(uint8_t red_pin, uint8_t green_pin, uint8_t blue_pin, uint8_t color_code) {
    switch(color_code) {
        case 0: digitalWrite(red_pin, 0); digitalWrite(green_pin, 0); digitalWrite(blue_pin, 0); break; // OFF
        case 1: digitalWrite(red_pin, 1); digitalWrite(green_pin, 0); digitalWrite(blue_pin, 0); break; // RED
        case 2: digitalWrite(red_pin, 0); digitalWrite(green_pin, 1); digitalWrite(blue_pin, 0); break; // GREEN
        case 3: digitalWrite(red_pin, 0); digitalWrite(green_pin, 0); digitalWrite(blue_pin, 1); break; // BLUE
        case 4: digitalWrite(red_pin, 1); digitalWrite(green_pin, 1); digitalWrite(blue_pin, 0); break; // YELLOW
        case 5: digitalWrite(red_pin, 0); digitalWrite(green_pin, 1); digitalWrite(blue_pin, 1); break; // CYAN
        case 6: digitalWrite(red_pin, 1); digitalWrite(green_pin, 0); digitalWrite(blue_pin, 1); break; // MAGENTA
        case 7: digitalWrite(red_pin, 1); digitalWrite(green_pin, 1); digitalWrite(blue_pin, 1); break; // WHITE
    }
}

10. Concrete Communication Hex Packet Examples (Verified Modbus RTU CRC-16)

Example 1: Master Polls Wall Unit Status (Read Reg 0 on Slave ID 1)

Master Request:  01 03 00 00 00 01 84 0A  (Slave 1, FC 03, Reg 0, Qty 1, CRC)
Slave Response:  01 03 02 00 01 79 84     (Slave 1, FC 03, 2 Bytes, Value = 0x0001 [Button 1 Pressed], CRC)

Example 2: Master Broadcasts Discovery Mode (Reg 254 = 0x00AA or 0x00FF)

Broadcast New/Pending Only: 00 06 00 FE 00 AA 69 94  (Broadcast 0x00, FC 06, Reg 254 = 0x00AA, CRC)
Broadcast Force ALL Units:  00 06 00 FE 00 FF A9 AB  (Broadcast 0x00, FC 06, Reg 254 = 0x00FF, CRC)

Example 3: Master Reads Dedicated Pairing Flag (Register 40253 / Offset 252 on Slave 255)

Master Request:  FF 03 00 FC 00 01 51 E4  (Slave 255, FC 03, Reg 252, Qty 1, CRC)
Slave Response:  FF 03 02 00 01 50 50     (Slave 255, FC 03, 2 Bytes, Reg 40253 = 1 [Unit Selected], CRC)

Example 4: Master Assigns Slave ID 101 (Reg 255 = 101)

Master Request:  FF 06 00 FF 00 65 6C 0F  (Target Slave 255, FC 06, Reg 255, Value 101, CRC)
Slave Response:  FF 06 00 FF 00 65 6C 0F  (Echo Response, burns ID 101 & sets Reg 253=1 into EEPROM)

Example 5: Master Configures Silent Nurse Call Bitmask (10 = 0x000A)

Master Request:  01 06 00 0A 00 0A 29 CF  (Slave 1, FC 06, Reg 10, Value 0x000A, CRC)

Example 6: Master Configures Call + Attendance Bitmask (18 = 0x0012)

Master Request:  01 06 00 0A 00 12 29 C5  (Slave 1, FC 06, Reg 10, Value 0x0012, CRC)

Example 7: Master Configures Corridor Door Dome Light (Slave 20)

Write Mode (Reg 0 = 3):     14 06 00 00 00 03 CB 0E
Write Color 1 (Reg 1 = 4):  14 06 00 01 00 04 DB 0C
Write Color 2 (Reg 2 = 1):  14 06 00 02 00 01 EB 0F
Write Interval (Reg 10 = 1500ms): 14 06 00 0A 05 DC A9 C4