Send CAMs under the phone's position vector, not bench placeholders
Every field of the GeoNetworking Source Position Vector this firmware sent was a compile-time constant: the bench coordinates, speed 0, heading 0, TST 0, station type passengerCar and one fixed MAC. The CAM inside described a moving cyclist while the GN header around it described a car parked at the bench. SERIAL_MSG_CAM_TX_PV (0x05) puts a 24-byte prefix ahead of the CAM UPER: MAC, station type, PAI, TST, latitude, longitude, speed and heading, all values the phone already has when it builds the CAM and none of which this chip can know. geonet_wrap_shb now takes them as a gn_lpv_t, and tx_radio_task hands the same MAC to dot11p_build_frame, so the 802.11 source address and the GN_ADDR MID stay one address across a pseudonym change. Speed is clamped rather than masked, since an overflowing 15-bit value flips its sign bit and reads as travelling backwards. This reverses the Phase 03 decision that the firmware owns the pseudonym. A pseudonym only protects anyone if the MAC, the GN_ADDR and the CAM's stationID change together, and the phone owns the stationID. The heartbeat gains a capability byte (payload[7], bit0 = CAM_TX_PV), appended so an app reading the first 7 bytes is unaffected. The app sends 0x05 only once it sees that bit, so app and firmware can be updated in either order. CAM_TX (0x01) is still handled and falls back to the bench values, with the station type corrected to cyclist to match the CAM. Verified on air from the COM10 test board, decoded independently by the CiT One's gnHeader: 24 of 24 CAM_TX_PV frames matched the sent position vector field by field, and so did the CAM station ID. The legacy path delivered 23 of 24 frames with no field mismatches. Flashed on the COM3 OBU and its boot log is clean. Also corrects the SERIAL_LINK_MAX_PAYLOAD comment, which still named the 400-byte receive capture buffer as the ceiling on the RX path. That buffer is 800 bytes now, so the serial link is the ceiling, and larger payloads are dropped and counted there.
This commit is contained in:
@@ -49,20 +49,52 @@
|
||||
// message's own ItsPduHeader.stationID is the meaningful identifier.
|
||||
// SERIAL_MSG_STATUS (0x03), ESP32 -> phone: heartbeat + counters, sent at 1 Hz so the phone can
|
||||
// distinguish "link idle" from "link dead" independent of CAM traffic (the app's watchdog in
|
||||
// UsbSerialTransport.kt declares the link dead after 3 missed beats). Payload is 7 bytes:
|
||||
// [status:1][oversize_drops:2 LE][tx_failures:2 LE][rx_crc_errors:2 LE]
|
||||
// UsbSerialTransport.kt declares the link dead after 3 missed beats). Payload is 8 bytes:
|
||||
// [status:1][oversize_drops:2 LE][tx_failures:2 LE][rx_crc_errors:2 LE][capabilities:1]
|
||||
// status 0 = ok. The counters are free-running totals since boot, saturating at 0xFFFF.
|
||||
// capabilities is a bitmask of the SERIAL_CAP_* flags below. It was appended as byte 7 rather
|
||||
// than inserted, so an app that predates it, and reads only the first 7 bytes, is unaffected.
|
||||
// They exist because the alternative - ESP_LOGW on the flashing port - is invisible to the
|
||||
// phone, which is the only thing watching during a bench session. Mirrored by EspLinkStatus
|
||||
// in the app's SerialFrame.kt.
|
||||
#define SERIAL_MSG_CAM_TX 0x01
|
||||
#define SERIAL_MSG_CAM_RX 0x02
|
||||
#define SERIAL_MSG_STATUS 0x03
|
||||
#define SERIAL_MSG_V2X_RX 0x04
|
||||
#define SERIAL_MSG_CAM_TX 0x01
|
||||
#define SERIAL_MSG_CAM_RX 0x02
|
||||
#define SERIAL_MSG_STATUS 0x03
|
||||
#define SERIAL_MSG_V2X_RX 0x04
|
||||
#define SERIAL_MSG_CAM_TX_PV 0x05
|
||||
|
||||
// Size of the V2X_RX prefix documented above. Must match the app's SerialFrame.kt.
|
||||
#define SERIAL_V2X_RX_PREFIX_LEN 14
|
||||
|
||||
// SERIAL_MSG_CAM_TX_PV (0x05), phone -> ESP32: a CAM together with the GeoNetworking Source
|
||||
// Position Vector to transmit it under. Payload is a fixed 24-byte prefix, then the CAM UPER:
|
||||
//
|
||||
// [0..5] mac 6 bytes pseudonym: the 802.11 source address AND the GN_ADDR MID
|
||||
// [6] station_type uint8 TS 102 894-2 StationType (2 = cyclist)
|
||||
// [7] flags uint8 bit0: PAI, position accuracy indicator
|
||||
// [8..11] tst uint32 LE ms at which lat/lon were acquired, TimestampIts mod 2^32
|
||||
// [12..15] lat int32 LE 1/10 microdegree
|
||||
// [16..19] lon int32 LE 1/10 microdegree
|
||||
// [20..21] speed int16 LE 0.01 m/s
|
||||
// [22..23] heading uint16 LE 0.1 degree from north, clockwise, 0..3599
|
||||
// [24..] CAM UPER bytes
|
||||
//
|
||||
// Little-endian like the rest of this framing; geonet.c converts to GeoNetworking's big-endian.
|
||||
// Every prefix field is something the phone already has when it builds the CAM, and none of it
|
||||
// can be known on this chip, which has no GNSS and no clock source on the OCB channel. Before
|
||||
// this message existed the GN header carried fixed placeholders instead (see main.c).
|
||||
//
|
||||
// A new type rather than a redefined CAM_TX, so app and firmware can be updated independently:
|
||||
// - old app, new firmware: the app sends CAM_TX, which is handled exactly as before.
|
||||
// - new app, old firmware: the app sends CAM_TX_PV only once the heartbeat advertises
|
||||
// SERIAL_CAP_CAM_TX_PV, and an old heartbeat carries no such bit, so it stays on CAM_TX.
|
||||
// Redefining CAM_TX would instead have double-wrapped every frame in one of those combinations
|
||||
// and sent one with no GN header in the other, silently, since neither side checks versions.
|
||||
#define SERIAL_CAM_TX_PV_PREFIX_LEN 24
|
||||
|
||||
// Capability bits, carried in byte 7 of the SERIAL_MSG_STATUS payload.
|
||||
#define SERIAL_CAP_CAM_TX_PV 0x01
|
||||
|
||||
// USB Serial/JTAG has no baud rate or GPIO pins to configure - it's a fixed on-chip USB device
|
||||
// controller wired directly to the native USB-C port's D+/D- lines in silicon. RX/TX buffer
|
||||
// sizes for usb_serial_jtag_driver_install() (see serial_link.c) are sized generously relative
|
||||
@@ -83,16 +115,25 @@
|
||||
// Raised from 160 to 512: 160 was reasoned from cam.c's 96-byte encode buffer, which only ever
|
||||
// described OUR OWN minimal CAM. A third-party CAM off the air carrying a path-history or
|
||||
// special-vehicle container comfortably exceeds it, and those stations would then never reach the
|
||||
// phone at all. 512 clears any realistic CAM; the real upstream ceiling on the RX path is
|
||||
// rx_item_t.data (400 bytes) in main.c, so nothing larger can get here anyway.
|
||||
// phone at all. 512 clears any realistic CAM. Our own CAM is 43 bytes of UPER.
|
||||
//
|
||||
// This, not the radio side, is the ceiling on the RX path. main.c captures up to RX_FRAME_MAX_LEN
|
||||
// (800) bytes per frame, sized for the CiT One's 528-byte DENM, so a larger ITS payload
|
||||
// does arrive here. serial_link_send_v2x_rx() then drops anything above this minus its 14-byte
|
||||
// prefix and counts it in the heartbeat's oversize-drop counter.
|
||||
#define SERIAL_LINK_MAX_PAYLOAD 512
|
||||
|
||||
// Initializes the USB Serial/JTAG driver and its background RX-framing and 1 Hz heartbeat tasks.
|
||||
// Call once from app_main, after nvs/event loop init. `on_cam_tx` is invoked (from the RX task's
|
||||
// context - keep it fast, it blocks the next frame's parsing) whenever a complete, checksummed
|
||||
// SERIAL_MSG_CAM_TX frame arrives from the phone.
|
||||
// Call once from app_main, after nvs/event loop init. Both callbacks run in the RX task's context,
|
||||
// so keep them fast: they block the next frame's parsing.
|
||||
// on_cam_tx a complete, checksummed SERIAL_MSG_CAM_TX frame: bare CAM UPER.
|
||||
// on_cam_tx_pv a complete, checksummed SERIAL_MSG_CAM_TX_PV frame, already checked to carry at
|
||||
// least one CAM byte after its prefix: the 24-byte prefix, then the CAM UPER.
|
||||
typedef void (*serial_link_cam_tx_cb_t)(const uint8_t *cam_uper, int cam_len);
|
||||
void serial_link_init(serial_link_cam_tx_cb_t on_cam_tx);
|
||||
typedef void (*serial_link_cam_tx_pv_cb_t)(const uint8_t *prefix,
|
||||
const uint8_t *cam_uper, int cam_len);
|
||||
void serial_link_init(serial_link_cam_tx_cb_t on_cam_tx,
|
||||
serial_link_cam_tx_pv_cb_t on_cam_tx_pv);
|
||||
|
||||
// Sends a SERIAL_MSG_V2X_RX frame: the metadata prefix plus the UPER bytes gn_unwrap.c extracted
|
||||
// from an over-the-air frame. Pass has_geo_area=false and zeroes for the area fields when the
|
||||
|
||||
Reference in New Issue
Block a user