diff --git a/include/modem.h b/include/modem.h index 425717c..886cff3 100644 --- a/include/modem.h +++ b/include/modem.h @@ -340,3 +340,105 @@ static inline int zebra_recv_ready(zebra_pulse_t *z, uint32_t sink, int timeout_ms) { return zebra_recv_hs_frame(z, sink, timeout_ms, ZEBRA_HS_TYPE_READY, NULL); } +/* ------------------------------------------------------------------ * + * BATTLE TOADS: dual-channel stereo UART * + * * + * One stereo tab → L and R modulated independently. * + * Both channels use same UART framing and baud rate. * + * TX sends byte_L and byte_R simultaneously each frame. * + * RX decodes both channels from a single PA poll per half-symbol. * + * Net throughput: 2x single-channel at same baud rate. * + * ------------------------------------------------------------------ */ + +/* Send one dual-channel symbol: L=bit_l, R=bit_r */ +static inline void bt_send_symbol(zebra_pulse_t *z, uint32_t sink, + int bit_l, int bit_r, + struct timespec *next, long period_ns) { + zebra_set_volume_lr_noack(z, sink, + zebra_bit_to_vol(bit_l), + zebra_bit_to_vol(bit_r)); + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, next, NULL); + ts_add_ns(next, period_ns); +} + +/* Send two bytes simultaneously: byte_l on L channel, byte_r on R channel. + * Frame: start(0,0) + 8 paired data bits + stop(1,1) = 10 symbols. */ +static inline void bt_send_byte_lr(zebra_pulse_t *z, uint32_t sink, + uint8_t byte_l, uint8_t byte_r, + struct timespec *next, long period_ns) { + bt_send_symbol(z, sink, 0, 0, next, period_ns); /* start */ + for (int i = 0; i < 8; i++) + bt_send_symbol(z, sink, + (byte_l >> i) & 1, + (byte_r >> i) & 1, + next, period_ns); + bt_send_symbol(z, sink, 1, 1, next, period_ns); /* stop */ +} + +/* Receive loop: decodes L and R channels from each PA poll. + * Calls cb twice per frame — first with L byte, then R byte. + * Output order: L0, R0, L1, R1, ... matching bt_send_byte_lr pairs. */ +static inline void bt_rx_run(zebra_pulse_t *z, uint32_t sink, int baud, + zebra_byte_cb cb, void *userdata) { + const int oversample = 4; + long quarter_ns = 1000000000L / ((long)baud * oversample); + long half_ns = 2 * quarter_ns; + long full_ns = 4 * quarter_ns; + + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + int prev_l = 1, prev_r = 1; /* both idle at MARK */ + + for (;;) { + ts_add_ns(&ts, quarter_ns); + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); + + uint8_t vol_l, vol_r; + if (zebra_get_volume_lr(z, sink, &vol_l, &vol_r) < 0) { + struct timespec retry = {1, 0}; + nanosleep(&retry, NULL); + prev_l = prev_r = 1; + continue; + } + + int cur_l = zebra_vol_to_bit(vol_l); + int cur_r = zebra_vol_to_bit(vol_r); + + /* start bit: detect falling edge on L (TX sends both low together) */ + if (prev_l == 1 && cur_l == 0) { + /* confirm start at center */ + ts_add_ns(&ts, half_ns); + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); + if (zebra_get_volume_lr(z, sink, &vol_l, &vol_r) < 0) + { prev_l = prev_r = 1; continue; } + if (zebra_vol_to_bit(vol_l) != 0) + { prev_l = prev_r = 1; continue; } + + /* decode 8 paired data bits */ + uint8_t byte_l = 0, byte_r = 0; + int ok = 1; + for (int i = 0; i < 8; i++) { + ts_add_ns(&ts, full_ns); + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); + if (zebra_get_volume_lr(z, sink, &vol_l, &vol_r) < 0) + { ok = 0; break; } + int bl = zebra_vol_to_bit(vol_l); + int br = zebra_vol_to_bit(vol_r); + if (bl < 0) bl = (vol_l >= ZEBRA_VOL_THRESHOLD) ? 1 : 0; + if (br < 0) br = (vol_r >= ZEBRA_VOL_THRESHOLD) ? 1 : 0; + byte_l |= (uint8_t)(bl << i); + byte_r |= (uint8_t)(br << i); + } + if (ok) { + cb(byte_l, userdata); + cb(byte_r, userdata); + } + /* Resync sample clock after each frame — same fix as zebra_rx_run */ + clock_gettime(CLOCK_MONOTONIC, &ts); + prev_l = prev_r = 1; + } else { + if (cur_l >= 0) prev_l = cur_l; + if (cur_r >= 0) prev_r = cur_r; + } + } +} diff --git a/web/fonts/chunkfive-regular-webfont.woff b/web/fonts/chunkfive-regular-webfont.woff new file mode 100644 index 0000000..54ced00 Binary files /dev/null and b/web/fonts/chunkfive-regular-webfont.woff differ diff --git a/web/fonts/chunkfive-regular-webfont.woff2 b/web/fonts/chunkfive-regular-webfont.woff2 new file mode 100644 index 0000000..7cecf49 Binary files /dev/null and b/web/fonts/chunkfive-regular-webfont.woff2 differ