Two detailed reports from analyzing all firmware variants loaded into Ghidra: 1. v2.06 vs v2.13 FW1 comparative analysis: - Complete vendor command dispatch table mapping (0x80-0x9D) - 3 new commands in v2.13: GET_DEMOD_STATUS (0x99), INIT_DEMOD (0x9A), DELAY_COMMAND (0x9C) - DiSEqC architecture change: GPIO bit-bang -> I2C controller - INT0 repurposed from USB re-enumeration to demodulator polling - Hardware revision detection via descriptor byte 2. v2.13 sub-variant comparison (FW1/FW2/FW3): - FW1: I2C-connected demodulator (original SkyWalker-1 hardware) - FW2: Parallel-bus demodulator via P0/P1 GPIO - FW3: Enhanced parallel-bus with dual-phase read and OR accumulation - All three support identical modulation types, differ only in hardware interface
379 lines
21 KiB
Markdown
379 lines
21 KiB
Markdown
# Genpix SkyWalker-1 FX2 Firmware Comparative Analysis: v2.06 vs v2.13 FW1
|
|
|
|
## Executive Summary
|
|
|
|
v2.13 is a significant evolution of the v2.06 firmware with 21 additional functions (82 vs 61). The key changes are:
|
|
|
|
1. **Three new vendor commands** (0x99, 0x9A, 0x9C) for LNB/tuner control
|
|
2. **Restructured INT0 handler** with active satellite front-end polling
|
|
3. **I2C-based initialization** with retry logic for the satellite demodulator
|
|
4. **Version-aware code paths** (hardware revision detection via descriptor byte)
|
|
5. **Refactored DiSEqC implementation** using I2C-based bus control
|
|
6. **Simplified BCM4500 status polling** (consolidated from 3 register reads to 1)
|
|
|
|
---
|
|
|
|
## 1. Vendor Command Dispatch Table Comparison
|
|
|
|
Both versions use the same two-stage USB control request dispatch:
|
|
|
|
- **Stage 1** (`FUN_CODE_032a` / `FUN_CODE_034e`): Handles standard USB requests (bRequest 0x00-0x0B) via a 12-entry jump table at CODE:033B / CODE:035F. These handle GET_STATUS, CLEAR_FEATURE, SET_FEATURE, SET_ADDRESS, GET_DESCRIPTOR, SET_DESCRIPTOR, GET_CONFIGURATION, SET_CONFIGURATION, GET_INTERFACE, SET_INTERFACE, SYNCH_FRAME, and FW_VERSION_READ (0x0B).
|
|
|
|
- **Stage 2** (`FUN_CODE_0056`, identical in both versions): Handles vendor requests (bmRequestType bit 6 set, bRequest 0x80-0x9D) via a 30-entry jump table at CODE:0076. Range check: `(bRequest + 0x80) < 0x1E`, dispatching to `JMP @A+DPTR` at `0x76 + (bRequest - 0x80) * 2`.
|
|
|
|
### Vendor Command Jump Table (0x80-0x9D)
|
|
|
|
| bRequest | Name | v2.06 Target | v2.13 Target | Status |
|
|
|----------|------|-------------|-------------|--------|
|
|
| 0x80 | GET_8PSK_CONFIG | 0x00B2 | 0x00B2 | **Both**: Read config byte to EP0BUF (v2.06: IRAM 0x6D, v2.13: IRAM 0x4F) |
|
|
| 0x81 | SET_8PSK_CONFIG | 0x0326 (STALL) | 0x034A (STALL) | **Both STALL** - not implemented in either |
|
|
| 0x82 | (reserved) | 0x0326 (STALL) | 0x034A (STALL) | **Both STALL** |
|
|
| 0x83 | I2C_WRITE | 0x00F1 | 0x00F1 | **Both**: Same I2C write handler |
|
|
| 0x84 | I2C_READ | 0x0102 | 0x0102 | **Both**: Same I2C read handler |
|
|
| 0x85 | ARM_TRANSFER | 0x0110 | 0x0110 | **Both**: Same ARM transfer handler |
|
|
| 0x86 | TUNE_8PSK | 0x012E | 0x012E | **Both**: Same tuning handler |
|
|
| 0x87 | GET_SIGNAL_STRENGTH | 0x0140 | 0x0162 | **CHANGED** - see section below |
|
|
| 0x88 | LOAD_BCM4500 | 0x0326 (STALL) | 0x034A (STALL) | **Both STALL** - BCM4500 loading via different mechanism |
|
|
| 0x89 | BOOT_8PSK | 0x00C4 | 0x00C4 | **Both**: Same boot handler |
|
|
| 0x8A | START_INTERSIL | 0x019C | 0x01BE | **Relocated** but functionally similar |
|
|
| 0x8B | SET_LNB_VOLTAGE | 0x01CB | 0x01ED | **Relocated** but functionally similar |
|
|
| 0x8C | SET_22KHZ_TONE | 0x01DD | 0x01FF | **Relocated** but functionally similar |
|
|
| 0x8D | SEND_DISEQC_COMMAND | 0x01EF | 0x0211 | **CHANGED** - different DiSEqC implementation |
|
|
| 0x8E | SET_DVB_MODE | 0x0326 (STALL) | 0x034A (STALL) | **Both STALL** |
|
|
| 0x8F | (unknown) | 0x01FC | 0x021E | Both: Similar read-back function |
|
|
| 0x90 | GET_SIGNAL_LOCK | 0x020B | 0x022D | **Relocated** but functionally similar |
|
|
| 0x91 | (unknown) | 0x022C | 0x024E | Both: I2C read-back |
|
|
| 0x92 | (unknown) | 0x024A | 0x026C | Both: I2C read-back |
|
|
| 0x93 | GET_SERIAL_NUMBER | 0x026F | 0x0293 | **Relocated** but functionally similar |
|
|
| 0x94 | (unknown) | 0x01B9 | 0x01DB | Both: LNB-related |
|
|
| 0x95 | (unknown) | 0x02DF | 0x0303 | Both: Read-back function |
|
|
| 0x96 | (unknown) | 0x02B4 | 0x02D8 | Both: Similar handler |
|
|
| 0x97 | (unknown) | 0x02C1 | 0x02E5 | Both: Similar handler |
|
|
| 0x98 | (unknown) | 0x02CB | 0x02EF | Both: Similar handler |
|
|
| 0x99 | **NEW: GET_DEMOD_STATUS** | 0x0326 (STALL) | 0x0317 | **ADDED in v2.13** |
|
|
| 0x9A | **NEW: INIT_DEMOD** | 0x0326 (STALL) | 0x0140 | **ADDED in v2.13** |
|
|
| 0x9B | (reserved) | 0x0326 (STALL) | 0x034A (STALL) | **Both STALL** |
|
|
| 0x9C | **NEW: DELAY_COMMAND** | 0x0326 (STALL) | 0x032B | **ADDED in v2.13** |
|
|
| 0x9D | SET_MODE_FLAG | 0x02FA | 0x033A | **CHANGED** - different implementation |
|
|
|
|
### Commands Added in v2.13
|
|
|
|
**0x99 - GET_DEMOD_STATUS (new read command)**
|
|
```
|
|
LCALL FUN_CODE_2421 ; calls FUN_CODE_2239(0x3F, 0xF9)
|
|
; -> I2C read from device 0x3F, register 0xF9
|
|
MOV EP0BUF[0], R7 ; return I2C read result
|
|
EP0BCL = 1 ; send 1 byte back
|
|
```
|
|
Reads demodulator register 0xF9 via I2C (device address 0x3F) and returns the value to the host. This is a status/diagnostics register read for the satellite demodulator IC.
|
|
|
|
**0x9A - INIT_DEMOD (new control command)**
|
|
```
|
|
LCALL 0x231E ; EP0 flush/prepare
|
|
if (config_flags.0 == 1) { ; check if demodulator is present
|
|
counter = 0;
|
|
while (counter < 3) {
|
|
LCALL FUN_CODE_1977 ; initialization step
|
|
if (success) break;
|
|
counter++;
|
|
}
|
|
}
|
|
EP0BCL = 0 ; no data returned
|
|
```
|
|
Performs up to 3 attempts to initialize the demodulator, but only if the demodulator-present flag (bit 0 of DAT_INTMEM_4F) is set. This provides host-triggered re-initialization capability.
|
|
|
|
**0x9C - DELAY_COMMAND (new control command)**
|
|
```
|
|
R7 = wValue ; delay parameter from USB SETUP packet
|
|
LCALL FUN_CODE_1ac6 ; tuning/acquisition delay function
|
|
EP0BCL = 0 ; no data returned
|
|
```
|
|
Calls FUN_CODE_1ac6 with the wValue parameter from the USB SETUP packet. FUN_CODE_1ac6 performs an I2C-based tuning acquisition sequence: it reads demod register 0xF9, writes control values to registers 0xF8 and 0xF9, then polls register 0xF9 up to 40 times (0x28) waiting for bit 0 to be set (lock acquired). If lock fails, it calls FUN_CODE_1e3c which performs a full demodulator reset sequence.
|
|
|
|
### Commands Removed from v2.13
|
|
None were removed -- all commands that were STALL in v2.06 remain STALL in v2.13.
|
|
|
|
### Changed Command Implementations
|
|
|
|
**0x87 - GET_SIGNAL_STRENGTH (modified)**
|
|
- v2.06 at 0x0140: Checks DAT_INTMEM_6D bit 0 (demod active), reads three I2C status registers (0xA2, 0xA8, 0xA4) to compute signal quality, loops up to 6 iterations polling for demod readiness
|
|
- v2.13 at 0x0162: Checks DAT_INTMEM_4F bit 0 (demod active), reads I2C but uses different function call chain (FUN_CODE_1278 vs FUN_CODE_0c97). Same overall logic with relocated internal variables.
|
|
|
|
**0x8D - SEND_DISEQC_COMMAND (significantly changed)**
|
|
- v2.06: `LCALL 0x23e0; LCALL 0x1e41` -- calls a GPIO-based DiSEqC implementation (0x1e41) that directly manipulates P0 port pins and uses timer-based bit-banging with FUN_CODE_2098 for tone modulation
|
|
- v2.13: `LCALL 0x231e; LCALL FUN_CODE_0dbc` -- calls an I2C-based DiSEqC implementation that:
|
|
1. Reads wLength (0xE6BE) as message byte count
|
|
2. Pulls P0.3 low (power enable for DiSEqC bus)
|
|
3. Delays 15 units via FUN_CODE_14b9
|
|
4. If message bytes present: iterates through EP0BUF data, sending each byte via `func_0x2060` (I2C-based DiSEqC bus write)
|
|
5. If wValue == 0 and no bytes: calls `func_0x22b0` (tone burst command)
|
|
6. If wValue != 0 and no bytes: calls `func_0x2060(0, 0xFF)` (continuous tone)
|
|
|
|
This is a major architectural change: v2.06 uses GPIO bit-banging for DiSEqC, while v2.13 delegates DiSEqC to a dedicated I2C-connected controller chip.
|
|
|
|
**0x9D - SET_MODE_FLAG (different logic)**
|
|
- v2.06: Reads byte at descriptor_base + 10, checks if value is 4, 5, or 6, and conditionally sets bit flag 0x06 based on wValue - 1
|
|
- v2.13: Simply checks if wValue != 0, and if so calls FUN_CODE_21d1 which performs a conditional demodulator reset (calls FUN_CODE_1e3c if `_1_4` flag isn't already set, then writes I2C control registers 0xFC on both device 0x7F and 0x3F)
|
|
|
|
---
|
|
|
|
## 2. Key Function Correspondence
|
|
|
|
| v2.06 Function | v2.13 Function | Role |
|
|
|---------------|---------------|------|
|
|
| `main` (0x188D) | `main_entry` (0x170D) | RESET vector - clears IRAM, processes init table, jumps to init |
|
|
| `FUN_CODE_09a7` (0x09A7) | `FUN_CODE_0800` (0x0800) | Main init + main loop |
|
|
| `FUN_CODE_13c3` (0x13C3) | `FUN_CODE_11ab` (0x11AB) | USB/peripheral descriptor setup |
|
|
| `FUN_CODE_032a` (0x032A) | `FUN_CODE_034e` (0x034E) | Standard USB request handler |
|
|
| `FUN_CODE_0056` (0x0056) | `FUN_CODE_0056` (0x0056) | Vendor request dispatcher (identical code) |
|
|
| `FUN_CODE_2297` (0x2297) | `FUN_CODE_21ec` (0x21EC) | Main loop poll (USB IRQ processing) |
|
|
| `FUN_CODE_21ed` (0x21ED) | `FUN_CODE_2189` (0x2189) | EP2CS setup + PCON idle |
|
|
| `FUN_CODE_211d` (0x211D) | `FUN_CODE_20b9` (0x20B9) | CPUCS reset pulse (EP2 management) |
|
|
| `FUN_CODE_2174` (0x2174) | `FUN_CODE_2110` (0x2110) | USB descriptor type walker (identical code) |
|
|
| `FUN_CODE_1919` (0x1919) | `FUN_CODE_1800` (0x1800) | GPIF/FIFO management (identical logic) |
|
|
| `FUN_CODE_1d4f` (0x1D4F) | -- | v2.06 demod init (GPIO-based, complex) |
|
|
| -- | `FUN_CODE_1d4b` (0x1D4B) | v2.13 demod init (I2C write 4 bytes to 0x7F/0xF0) |
|
|
| `FUN_CODE_1da8` (0x1DA8) | -- | v2.06 I2C read with timeout (uses FUN_CODE_1556) |
|
|
| -- | `FUN_CODE_0eea` (0x0EEA) | v2.13 I2C read with retry (20 attempts) |
|
|
| `FUN_CODE_1dfb` (0x1DFB) | `FUN_CODE_14b9` (0x14B9) | Delay loop (clock-dependent timing) |
|
|
| `FUN_CODE_1cf3` (0x1CF3) | `FUN_CODE_1c44` (0x1C44) | Configuration update function |
|
|
| `FUN_CODE_12ea` (0x12EA) | `FUN_CODE_1000` (0x1000) | USB endpoint configuration |
|
|
| `FUN_CODE_0ddd` (0x0DDD) | `FUN_CODE_0ca4` (0x0CA4) | BCM4500 firmware loader |
|
|
| `FUN_CODE_2000` (0x2000) | `FUN_CODE_208d` (0x208D) | BCM4500 status polling |
|
|
| `FUN_CODE_1556` (0x1556) | `FUN_CODE_0eea` (0x0EEA) | I2C multi-byte transfer |
|
|
| `FUN_CODE_24d2` (0x24D2) | `FUN_CODE_243d` (0x243D) | SET_DVB_MODE config store |
|
|
| `FUN_CODE_2419` (0x2419) | `FUN_CODE_2357` (0x2357) | GET config byte to EP0BUF |
|
|
| `FUN_CODE_23cb` (0x23CB) | `FUN_CODE_2309` (0x2309) | Read descriptor byte to EP0BUF |
|
|
| `FUN_CODE_1a0e` (0x1A0E) | -- | v2.06 serial number reader (EEPROM) |
|
|
| `INT0_vec` (0x0003) | `INT0_vector` (0x0003) | INT0 interrupt handler (**significantly different**) |
|
|
| -- | `FUN_CODE_2239` (0x2239) | v2.13 I2C single-byte read helper |
|
|
| -- | `FUN_CODE_2031` (0x2031) | v2.13 USB reconnect function |
|
|
| -- | `FUN_CODE_1799` (0x1799) | v2.13 demod checksum/signature verify |
|
|
| -- | `FUN_CODE_1ca0` (0x1CA0) | v2.13 descriptor checksum verify |
|
|
| -- | `FUN_CODE_1ac6` (0x1AC6) | v2.13 tuning acquisition sequence |
|
|
| -- | `FUN_CODE_1e3c` (0x1E3C) | v2.13 demodulator full reset |
|
|
| -- | `FUN_CODE_10d9` (0x10D9) | v2.13 demod status polling/init |
|
|
| -- | `FUN_CODE_0dbc` (0x0DBC) | v2.13 I2C-based DiSEqC controller |
|
|
|
|
### USB Descriptor Setup (FUN_CODE_13c3 vs FUN_CODE_11ab)
|
|
|
|
Both functions are structurally identical:
|
|
1. Disable USB disconnect (0xE605 bit 1 clear)
|
|
2. Configure IFCONFIG (0xE600) for internal clock, 48MHz
|
|
3. Set REVCTL (0xE601) to 0xCA
|
|
4. Configure GPIFIDLECTL, PORTACFG
|
|
5. Set PORT registers (P0, P3, IPL1)
|
|
6. Configure GPIFCTLCFG, FIFORESET, FIFOPINPOLAR
|
|
7. Configure Timer2 (RCAP2H=0xF8, RCAP2L=0x2F -> ~2ms period at 48MHz/12)
|
|
8. Initialize subsystem modules
|
|
|
|
Key difference: v2.13 calls `INT0_vector()` (the INT0 handler) during initialization as a probing step. This runs the demodulator availability check during USB setup, before enabling interrupts. v2.06 does not do this.
|
|
|
|
Descriptor pointer offsets:
|
|
- v2.06: BANK1_R4:R5 = 0x1200 (descriptor base)
|
|
- v2.13: BANK1_R4:R5 = 0x0E00 (descriptor base, lower due to code restructuring)
|
|
|
|
---
|
|
|
|
## 3. Structural Differences
|
|
|
|
### 3.1 v2.13 Retry Loops (FUN_CODE_1799 and FUN_CODE_1ca0)
|
|
|
|
In the main init function `FUN_CODE_0800`, v2.13 has:
|
|
|
|
```c
|
|
// Retry loop 1: FUN_CODE_1799 - demodulator signature verification
|
|
DAT_INTMEM_36 = 0x14; // 20 attempts
|
|
while (DAT_INTMEM_36 != 0 && FUN_CODE_1799() fails) {
|
|
DAT_INTMEM_36--;
|
|
}
|
|
if (DAT_INTMEM_36 == 0) {
|
|
FUN_CODE_1ac6(100); // tuning acquisition with 100ms delay
|
|
}
|
|
|
|
// Retry loop 2: FUN_CODE_1ca0 - descriptor checksum verification
|
|
DAT_INTMEM_36 = 0x14; // 20 attempts
|
|
while (DAT_INTMEM_36 != 0 && FUN_CODE_1ca0() fails) {
|
|
DAT_INTMEM_36--;
|
|
}
|
|
if (DAT_INTMEM_36 == 0) {
|
|
FUN_CODE_1ac6(100); // tuning acquisition with 100ms delay
|
|
}
|
|
```
|
|
|
|
**FUN_CODE_1799 - Demodulator Signature Verification:**
|
|
1. Calls FUN_CODE_1d4b() which writes 4 bytes via I2C to device 0x7F, register 0xF0 (demodulator control)
|
|
2. Saves parameters DAT_INTMEM_39:3A
|
|
3. Checks if parameters match 0x021C (known good value) - returns early if match
|
|
4. Reads 5 I2C bytes via FUN_CODE_0718, each at register 0x0A offset (stepping by 2)
|
|
5. Subtracts 0x30 ('0') from each byte (ASCII to binary conversion)
|
|
6. Sums the values and compares sum to the saved parameters
|
|
7. Returns success (carry set) if checksum matches
|
|
|
|
This verifies the demodulator responds correctly with the expected identification pattern. The ASCII-to-binary conversion suggests the demod returns a readable version string at register 0x0A.
|
|
|
|
**FUN_CODE_1ca0 - Descriptor Checksum Verification:**
|
|
1. Iterates bytes 6 through 0x29 (36 bytes) of the BANK2_R6:R7 descriptor block
|
|
2. Computes running sum, compares against expected value 0x0706
|
|
3. If first block passes, iterates bytes 0x2C through 0x4F (36 bytes) of same block
|
|
4. Computes second running sum, compares against expected value 0x0686
|
|
5. Returns success only if both checksums match
|
|
|
|
This validates the integrity of a 2-block descriptor/configuration structure (possibly EEPROM-loaded calibration data).
|
|
|
|
**v2.06 equivalent:** v2.06 does NOT have these retry loops. It calls `FUN_CODE_1a0e` (serial number/EEPROM reader) directly without verification, then proceeds immediately. There is no signature check or checksum validation.
|
|
|
|
### 3.2 Version Byte Check (Hardware Revision Detection)
|
|
|
|
After the retry loops, v2.13 performs:
|
|
|
|
```c
|
|
// Read byte at descriptor_base + 10
|
|
byte version_byte = *(BANK1_R4:R5 + 10); // 0x0E0A
|
|
if (version_byte == 0x03) {
|
|
bVar4 = 0x80; // flag = set
|
|
} else {
|
|
bVar4 = 0; // flag = clear
|
|
}
|
|
_1_3 = bVar4 >> 7; // store as bit flag _1_3
|
|
```
|
|
|
|
This reads byte offset 10 from the USB descriptor base address. Offset 10 in a USB device descriptor is `bMaxPacketSize0` in standard USB, but since this is a custom descriptor area, it likely encodes a hardware revision. The value 0x03 sets bit flag `_1_3`, creating a hardware-revision-aware code path.
|
|
|
|
**Impact:** The `_1_3` flag is used elsewhere in v2.13 to conditionally execute different initialization sequences, supporting multiple hardware revisions of the SkyWalker-1 board.
|
|
|
|
### 3.3 FUN_CODE_2031 - USB Reconnect Before Main Loop
|
|
|
|
```c
|
|
void FUN_CODE_2031(void) {
|
|
if (_0_0 == 0) {
|
|
CPUCS |= 0x08; // Set CPUCS.3 (8051 reset bit? Or re-enumerate)
|
|
} else {
|
|
CPUCS |= 0x0A; // Set CPUCS.3 + CPUCS.1
|
|
}
|
|
FUN_CODE_14b9(5, 0xDC); // Delay ~1500 cycles
|
|
EPIRQ = 0xFF; // Clear all endpoint interrupts
|
|
USBIRQ = 0xFF; // Clear all USB interrupts
|
|
DAT_SFR_91 &= 0xEF; // Clear EXIF.4 (USB interrupt flag)
|
|
CPUCS &= 0xF7; // Clear CPUCS.3
|
|
}
|
|
```
|
|
|
|
This performs a controlled USB re-enumeration by pulsing CPUCS.3, then clearing all pending USB/endpoint interrupts. The conditional on `_0_0` adds CPUCS.1 when the flag is set (possibly switching between 12MHz and 48MHz operation).
|
|
|
|
**v2.06 equivalent:** In v2.06, this exact same logic exists as `INT0_vec` (the INT0 interrupt handler at 0x0003). The critical difference is that in v2.06 this code runs as an interrupt handler, while in v2.13 it's called as a normal function (`FUN_CODE_2031`) before the main loop starts, AND the INT0 vector is repurposed for demodulator polling (see section 4).
|
|
|
|
---
|
|
|
|
## 4. INT0 Handler Difference
|
|
|
|
### v2.06 INT0 (CODE:0003) - USB Re-enumeration
|
|
|
|
```c
|
|
void INT0_vec(void) {
|
|
if (_0_7 == 0) {
|
|
CPUCS |= 0x08; // CPUCS bit 3
|
|
} else {
|
|
CPUCS |= 0x0A; // CPUCS bits 3+1
|
|
}
|
|
FUN_CODE_1dfb(5, 0xDC); // Delay
|
|
EPIRQ = 0xFF; // Clear endpoint IRQs
|
|
USBIRQ = 0xFF; // Clear USB IRQs
|
|
DAT_SFR_91 &= 0xEF; // Clear external interrupt flag
|
|
CPUCS &= 0xF7; // Clear CPUCS bit 3
|
|
}
|
|
```
|
|
|
|
Simple USB reconnect/re-enumeration handler. Pulses CPUCS.3, clears all pending interrupts.
|
|
|
|
### v2.13 INT0 (CODE:0003) - Demodulator Availability Polling
|
|
|
|
```c
|
|
void INT0_vector(void) {
|
|
for (DAT_INTMEM_37 = 0x28; DAT_INTMEM_37 != 0; DAT_INTMEM_37--) {
|
|
// Read I2C device 0x7F (demod A), checking for response
|
|
byte result = FUN_CODE_2239(0x7F); // I2C read from 0x7F
|
|
if (result != 0x01) {
|
|
// Try I2C device 0x3F (demod B)
|
|
result = FUN_CODE_2239(0x3F); // I2C read from 0x3F
|
|
if (result != 0x01) break; // Neither responded normally
|
|
}
|
|
}
|
|
_1_4 = (DAT_INTMEM_37 == 0); // Set flag if loop exhausted (no demod found)
|
|
}
|
|
```
|
|
|
|
This is a complete replacement of INT0's purpose. Instead of USB re-enumeration, INT0 now polls two I2C devices (0x7F and 0x3F) up to 40 times (0x28). These are two possible addresses for the satellite demodulator IC.
|
|
|
|
**FUN_CODE_2239 decompiled:**
|
|
```c
|
|
undefined1 FUN_CODE_2239(byte device_addr) {
|
|
DAT_INTMEM_48 = 0xE1; // buffer address high
|
|
DAT_INTMEM_49 = 0; // buffer address low
|
|
FUN_CODE_0eea(1, device_addr, 0x51); // I2C read 1 byte from device
|
|
return DAT_EXTMEM_e100; // return the read byte
|
|
}
|
|
```
|
|
|
|
The function performs an I2C single-byte read from the specified device address, using address 0x51 as a parameter (likely selecting a specific I2C bus or mode via the FX2's auxiliary I2C controller at 0xE678). It stores the result at 0xE100 (XRAM buffer).
|
|
|
|
**Behavioral meaning:** The flag `_1_4` is set to 1 if neither demodulator responded after 40 attempts - indicating no demodulator hardware is present. This flag is later checked by:
|
|
- `FUN_CODE_21d1` (command 0x9D handler) - skips demodulator reset if `_1_4 != 1`
|
|
- Various initialization paths to avoid hanging on missing hardware
|
|
|
|
**Why this matters:** v2.06 assumes the demodulator is always present. v2.13 can detect and gracefully handle boards where the demodulator is absent or unresponsive, making it more robust for manufacturing QC and field failures.
|
|
|
|
---
|
|
|
|
## 5. What Can v2.13 Do That v2.06 Cannot?
|
|
|
|
### 5.1 Demodulator Hardware Detection
|
|
v2.13 probes two I2C addresses (0x7F, 0x3F) at startup to determine which demodulator variant is installed, or if none is present. v2.06 blindly assumes the hardware configuration.
|
|
|
|
### 5.2 Host-Initiated Demodulator Re-initialization (Command 0x9A)
|
|
The host can trigger a demodulator re-initialization via USB vendor command 0x9A, with up to 3 retry attempts. v2.06 has no mechanism for the host to request re-initialization.
|
|
|
|
### 5.3 Demodulator Status Read (Command 0x99)
|
|
Direct I2C register read of demodulator register 0xF9, returned to host. This enables diagnostic/monitoring software to check demodulator status without going through the full signal quality pipeline.
|
|
|
|
### 5.4 Host-Controlled Tuning Delay (Command 0x9C)
|
|
Allows the host to invoke the tuning acquisition sequence with a configurable delay parameter. In v2.06, the tuning timing is entirely firmware-controlled with no host influence.
|
|
|
|
### 5.5 I2C-Based DiSEqC Control
|
|
v2.13 uses a dedicated I2C-connected DiSEqC controller chip rather than GPIO bit-banging:
|
|
- More precise DiSEqC timing (hardware-generated rather than software-timed)
|
|
- Support for reading DiSEqC reply messages (the I2C controller can buffer responses)
|
|
- Lower CPU overhead during DiSEqC transactions
|
|
- Better compatibility with DiSEqC 1.2 motor positioning commands that require precise timing
|
|
|
|
### 5.6 Firmware/Descriptor Integrity Verification
|
|
v2.13 validates demodulator identification (ASCII version string checksum) and descriptor block integrity (two 36-byte checksums) before proceeding. If verification fails after 20 attempts, it falls back to a recovery sequence. v2.06 does no integrity checking.
|
|
|
|
### 5.7 Hardware Revision Awareness
|
|
The version byte check (descriptor offset 10, value 0x03) creates conditional code paths allowing a single firmware image to support multiple SkyWalker-1 hardware revisions. v2.06 has a single code path for one hardware revision.
|
|
|
|
### 5.8 Simplified BCM4500 Status Polling
|
|
v2.06's `FUN_CODE_2000` polls three separate BCM4500 registers (0xA2, 0xA8, 0xA4 via I2C) to determine demodulator readiness. v2.13's `FUN_CODE_208d` polls only one register (0xA4), suggesting either the demodulator firmware was updated to consolidate status, or the additional checks were found to be redundant.
|
|
|
|
### 5.9 Conditional Demodulator Reset (Command 0x9D)
|
|
v2.13's 0x9D handler can trigger a full demodulator reset sequence (FUN_CODE_1e3c -> register writes to 0x18 bus) controlled by the host via wValue. This is useful for error recovery without full device re-enumeration.
|
|
|
|
---
|
|
|
|
## 6. Architecture Summary
|
|
|
|
| Aspect | v2.06 | v2.13 |
|
|
|--------|-------|-------|
|
|
| Total functions | 61 | 82 (+21) |
|
|
| RESET vector | 0x188D | 0x170D |
|
|
| Stack pointer | 0x72 | 0x50 |
|
|
| Init data table | CODE:0B46 | CODE:0B88 |
|
|
| Descriptor base | 0x1200 | 0x0E00 |
|
|
| Config byte (IRAM) | 0x6D | 0x4F |
|
|
| INT0 purpose | USB re-enumerate | Demod probe |
|
|
| DiSEqC method | GPIO bit-bang | I2C controller |
|
|
| Demod init | Direct, no retry | 20-attempt retry |
|
|
| Integrity checks | None | Checksum verification |
|
|
| HW revision support | Single | Multi-revision (flag _1_3) |
|
|
| New vendor cmds | -- | 0x99, 0x9A, 0x9C |
|