Drive the ESP32-C5 station over USB or BLE, send CAM or VAM, signed or not
The app now speaks the station-link protocol of the new obu-firmware. Esp32Link picks the transport from Settings (UsbSerialTransport or the new BleLinkTransport), tells the previous firmware from the new one by its heartbeat, and runs the session: STATION_CONFIGURE with the current pseudonym MAC (which also starts the board's radio), CREDENTIALS_PROVISION of the bundled demo chain when the board has no ticket, then per message a POTI_UPDATE and a BTP_DATA_REQUEST. Received messages still arrive as V2X_RX frames, so the receive side is unchanged. A board on the previous firmware keeps working for CAM over USB. Settings > Connection > ESP32-C5: link USB-C or Bluetooth, transmit CAM or VAM, "Sign outgoing messages" (on by default). The connection card, top bar and dashboard show the link in use, the pairing passkey and signing counters. - VAM: VamUperCodec (TS 103 300-3 V2.3.1, bytes checked against asn1tools) and VamGenerationRules (clause 6.4, Tables 16/17). - BLE: the firmware's GATT layout (service 0000C175-...), MTU 517, pairing and encryption settled before any other operation (short timeouts during pairing made it loop), backoff between attempts, reasons on the card. - Clock: a PoTi goes to the board once per new fix and never moves the board's clock backwards except for a real correction (>= 60 s); stale and wobbling fix times made the board answer time_regression and restart its stack every few seconds. GnssTimeSource keeps the last measured phone-clock error while GNSS time drops out indoors: the bench phone is 14 minutes fast, and falling back to it made every transmitted timestamp jump by that much. - assets/demo-chain.vcr: throwaway, not EU-registered demo chain generated 2026-09-23 (AT B80B49387A4C12EB, psid 36 and 638). Its private key ships with the app on purpose; receivers verifying against the EU trust list drop what it signs. - Bluetooth permissions requested at start-up on Android 12+. StationLinkTest pins the codec to bytes from the colleague's Python implementation (microbu_link/messages.py). 103 unit tests pass.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
package com.hawhamburg.micr0bu
|
||||
|
||||
import com.hawhamburg.micr0bu.domain.asn1.VamContent
|
||||
import com.hawhamburg.micr0bu.domain.asn1.VamUperCodec
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Pins the VAM encoder against bytes this code did not produce.
|
||||
*
|
||||
* ## Where the expected bytes come from
|
||||
* asn1tools 0.167, compiling the ETSI modules vanetza-idf ships (asn1/release2:
|
||||
* TS102894-2v241-CDD.asn, TS103300-3v231/VAM-PDU-Descriptions.asn and its motorcyclist container),
|
||||
* encoding the same values as a Python dict: the same toolchain the colleague's reference VBS
|
||||
* (microbu-esp32c5/station-link/python/microbu_link/vbs.py) builds its VAMs with. Station
|
||||
* 0x12345678, fix at Unix ms 1790170000123 (generationDeltaTime 45819), 53.5546667 N
|
||||
* 10.0223889 E, 5.43 m/s, heading 123.4 deg, -1.26 m/s^2; every confidence and the altitude
|
||||
* unavailable, as the encoder sends them.
|
||||
*/
|
||||
class VamUperCodecTest {
|
||||
|
||||
private fun ByteArray.hex(): String = joinToString("") { "%02x".format(it) }
|
||||
|
||||
private fun content(includeLowFrequency: Boolean, accuracyM: Float? = 3.0f) = VamContent(
|
||||
stationId = 0x12345678,
|
||||
timestamp = 1_790_170_000_123L,
|
||||
latitude = 53.5546667,
|
||||
longitude = 10.0223889,
|
||||
accuracyM = accuracyM,
|
||||
speedMps = 5.43,
|
||||
headingDeg = 123.4,
|
||||
accelerationMps2 = -1.26,
|
||||
includeLowFrequency = includeLowFrequency,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `VAM with the low-frequency container matches asn1tools`() {
|
||||
assertEquals(
|
||||
"031012345678b2fb400aac85a15b8a18ec88f30f3708eddd0f8002697e087ff24f322220",
|
||||
VamUperCodec.encode(content(includeLowFrequency = true)).hex(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `VAM without the low-frequency container matches asn1tools`() {
|
||||
assertEquals(
|
||||
"031012345678b2fb000aac85a15b8a18ec88f30f3708eddd0f8002697e087ff24f30",
|
||||
VamUperCodec.encode(content(includeLowFrequency = false)).hex(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unknown accuracy encodes the confidence ellipse as unavailable`() {
|
||||
assertEquals(
|
||||
"031012345678b2fb000aac85a15b8a18ec8fffffff08eddd0f8002697e087ff24f30",
|
||||
VamUperCodec.encode(content(includeLowFrequency = false, accuracyM = null)).hex(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user