diff --git a/docs/development/msp/msp_messages.json b/docs/development/msp/msp_messages.json index e1b128f305d..8368373bcc1 100644 --- a/docs/development/msp/msp_messages.json +++ b/docs/development/msp/msp_messages.json @@ -10371,6 +10371,106 @@ "notes": "Requires `USE_ADSB`. Only a subset of `adsbVehicle_t` is transmitted (callsign, core values, heading in whole degrees, TSLC, emitter type, TTL).", "description": "Retrieves the list of currently tracked ADSB (Automatic Dependent Surveillance–Broadcast) vehicles. See `adsbVehicle_t` and `adsbVehicleValues_t` in `io/adsb.h` for the exact structure fields." }, + "MSP2_ADSB_VEHICLE": { + "code": 8337, + "mspv": 2, + "request": { + "payload": [ + { + "name": "index", + "ctype": "uint8_t", + "desc": "Slot index to read, `0 .. (MSP2_ADSB_VEHICLE_COUNT - 1)`. WARNING: this is an iteration cursor over fixed slots, NOT a stable identifier. The same index may return a different aircraft (or an empty slot) on a later poll. Always identify the aircraft by the `icao` field in the reply; never cache or correlate data by index. Returns an error result if the index is out of range.", + "units": "" + } + ] + }, + "reply": { + "payload": [ + { + "name": "icao", + "ctype": "uint32_t", + "desc": "ICAO 24-bit address (`vehicleValues.icao`). This is the stable per-aircraft identifier; use it to correlate replies, not the request index. An empty slot reports `icao == 0` and `ttl == 0`.", + "units": "" + }, + { + "name": "lat", + "ctype": "int32_t", + "desc": "Latitude (`vehicleValues.gps.lat`).", + "units": "1e-7 deg" + }, + { + "name": "lon", + "ctype": "int32_t", + "desc": "Longitude (`vehicleValues.gps.lon`).", + "units": "1e-7 deg" + }, + { + "name": "alt", + "ctype": "int32_t", + "desc": "Altitude above sea level (`vehicleValues.alt`).", + "units": "cm" + }, + { + "name": "heading", + "ctype": "uint16_t", + "desc": "Course over ground at full resolution (`vehicleValues.heading`). Unlike `MSP2_ADSB_VEHICLE_LIST`, this is in centidegrees, not whole degrees.", + "units": "1e-2 deg" + }, + { + "name": "horVelocity", + "ctype": "uint16_t", + "desc": "Horizontal (ground) speed (`vehicleValues.horVelocity`). Not present in `MSP2_ADSB_VEHICLE_LIST`.", + "units": "cm/s" + }, + { + "name": "tslc", + "ctype": "uint8_t", + "desc": "Time since last communication (`vehicleValues.tslc`).", + "units": "s" + }, + { + "name": "emitterType", + "ctype": "uint8_t", + "desc": "Emitter category (`vehicleValues.emitterType`).", + "units": "" + }, + { + "name": "ttl", + "ctype": "uint8_t", + "desc": "Remaining time-to-live for this slot (`adsbVehicle->ttl`). `ttl == 0` means the slot is empty/expired and its contents are stale; skip such entries.", + "units": "s" + }, + { + "name": "callsign", + "desc": "Fixed-length callsign (`vehicleValues.callsign`), padded with NULs if shorter.", + "ctype": "char", + "array": true, + "array_size": 9, + "array_size_define": "ADSB_CALL_SIGN_MAX_LENGTH", + "units": "" + } + ] + }, + "notes": "Requires `USE_ADSB`. Reads a single ADSB vehicle slot by index. THE INDEX IS NOT A STABLE HANDLE: slots are reused, so a given index may hold a different aircraft (or be empty, `ttl == 0`) between polls. Correlate aircraft by the `icao` field in the reply, never by index. Compared with the bulk `MSP2_ADSB_VEHICLE_LIST`, this message adds horizontal velocity and reports heading at full (centidegree) resolution, and orders the callsign last. Returns an error result for an out-of-range index.", + "description": "Retrieves a single tracked ADSB (Automatic Dependent Surveillance-Broadcast) vehicle by slot index. Intended for polling one slot at a time: query `MSP2_ADSB_VEHICLE_COUNT` for the iteration bound, then request indices `0 .. count-1`, skipping slots with `ttl == 0`, and identify each aircraft by its `icao`. See `adsbVehicle_t` / `adsbVehicleValues_t` in `io/adsb.h`." + }, + "MSP2_ADSB_VEHICLE_COUNT": { + "code": 8338, + "mspv": 2, + "request": null, + "reply": { + "payload": [ + { + "name": "count", + "ctype": "uint8_t", + "desc": "Number of vehicle slots to iterate (`MAX_ADSB_VEHICLES`). This is the slot capacity / iteration bound, not the number of currently active aircraft - some slots may be empty (`ttl == 0`). 0 if `USE_ADSB` is disabled.", + "units": "" + } + ] + }, + "notes": "Requires `USE_ADSB`. Returns the iteration bound for `MSP2_ADSB_VEHICLE`: request indices `0 .. count-1` and skip any slot whose `ttl == 0`.", + "description": "Returns the number of ADSB vehicle slots available to iterate with `MSP2_ADSB_VEHICLE`." + }, "MSP2_INAV_CUSTOM_OSD_ELEMENTS": { "code": 8448, "mspv": 2, diff --git a/src/main/fc/fc_msp.c b/src/main/fc/fc_msp.c index 3ec3f89f3f0..eb50427ea81 100644 --- a/src/main/fc/fc_msp.c +++ b/src/main/fc/fc_msp.c @@ -1051,6 +1051,15 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF sbufWriteU32(dst, 0); #endif break; + + case MSP2_ADSB_VEHICLE_COUNT: +#ifdef USE_ADSB + sbufWriteU8(dst, MAX_ADSB_VEHICLES); // iteration bound for the client +#else + sbufWriteU8(dst, 0); +#endif + break; + case MSP_DEBUG: // output some useful QA statistics // debug[x] = ((hse_value / 1000000) * 1000) + (SystemCoreClock / 1000000); // XX0YY [crystal clock : core clock] @@ -4449,6 +4458,32 @@ bool mspFCProcessInOutCommand(uint16_t cmdMSP, sbuf_t *dst, sbuf_t *src, mspResu *ret = MSP_RESULT_ACK; break; +#ifdef USE_ADSB + case MSP2_ADSB_VEHICLE: + if (sbufBytesRemaining(src) >= 1) { + adsbVehicle_t *vehicle = findVehicle(sbufReadU8(src)); + if (vehicle == NULL) { // index past MAX_ADSB_VEHICLES + *ret = MSP_RESULT_ERROR; + break; + } + sbufWriteU32(dst, vehicle->vehicleValues.icao); + sbufWriteU32(dst, vehicle->vehicleValues.gps.lat); + sbufWriteU32(dst, vehicle->vehicleValues.gps.lon); + sbufWriteU32(dst, vehicle->vehicleValues.alt); + sbufWriteU16(dst, vehicle->vehicleValues.heading); // centideg, full-res + sbufWriteU16(dst, vehicle->vehicleValues.horVelocity); // cm/s - omitted by the bulk list + sbufWriteU8(dst, vehicle->vehicleValues.tslc); + sbufWriteU8(dst, vehicle->vehicleValues.emitterType); + sbufWriteU8(dst, vehicle->ttl); + sbufWriteData(dst, vehicle->vehicleValues.callsign, ADSB_CALL_SIGN_MAX_LENGTH); + } else { + *ret = MSP_RESULT_ERROR; // no index supplied + break; + } + *ret = MSP_RESULT_ACK; + break; +#endif + #if defined(USE_FLASHFS) case MSP_DATAFLASH_READ: mspFcDataFlashReadCommand(dst, src); diff --git a/src/main/msp/msp_protocol_v2_inav.h b/src/main/msp/msp_protocol_v2_inav.h index e50115d99ed..6d09ed2a13c 100755 --- a/src/main/msp/msp_protocol_v2_inav.h +++ b/src/main/msp/msp_protocol_v2_inav.h @@ -111,6 +111,8 @@ #define MSP2_INAV_SELECT_MIXER_PROFILE 0x2080 #define MSP2_ADSB_VEHICLE_LIST 0x2090 +#define MSP2_ADSB_VEHICLE 0x2091 +#define MSP2_ADSB_VEHICLE_COUNT 0x2092 #define MSP2_INAV_CUSTOM_OSD_ELEMENTS 0x2100 #define MSP2_INAV_CUSTOM_OSD_ELEMENT 0x2101