Files
MicrOBU/obu-cam-transmistter/main/geonet.h
T
Ashin Walpola f507a8a9fd Fix UPER encoding of CurvatureCalculationMode; verified on hardware
CurvatureCalculationMode is the one extensible ENUMERATED in CAM:
  ENUMERATED {yawRateUsed(0), yawRateNotUsed(1), unavailable(2), ...}
UPER encodes an extensible ENUMERATED as an extension bit followed by the root
index - 1 + 2 = 3 bits. All three of our encoders wrote only the 2-bit index,
shifting yawRate and the entire low-frequency container one bit early for any
standards-compliant receiver.

It went unnoticed because every end of this project shared the mistake: the
Kotlin codec was ported bit-for-bit from cam.c, so phone and ESP32 agreed
perfectly with each other and with nothing else. Confirmed against the ETSI
ASN.1 in the C-ITS-Parser checkout, where rasn marks this type - and only this
type - #[non_exhaustive].

Fixed in all three copies of the encoder (app CamUperCodec.kt,
obu-firmware/main/cam.c, obu-cam-transmistter/main/cam.c) plus the decoder,
which now rejects rather than misreads a set extension bit. Frame size is
unchanged at 43 bytes. Transmitter reflashed and the phone decodes its CAMs.

Also in this change:

- serial_link: skip send_frame entirely when no USB host is attached, and raise
  the tx mutex timeout above the worst-case hold. With the phone unplugged every
  write blocked its full timeout while holding the lock, so forwarded CAM_RX
  traffic starved the 1 Hz heartbeat - observed as "tx mutex timeout, dropping
  frame" on the console, and it would have tripped the phone's link watchdog.
  Verified gone on hardware.
- Log decoded and failed CAMs in CamUseCaseRepository. "The app shows nothing"
  had two indistinguishable causes; a silent `?: return` made this bug much
  harder to find than it needed to be.
- Remove the ESP32 send-only/send-and-receive toggle. Reception can't be
  disabled in firmware (raw TX only works while promiscuous), so it was an
  app-side filter pretending to be a radio control.
- V2X monitor follows the serial link state on the ESP32 path instead of MQTT,
  which is permanently disconnected there; CAM intake is gated on the link being
  up, and engine state is cleared when it drops.
- About screen: 0.5.0, Phase 03.
- Track obu-cam-transmistter, the bench CAM transmitter. Its cam.c is compiled
  (unlike obu-firmware's reference copy) and must stay bit-identical to the other
  two - this commit is what that coupling costs when it's broken.
- Document the two-toolchain split: this project builds on IDF 5.5.4, obu-firmware
  on the pinned 6.1. Exporting both in one shell fails confusingly.
2026-08-11 14:50:35 +02:00

45 lines
2.2 KiB
C

#ifndef GEONET_H
#define GEONET_H
#include <stdint.h>
#include <stddef.h>
// Wraps an ITS application payload (e.g. from denm_encode) with a minimal
// GeoNetworking Basic Header + Common Header + Single-Hop-Broadcast
// extended header (HeaderType=TSB(5), HeaderSubtype=SINGLE_HOP(0), per
// ETSI EN 302 636-4-1 table 9), then prepends a BTP-B header addressed to
// the DENM service port (2002).
//
// `mac` is the 6-byte pseudonym/link-layer address - pass the SAME address
// you hand to dot11p_build_frame's src address, since GN_ADDR's MID field
// (the last 6 bytes of the 8-byte GN_ADDR) is defined to BE that
// link-layer address (EN 302 636-4-1 clause 9.5.1). `station_type` is the
// 5-bit ITS-S type from the same clause (5 = passengerCar) and gets packed
// into GN_ADDR alongside the address.
//
// `latitude_tenmicrodeg`/`longitude_tenmicrodeg` go into the Source Long
// Position Vector (clause 9.5.2) as plain 32-bit signed big-endian fields -
// NOT UPER bit-packed like the DENM payload's position fields, this is a
// fixed-width binary protocol. Pass the SAME values you gave denm_encode's
// eventPosition, so the GN-layer position and the DENM's own claimed
// position agree.
//
// Deliberate simplification: real DENM dissemination normally uses
// GeoBroadcast (GBC, HeaderType=4) so RSUs/OBUs can forward it across an
// area - that needs a sequence number + geo-area fields this skeleton
// doesn't build yet. Single-hop broadcast is simpler and is the
// best-tested decode path in the receiver firmware you already have
// working (same extended header shape as CAM). Fine for a single-vehicle
// beacon; revisit if you need real multi-hop forwarding later.
//
// `btp_dest_port` is the BTP-B destination port for the service being carried
// (ETSI TS 103 248): 2001 = CAM, 2002 = DENM, 2003 = MAPEM, 2004 = SPATEM, ...
//
// Returns bytes written, or -1 if out buffer too small.
int geonet_wrap_shb(const uint8_t *its_payload, int its_len,
const uint8_t mac[6], uint8_t station_type,
int32_t latitude_tenmicrodeg, int32_t longitude_tenmicrodeg,
uint16_t btp_dest_port,
uint8_t *out, size_t out_len);
#endif