|
| 1 | +# ND-100/120 Panel Controller - Complete Command Analysis |
| 2 | + |
| 3 | +## 1. Summary Section |
| 4 | + |
| 5 | +### 1.1 Command Format Structure |
| 6 | + |
| 7 | +**Input Command Format** (PORTA bits 5-0): |
| 8 | +``` |
| 9 | +Bit Layout: |
| 10 | + 7 6 5 4 3 2 1 0 |
| 11 | + ┌─┬─┬─┬─┬─┬─┬─┬─┐ |
| 12 | + │S│C│ COMMAND │ |
| 13 | + └─┴─┴─────────────────┘ |
| 14 | + │ │ │ |
| 15 | + │ │ └── 6-bit command code (0x00-0x3F) |
| 16 | + │ └─────────── Button change flag (0x40) |
| 17 | + └─────────────── Status/control bit (0x80) |
| 18 | +``` |
| 19 | + |
| 20 | +**Command Processing Steps**: |
| 21 | +1. Extract command: `command = PORTA & 0x3F` |
| 22 | +2. Select lookup table: `table = (DisplayControlFlags & 0x10) ? 0x8B : 0x80` |
| 23 | +3. Lookup dispatch: `dispatch_code = table[command + 1] << 1` |
| 24 | +4. Execute handler: `switch(dispatch_code)` with cases 0x00-0xFE (even numbers) |
| 25 | + |
| 26 | +**Response Format** (PORTB output): |
| 27 | +``` |
| 28 | +Bit Layout: |
| 29 | + 7 6 5 4 3 2 1 0 |
| 30 | + ┌─┬─┬─┬─┬─┬─┬─┬─┐ |
| 31 | + │S│ RESPONSE DATA │ |
| 32 | + └─┴─────────────────────┘ |
| 33 | + │ │ |
| 34 | + │ └── 7-bit response data |
| 35 | + └────────────── Status bit (combined with DisplayControlFlags) |
| 36 | +``` |
| 37 | + |
| 38 | +**Response Protocol**: |
| 39 | +```c |
| 40 | +PORTC = PORTC & 0xFE; // Clear strobe |
| 41 | +PORTB = (data | status) & 0x7F; // Set response + status |
| 42 | +PORTC = PORTC | 1; // Set strobe (data valid) |
| 43 | +``` |
| 44 | + |
| 45 | +### 1.2 Command Summary Table |
| 46 | + |
| 47 | +| Dispatch | Handler | Command Name | Response | Address | Notes | |
| 48 | +|----------|---------|--------------|----------|---------|-------| |
| 49 | +| 0x00 | caseD_34 | Display Update | Status | 0x01DB | Display control operation | |
| 50 | +| 0x02 | caseD_2a | Conditional Update | Status | 0x01D1 | Conditional display operation | |
| 51 | +| 0x04 | caseD_46 | Multi-stage Update | Status | 0x01ED | Complex display sequence | |
| 52 | +| 0x06 | caseD_56 | *Unknown* | Status | 0x01FD | Handler not analyzed | |
| 53 | +| 0x08 | caseD_5a | *Unknown* | Status | 0x0201 | Handler not analyzed | |
| 54 | +| 0x0A | caseD_5e | *Unknown* | Status | 0x0205 | Via indirect jump | |
| 55 | +| 0x0C | caseD_6c | *Unknown* | Status | 0x0213 | Handler not analyzed | |
| 56 | +| 0x10-0x18 | Input Polling | Button Input | None | 0x01B7 | Waits for button release | |
| 57 | +| 0x90-0x94 | Direct Output | Data Output | Data | 0x023C | Direct PORTB output | |
| 58 | +| 0xA2 | Special Return | Status Return | Combined | - | Returns combined status | |
| 59 | +| 0xEE-0xFE | Serial Data | Data Reception | None | 0x02DE | Serial input processing | |
| 60 | + |
| 61 | +### 1.3 Lookup Table Structure |
| 62 | + |
| 63 | +**Primary Table (0x80)**: Used when `DisplayControlFlags & 0x10 == 0` |
| 64 | +**Secondary Table (0x8B)**: Used when `DisplayControlFlags & 0x10 != 0` |
| 65 | + |
| 66 | +``` |
| 67 | +Table Entry Format: |
| 68 | +[command_code][dispatch_flags] |
| 69 | +``` |
| 70 | + |
| 71 | +## 2. Detailed Command Analysis |
| 72 | + |
| 73 | +### 2.1 Command 0x00 (Dispatch 0x00) — Display Update |
| 74 | + |
| 75 | +**Handler**: `caseD_34` at address `0x01DB` |
| 76 | + |
| 77 | +**Processing Logic**: |
| 78 | +```c |
| 79 | +if ((ButtonStateBuffer & 0x80) == 0) { |
| 80 | + OutputToDisplayDriver(2); // Send data=2 with status |
| 81 | + OutputToDisplayDriver(); // Send status only |
| 82 | + caseD_a4(); // Execute display update sequence |
| 83 | + CompleteCommandProcessing(4); // Complete with response=4 |
| 84 | +} else { |
| 85 | + WriteToDisplayPort(DisplayControlFlags); // Direct status output |
| 86 | + caseD_10(); // Execute handler 0x10 |
| 87 | + UpdateTimersAndWait(); // Update timers and wait |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +**Response**: Status byte via `CompleteCommandProcessing(4)` |
| 92 | +**Internal State Changes**: Updates DisplayControlFlags, executes display sequences |
| 93 | +**Subroutines**: `OutputToDisplayDriver`, `caseD_a4`, `CompleteCommandProcessing` |
| 94 | + |
| 95 | +### 2.2 Command 0x01 (Dispatch 0x02) — Conditional Update |
| 96 | + |
| 97 | +**Handler**: `caseD_2a` at address `0x01D1` |
| 98 | + |
| 99 | +**Processing Logic**: |
| 100 | +```c |
| 101 | +if (((DisplayControlFlags & 0x10) == 0) && ((SerialInputData & 8) != 0)) { |
| 102 | + WriteToDisplayPort(DisplayControlFlags); // Output status |
| 103 | + caseD_10(); // Execute handler |
| 104 | + UpdateTimersAndWait(); // Update and wait |
| 105 | +} else { |
| 106 | + CompleteCommandProcessing(1); // Complete with response=1 |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +**Response**: Status byte via `CompleteCommandProcessing(1)` or direct output |
| 111 | +**Internal State Changes**: Conditional based on control flags and input data |
| 112 | +**Subroutines**: `WriteToDisplayPort`, `caseD_10`, `CompleteCommandProcessing` |
| 113 | + |
| 114 | +### 2.3 Command 0x02 (Dispatch 0x04) — Multi-stage Update |
| 115 | + |
| 116 | +**Handler**: `caseD_46` at address `0x01ED` |
| 117 | + |
| 118 | +**Processing Logic**: |
| 119 | +```c |
| 120 | +OutputToDisplayDriver(2); // Send data=2 with status |
| 121 | +caseD_10(); // Execute handler 0x10 |
| 122 | +OutputToDisplayDriver(); // Send status only |
| 123 | +caseD_a4(); // Execute display sequence |
| 124 | +WriteToDisplayPort(DisplayControlFlags); // Output final status |
| 125 | +caseD_10(); // Execute handler again |
| 126 | +UpdateTimersAndWait(); // Complete operation |
| 127 | +``` |
| 128 | +
|
| 129 | +**Response**: Multiple outputs via `OutputToDisplayDriver` and `WriteToDisplayPort` |
| 130 | +**Internal State Changes**: Complex multi-stage display operation |
| 131 | +**Subroutines**: Multiple display and control functions |
| 132 | +
|
| 133 | +### 2.4 Command 0x08-0x0C (Dispatch 0x10-0x18) — Button Input Polling |
| 134 | +
|
| 135 | +**Handler**: Code at `0x01B7` |
| 136 | +
|
| 137 | +**Processing Logic**: |
| 138 | +```c |
| 139 | +do { |
| 140 | + bVar4 = PORTA; // Read input |
| 141 | + bVar4 = bVar4 & 0x3f; // Mask to command bits |
| 142 | + bVar8 = bVar4 == 0; // Check if zero |
| 143 | +} while (!bVar8); // Wait until input clear |
| 144 | +return bVar4; // Return final value |
| 145 | +``` |
| 146 | + |
| 147 | +**Response**: Returns button state value |
| 148 | +**Internal State Changes**: None (polling only) |
| 149 | +**Usage**: Waits for button release, used in button processing |
| 150 | + |
| 151 | +### 2.5 Command 0x48-0x4A (Dispatch 0x90-0x94) — Direct Data Output |
| 152 | + |
| 153 | +**Handler**: Code at `0x023C` |
| 154 | + |
| 155 | +**Processing Logic**: |
| 156 | +```c |
| 157 | +bVar4 = (bVar4 | DisplayControlFlags) & 0x7f; // Combine data + status |
| 158 | +PORTC = PORTC & 0xfe; // Clear strobe |
| 159 | +PORTB = bVar4; // Set output data |
| 160 | +PORTC = PORTC | 1; // Set strobe |
| 161 | +// Timing delay loop |
| 162 | +``` |
| 163 | + |
| 164 | +**Response**: Direct 7-bit data output via PORTB |
| 165 | +**Internal State Changes**: None (direct output only) |
| 166 | +**Usage**: Raw data transmission to CPU |
| 167 | + |
| 168 | +### 2.6 Command 0x51 (Dispatch 0xA2) — Special Status Return |
| 169 | + |
| 170 | +**Handler**: Inline code in switch statement |
| 171 | + |
| 172 | +**Processing Logic**: |
| 173 | +```c |
| 174 | +CountdownTimer2 = 0x50; // Set timer value |
| 175 | +CommandParameter = bVar3; // Store command |
| 176 | +return bVar4 | *(byte *)(ushort)bVar7; // Return combined value |
| 177 | +``` |
| 178 | + |
| 179 | +**Response**: Combined status and table data |
| 180 | +**Internal State Changes**: Updates timer and command storage |
| 181 | +**Usage**: Special command completion with enhanced status |
| 182 | + |
| 183 | +### 2.7 Command 0x77-0x7F (Dispatch 0xEE-0xFE) — Serial Data Reception |
| 184 | + |
| 185 | +**Handler**: Code at `0x02DE` (complex serial processing) |
| 186 | + |
| 187 | +**Processing Logic**: |
| 188 | +```c |
| 189 | +// Multi-byte serial data reception loop |
| 190 | +bVar7 = 8; // 8 bytes to receive |
| 191 | +do { |
| 192 | + // 8-bit reception loop per byte |
| 193 | + do { |
| 194 | + PORTC = PORTC & 0xfd; // Clear clock |
| 195 | + PORTC = PORTC | 2; // Set clock |
| 196 | + SerialInputData = PORTA; // Read input |
| 197 | + |
| 198 | + // Shift data into 3 registers |
| 199 | + ShiftRegister1 = ShiftRegister1 >> 1; |
| 200 | + ShiftRegister2 = ShiftRegister2 >> 1; |
| 201 | + ShiftRegister3 = ShiftRegister3 >> 1; |
| 202 | + |
| 203 | + // Input active-low data |
| 204 | + if ((PORTA & 1) == 0) ShiftRegister1 |= 0x80; |
| 205 | + if ((PORTA & 2) == 0) ShiftRegister2 |= 0x80; |
| 206 | + if ((PORTA & 4) == 0) ShiftRegister3 |= 0x80; |
| 207 | + |
| 208 | + BitCounter++; |
| 209 | + } while (BitCounter != 8); |
| 210 | + |
| 211 | + // Store completed bytes in buffers |
| 212 | + *(byte *)(bVar7 + 0x2d) = ShiftRegister1; // TimeDataBuffer |
| 213 | + *(byte *)(bVar7 + 0x35) = ShiftRegister2; // TimeDisplayBuffer |
| 214 | + *(byte *)(bVar7 + 0x3d) = ShiftRegister3; // StatusDataBuffer |
| 215 | + |
| 216 | + bVar7--; |
| 217 | +} while (bVar7 != 0); |
| 218 | + |
| 219 | +// Process received data for display |
| 220 | +// (Complex character decoding and display logic follows) |
| 221 | +``` |
| 222 | + |
| 223 | +**Response**: None (data reception only) |
| 224 | +**Internal State Changes**: Updates time, display, and status buffers |
| 225 | +**Subroutines**: `DecodeCharacterFromTable`, `ShowSystemStatusDisplay`, display functions |
| 226 | + |
| 227 | +## 3. Response Generation Functions |
| 228 | + |
| 229 | +### 3.1 OutputToDisplayDriver(data) |
| 230 | + |
| 231 | +**Address**: `0x0238` |
| 232 | +**Function**: Combines data with status and outputs via strobe protocol |
| 233 | +```c |
| 234 | +PORTC = PORTC & 0xfe; // Clear strobe |
| 235 | +PORTB = (data | DisplayControlFlags) & 0x7f; // Combine data + status |
| 236 | +PORTC = PORTC | 1; // Set strobe |
| 237 | +// Timing delay (32 × 256 cycles) |
| 238 | +``` |
| 239 | + |
| 240 | +### 3.2 WriteToDisplayPort(data) |
| 241 | + |
| 242 | +**Address**: `0x023C` |
| 243 | +**Function**: Direct data output via strobe protocol |
| 244 | +```c |
| 245 | +PORTC = PORTC & 0xfe; // Clear strobe |
| 246 | +PORTB = data; // Set data |
| 247 | +PORTC = PORTC | 1; // Set strobe |
| 248 | +// Timing delay (32 × 256 cycles) |
| 249 | +``` |
| 250 | + |
| 251 | +### 3.3 CompleteCommandProcessing(response_code) |
| 252 | + |
| 253 | +**Address**: `0x01C0` |
| 254 | +**Function**: Standard command completion sequence |
| 255 | +```c |
| 256 | +OutputToDisplayDriver(); // Send status |
| 257 | +OutputToDisplayDriver(); // Send status again |
| 258 | +WriteToDisplayPort(DisplayControlFlags); // Send final status |
| 259 | +caseD_10(); // Execute handler |
| 260 | +UpdateTimersAndWait(); // Complete with timing |
| 261 | +``` |
| 262 | +
|
| 263 | +## 4. Control Flags and State Variables |
| 264 | +
|
| 265 | +### 4.1 DisplayControlFlags (0x14) |
| 266 | +
|
| 267 | +**Usage**: Primary control register for command processing |
| 268 | +``` |
| 269 | +Bit 7: CPU communication status |
| 270 | +Bit 6: Additional display control |
| 271 | +Bit 5: Display enable flag (0x20) |
| 272 | +Bit 4: Command table select (0=0x80, 1=0x8B) |
| 273 | +Bit 3-0: Display mode and addressing |
| 274 | +``` |
| 275 | +
|
| 276 | +### 4.2 Command Processing Variables |
| 277 | +
|
| 278 | +- **CommandParameter (0x16)**: Current command code (PORTA & 0x3F) |
| 279 | +- **ButtonStateBuffer (0x12)**: Current button/input state |
| 280 | +- **SerialInputData (0x20)**: Raw input data from PORTA |
| 281 | +- **ButtonChangeFlags (0x17)**: Detected input changes |
| 282 | +
|
| 283 | +## 5. Ambiguities and Unknowns |
| 284 | +
|
| 285 | +### 5.1 Unanalyzed Command Handlers |
| 286 | +
|
| 287 | +**Commands requiring further analysis**: |
| 288 | +- **caseD_56 (0x01FD)**: Handler not decompiled |
| 289 | +- **caseD_5a (0x0201)**: Handler not decompiled |
| 290 | +- **caseD_6c (0x0213)**: Handler not decompiled |
| 291 | +- **caseD_10**: Referenced frequently but not located |
| 292 | +- **caseD_a4**: Display sequence handler not analyzed |
| 293 | +
|
| 294 | +### 5.2 Lookup Table Contents |
| 295 | +
|
| 296 | +**Unknown table entries**: |
| 297 | +- Complete contents of command_lookup_table_primary (0x80) |
| 298 | +- Complete contents of command_lookup_table_secondary (0x8B) |
| 299 | +- Mapping between command codes and dispatch values |
| 300 | +- Table termination and bounds checking |
| 301 | +
|
| 302 | +### 5.3 Response Format Details |
| 303 | +
|
| 304 | +**Partially understood**: |
| 305 | +- Exact bit meanings in status responses |
| 306 | +- CPU interpretation of strobe timing |
| 307 | +- Error or fault response codes |
| 308 | +- Response data encoding for specific commands |
| 309 | +
|
| 310 | +### 5.4 Serial Data Protocol |
| 311 | +
|
| 312 | +**Unknown aspects**: |
| 313 | +- Complete data packet structure (192 bits total) |
| 314 | +- Synchronization and framing |
| 315 | +- Error detection/correction |
| 316 | +- Timing requirements and tolerances |
| 317 | +
|
| 318 | +## 6. Implementation Notes |
| 319 | +
|
| 320 | +### 6.1 Command Dispatch Mechanism |
| 321 | +
|
| 322 | +The firmware uses a sophisticated two-level dispatch system: |
| 323 | +1. **Command extraction**: `PORTA & 0x3F` gives 6-bit command (0-63) |
| 324 | +2. **Table selection**: DisplayControlFlags bit 4 selects primary/secondary table |
| 325 | +3. **Lookup**: `table[command+1] << 1` gives dispatch code (even numbers 0x00-0xFE) |
| 326 | +4. **Switch execution**: Massive switch statement with 128+ cases |
| 327 | +
|
| 328 | +### 6.2 Response Timing |
| 329 | +
|
| 330 | +All responses use identical strobe protocol: |
| 331 | +- Clear PORTC bit 0 (setup) |
| 332 | +- Set PORTB data (valid data) |
| 333 | +- Set PORTC bit 0 (strobe) |
| 334 | +- Fixed delay loop (8192 cycles typical) |
| 335 | +
|
| 336 | +### 6.3 State Machine Architecture |
| 337 | +
|
| 338 | +The firmware implements a complex state machine where: |
| 339 | +- Commands can modify DisplayControlFlags |
| 340 | +- Flag changes affect subsequent command interpretation |
| 341 | +- Multiple response stages possible per command |
| 342 | +- Timer coordination maintains CPU synchronization |
| 343 | +
|
| 344 | +--- |
| 345 | +
|
| 346 | +*This analysis covers all identifiable commands in the ProcessData switch statement. Further investigation required for complete handler decompilation and lookup table contents.* |
0 commit comments