/** * @copyright Copyright (c) 2021 Sagetech, Inc. All rights reserved. * * @file sgDecodeSVR.c * @author jimb * * @date Feb 10, 2021 * * This file receives a raw ADS-B target state vector report message buffer and * parses the payload into a data struct. */ #include #include #include #include #include "sg.h" #include "sgUtil.h" #include "target.h" // airborne surface // -------- -------- #define SV_PARAM_TOA_EPOS (1 << 3) // x #define SV_PARAM_TOA_POS (1 << 2) // x x #define SV_PARAM_TOA_VEL (1 << 1) // x x #define SV_PARAM_LATLON (1 << 0) // x x #define SV_PARAM_GEOALT (1 << 7) // x #define SV_PARAM_VEL (1 << 6) // x #define SV_PARAM_SURF_GS (1 << 5) // x #define SV_PARAM_SURF_HEAD (1 << 4) // x #define SV_PARAM_BAROALT (1 << 3) // x #define SV_PARAM_VRATE (1 << 2) // x #define SV_PARAM_NIC (1 << 1) // x x #define SV_PARAM_ESTLAT (1 << 0) // x #define SV_PARAM_ESTLON (1 << 7) // x #define SV_PARAM_ESTNVEL (1 << 6) #define SV_PARAM_ESTEVAL (1 << 5) #define SV_PARAM_SURV (1 << 4) // x x #define SV_PARAM_REPORT (1 << 3) // x x /// the payload offset. #define PBASE 4 /* * Documented in the header file. */ bool sgDecodeSVR(uint8_t *buffer, sg_svr_t *svr) { // memset(svr, 0, sizeof(sg_svr_t)); uint8_t fields[3]; memcpy(&fields, &buffer[PBASE + 0], 3); svr->type = buffer[PBASE + 0] == 0x1F ? svrAirborne : svrSurface; svr->flags = buffer[PBASE + 3]; svr->eflags = buffer[PBASE + 4]; svr->addr = toInt32(&buffer[PBASE + 5]) & 0xFFFFFF; svr->addrType = buffer[PBASE + 8] & 0xFF; uint8_t ofs = 9; if (fields[0] & SV_PARAM_TOA_EPOS) { svr->toaEst = toTOA(&buffer[PBASE + ofs]); ofs += 2; } if (fields[0] & SV_PARAM_TOA_POS) { svr->toaPosition = toTOA(&buffer[PBASE + ofs]); ofs += 2; } if (fields[0] & SV_PARAM_TOA_VEL) { svr->toaSpeed = toTOA(&buffer[PBASE + ofs]); ofs += 2; } if (fields[0] & SV_PARAM_LATLON) { if (svr->validity.position) { svr->lat = toLatLon(&buffer[PBASE + ofs + 0]); svr->lon = toLatLon(&buffer[PBASE + ofs + 3]); } else { svr->lat = 0.0; svr->lon = 0.0; } ofs += 6; } if (svr->type == svrAirborne) { if (fields[1] & SV_PARAM_GEOALT) { if (svr->validity.geoAlt) { svr->airborne.geoAlt = toAlt(&buffer[PBASE + ofs]); } else { svr->airborne.geoAlt = 0; } ofs += 3; } if (fields[1] & SV_PARAM_VEL) { if (svr->validity.airSpeed) { int16_t nvel = toVel(&buffer[PBASE + ofs + 0]); int16_t evel = toVel(&buffer[PBASE + ofs + 2]); svr->airborne.heading = toHeading2((double)nvel, (double)evel); svr->airborne.speed = sqrt(nvel * nvel + evel * evel); svr->airborne.velEW = evel; svr->airborne.velNS = nvel; } else { svr->airborne.heading = 0; svr->airborne.speed = 0; svr->airborne.velEW = 0; svr->airborne.velNS = 0; } ofs += 4; } if (fields[1] & SV_PARAM_BAROALT) { if (svr->validity.baroAlt) { svr->airborne.baroAlt = toAlt(&buffer[PBASE + ofs]); } else { svr->airborne.baroAlt = 0; } ofs += 3; } if (fields[1] & SV_PARAM_VRATE) { if (svr->validity.baroVRate || svr->validity.geoVRate) { svr->airborne.vrate = toInt16(&buffer[PBASE + ofs]); } else { svr->airborne.vrate = 0; } ofs += 2; } } else { if (fields[1] & SV_PARAM_SURF_GS) { if (svr->validity.surfSpeed) { svr->surface.speed = toGS(&buffer[PBASE + ofs]); } else { svr->surface.speed = 0; } ofs += 1; } if (fields[1] & SV_PARAM_SURF_HEAD) { if (svr->validity.surfHeading) { svr->surface.heading = toHeading(&buffer[PBASE + ofs]); } else { svr->surface.heading = 0; } ofs += 1; } } if (fields[1] & SV_PARAM_NIC) { svr->nic = buffer[PBASE + ofs]; ofs += 1; } if (fields[1] & SV_PARAM_ESTLAT) { if (svr->evalidity.estPosition) { svr->airborne.estLat = toLatLon(&buffer[PBASE + ofs]); } else { svr->airborne.estLat = 0; } ofs += 3; } if (fields[2] & SV_PARAM_ESTLON) { if (svr->evalidity.estPosition) { svr->airborne.estLon = toLatLon(&buffer[PBASE + ofs]); } else { svr->airborne.estLon = 0; } ofs += 3; } if (fields[2] & SV_PARAM_SURV) { svr->survStatus = buffer[PBASE + ofs]; ofs += 1; } if (fields[2] & SV_PARAM_REPORT) { svr->mode = buffer[PBASE + ofs]; } return true; }