Fix remaining safety review findings: DiSEqC timeout, hotplug, watchdog status
Addresses all remaining Apollo review items: - C-3: DiSEqC Timer2 spin loops now have timeout protection via diseqc_wait_ticks() with per-tick I2C_TIMEOUT countdown. Tone burst refactored to use the shared helper instead of bare while(!TF2) loops. New ERR_DISEQC_TIMER (0x0C) error code on Timer2 failure. - I-3: Hotplug scan hp_prev copy moved from start to end of scan. Aborted scans no longer corrupt the previous-good baseline, preventing false "removed" events on consecutive scan failures. - S-1: Watchdog-fired detection in main loop — when wdt_armed==2 (ISR fired), sets ERR_WDT_FIRED (0x0D) readable via 0xBC and clears BM_STARTED|BM_FW_LOADED|BM_ARMED so host sees system is down. - I-2: Comment explaining (WORD)sd_poll_count cast as SDCC optimization. - I-1: CKCON bit ownership comment in diseqc_tone_burst() Timer2 setup. Code: 13,079 / 15,360 bytes (85%). XRAM: 218 / 512. Stack: 132 bytes.
This commit is contained in:
parent
834c2bd9ee
commit
aecad367a0
@ -80,6 +80,8 @@
|
|||||||
#define ERR_EP2_TIMEOUT 0x09
|
#define ERR_EP2_TIMEOUT 0x09
|
||||||
#define ERR_NOT_SUPPORTED 0x0A
|
#define ERR_NOT_SUPPORTED 0x0A
|
||||||
#define ERR_DISEQC_LEN 0x0B
|
#define ERR_DISEQC_LEN 0x0B
|
||||||
|
#define ERR_DISEQC_TIMER 0x0C
|
||||||
|
#define ERR_WDT_FIRED 0x0D
|
||||||
|
|
||||||
/* configuration status byte bits */
|
/* configuration status byte bits */
|
||||||
#define BM_STARTED 0x01
|
#define BM_STARTED 0x01
|
||||||
@ -586,13 +588,8 @@ static void bcm4500_shutdown(void) {
|
|||||||
static void i2c_hotplug_scan(void) {
|
static void i2c_hotplug_scan(void) {
|
||||||
static __xdata BYTE hp_a, hp_byte, hp_bit, hp_diff;
|
static __xdata BYTE hp_a, hp_byte, hp_bit, hp_diff;
|
||||||
|
|
||||||
/* Save current as previous before starting new scan.
|
/* Clear current scan buffer (hp_prev retains last SUCCESSFUL scan
|
||||||
* This keeps hp_prev valid between scans so the host can read
|
* so aborted scans don't corrupt the comparison baseline) */
|
||||||
* both bitmaps and see the actual transition. */
|
|
||||||
for (hp_a = 0; hp_a < 16; hp_a++)
|
|
||||||
hp_prev[hp_a] = hp_curr[hp_a];
|
|
||||||
|
|
||||||
/* Clear current scan buffer */
|
|
||||||
for (hp_a = 0; hp_a < 16; hp_a++)
|
for (hp_a = 0; hp_a < 16; hp_a++)
|
||||||
hp_curr[hp_a] = 0;
|
hp_curr[hp_a] = 0;
|
||||||
|
|
||||||
@ -641,6 +638,12 @@ static void i2c_hotplug_scan(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Snapshot successful scan as baseline for next comparison.
|
||||||
|
* Done after comparison so hp_prev always reflects the last
|
||||||
|
* fully-completed scan, not a partial abort. */
|
||||||
|
for (hp_a = 0; hp_a < 16; hp_a++)
|
||||||
|
hp_prev[hp_a] = hp_curr[hp_a];
|
||||||
|
|
||||||
hp_scan_ok = 1;
|
hp_scan_ok = 1;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -677,6 +680,8 @@ static void stream_diag_poll(void) {
|
|||||||
|
|
||||||
/* Rate-limited BCM4500 I2C reads for sync tracking.
|
/* Rate-limited BCM4500 I2C reads for sync tracking.
|
||||||
* Only attempt if BCM is booted and interval elapsed. */
|
* Only attempt if BCM is booted and interval elapsed. */
|
||||||
|
/* (WORD) cast: SDCC optimization — avoids 32-bit AND. The 12-bit
|
||||||
|
* mask (0x0FFF) only needs the low 16 bits, so the cast is safe. */
|
||||||
if ((config_status & BM_FW_LOADED) &&
|
if ((config_status & BM_FW_LOADED) &&
|
||||||
((WORD)sd_poll_count & (SD_I2C_INTERVAL - 1)) == 0) {
|
((WORD)sd_poll_count & (SD_I2C_INTERVAL - 1)) == 0) {
|
||||||
sd_rd[0] = 0;
|
sd_rd[0] = 0;
|
||||||
@ -781,6 +786,10 @@ static void gpif_stop(void) {
|
|||||||
IOD |= 0xE0;
|
IOD |= 0xE0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward declaration: diseqc_wait_ticks() is defined in the Manchester
|
||||||
|
* encoder section but used by diseqc_tone_burst() above it. */
|
||||||
|
static void diseqc_wait_ticks(BYTE count);
|
||||||
|
|
||||||
/* ---------- DiSEqC tone burst ---------- */
|
/* ---------- DiSEqC tone burst ---------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -791,45 +800,31 @@ static void gpif_stop(void) {
|
|||||||
* Uses Timer2 for timing as the stock firmware does.
|
* Uses Timer2 for timing as the stock firmware does.
|
||||||
*/
|
*/
|
||||||
static void diseqc_tone_burst(BYTE sat_b) {
|
static void diseqc_tone_burst(BYTE sat_b) {
|
||||||
BYTE i;
|
|
||||||
|
|
||||||
if (sat_b) { last_error = ERR_NOT_SUPPORTED; return; }
|
if (sat_b) { last_error = ERR_NOT_SUPPORTED; return; }
|
||||||
|
|
||||||
/* Configure Timer2 auto-reload */
|
/* Configure Timer2 auto-reload.
|
||||||
/* CKCON.T2M = 0 -> Timer2 clk = 48MHz/12 = 4MHz */
|
* CKCON bit 5 (T2M) only — do not touch bit 3 (Timer0/watchdog). */
|
||||||
CKCON &= ~0x20;
|
CKCON &= ~0x20;
|
||||||
T2CON = 0x04; /* auto-reload, running */
|
T2CON = 0x04; /* auto-reload, running */
|
||||||
RCAP2H = 0xF8;
|
RCAP2H = 0xF8;
|
||||||
RCAP2L = 0x2F; /* reload = 63535 -> ~500us tick */
|
RCAP2L = 0x2F; /* reload = 63535 -> ~500us tick */
|
||||||
TL2 = 0xFF;
|
TL2 = 0xFF;
|
||||||
TH2 = 0xFF; /* force immediate overflow */
|
TH2 = 0xFF; /* force immediate overflow */
|
||||||
|
TF2 = 0;
|
||||||
|
|
||||||
/* Pre-burst settling: 15 ticks (~7.5ms) with carrier off */
|
/* Pre-burst settling: 15 ticks (~7.5ms) with carrier off */
|
||||||
IOA &= ~PIN_22KHZ;
|
IOA &= ~PIN_22KHZ;
|
||||||
TF2 = 0;
|
diseqc_wait_ticks(15);
|
||||||
for (i = 0; i < 15; i++) {
|
|
||||||
while (!TF2)
|
|
||||||
;
|
|
||||||
TF2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Burst: 25 ticks (~12.5ms) with carrier on */
|
/* Burst: 25 ticks (~12.5ms) with carrier on */
|
||||||
IOA |= PIN_22KHZ;
|
IOA |= PIN_22KHZ;
|
||||||
for (i = 0; i < 25; i++) {
|
diseqc_wait_ticks(25);
|
||||||
while (!TF2)
|
|
||||||
;
|
|
||||||
TF2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Carrier off */
|
/* Carrier off */
|
||||||
IOA &= ~PIN_22KHZ;
|
IOA &= ~PIN_22KHZ;
|
||||||
|
|
||||||
/* Post-burst settling: 5 ticks (~2.5ms) */
|
/* Post-burst settling: 5 ticks (~2.5ms) */
|
||||||
for (i = 0; i < 5; i++) {
|
diseqc_wait_ticks(5);
|
||||||
while (!TF2)
|
|
||||||
;
|
|
||||||
TF2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop Timer2 */
|
/* Stop Timer2 */
|
||||||
TR2 = 0;
|
TR2 = 0;
|
||||||
@ -853,9 +848,15 @@ static void diseqc_tone_burst(BYTE sat_b) {
|
|||||||
|
|
||||||
static void diseqc_wait_ticks(BYTE count) {
|
static void diseqc_wait_ticks(BYTE count) {
|
||||||
static __xdata BYTE dt_i;
|
static __xdata BYTE dt_i;
|
||||||
|
WORD dt_timeout;
|
||||||
for (dt_i = 0; dt_i < count; dt_i++) {
|
for (dt_i = 0; dt_i < count; dt_i++) {
|
||||||
while (!TF2)
|
dt_timeout = I2C_TIMEOUT;
|
||||||
;
|
while (!TF2) {
|
||||||
|
if (--dt_timeout == 0) {
|
||||||
|
last_error = ERR_DISEQC_TIMER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
TF2 = 0;
|
TF2 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2210,6 +2211,15 @@ void main(void) {
|
|||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
wdt_kick(); /* main loop alive — reset watchdog */
|
wdt_kick(); /* main loop alive — reset watchdog */
|
||||||
|
|
||||||
|
/* If watchdog fired while we were blocked in a vendor command,
|
||||||
|
* acknowledge it: set error code so host can read via 0xBC,
|
||||||
|
* and clear config flags so stale state doesn't cause confusion. */
|
||||||
|
if (wdt_armed == 2) {
|
||||||
|
last_error = ERR_WDT_FIRED;
|
||||||
|
config_status &= ~(BM_STARTED | BM_FW_LOADED | BM_ARMED);
|
||||||
|
wdt_armed = 0; /* acknowledged — host must re-boot to recover */
|
||||||
|
}
|
||||||
|
|
||||||
if (got_sud) {
|
if (got_sud) {
|
||||||
handle_setupdata();
|
handle_setupdata();
|
||||||
got_sud = FALSE;
|
got_sud = FALSE;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user