Line data Source code
1 : /** 2 : * @copyright Copyright (c) 2020 Sagetech, Inc. All rights reserved. 3 : * 4 : * @file sgDecodeMSR.c 5 : * @author jim.billmeyer 6 : * 7 : * @date Mar 17, 2021 8 : */ 9 : 10 : #include "sg.h" 11 : #include <stdbool.h> 12 : #include <stdint.h> 13 : #include <string.h> 14 : #include "sgUtil.h" 15 : 16 : #define MS_PARAM_TOA (1 << 3) 17 : #define MS_PARAM_ADSBVER (1 << 2) 18 : #define MS_PARAM_CALLSIGN (1 << 1) 19 : #define MS_PARAM_CATEMITTER (1 << 0) 20 : 21 : #define MS_PARAM_AVLEN (1 << 7) 22 : #define MS_PARAM_PRIORITY (1 << 6) 23 : #define MS_PARAM_CAPCODES (1 << 5) 24 : #define MS_PARAM_OPMODE (1 << 4) 25 : #define MS_PARAM_NACP (1 << 3) 26 : #define MS_PARAM_NACV (1 << 2) 27 : #define MS_PARAM_SDA (1 << 1) 28 : #define MS_PARAM_GVA (1 << 0) 29 : 30 : #define MS_PARAM_NIC (1 << 7) 31 : #define MS_PARAM_HEADING (1 << 6) 32 : #define MS_PARAM_VRATE (1 << 5) 33 : 34 : #define MS_CAP_B2LOW (1 << 3) 35 : #define MS_CAP_UAT (1 << 1) 36 : #define MS_CAP_TCR ((1 << 2) | (1 << 3)) 37 : #define MS_CAP_TSR (1 << 4) 38 : #define MS_CAP_ARV (1 << 5) 39 : #define MS_CAP_ADSB (1 << 6) 40 : #define MS_CAP_TCAS (1 << 7) 41 : 42 : #define MS_OP_GPS_LATFMT (1 << 7) 43 : #define MS_OP_GPS_LONFMT (1 << 6) 44 : #define MS_OP_TCAS_RA (1 << 5) 45 : #define MS_OP_IDENT (1 << 4) 46 : #define MS_OP_SINGLE_ANT (1 << 2) 47 : 48 : /// the payload offset. 49 : #define PBASE 4 50 : 51 : /* 52 : * Documented in the header file. 53 : */ 54 4228 : bool sgDecodeMSR(uint8_t *buffer, sg_msr_t *msr) 55 : { 56 4228 : memset(msr, 0, sizeof(sg_msr_t)); 57 : 58 : uint8_t fields[3]; 59 4228 : memcpy(fields, &buffer[PBASE + 0], 3); 60 : 61 4228 : if (buffer[PBASE + 1] == 0x6E && buffer[PBASE + 2] == 0x60) 62 : { 63 0 : msr->type = msrTypeV0; 64 : } 65 4228 : else if (buffer[PBASE + 1] == 0x7E && buffer[PBASE + 2] == 0xE0) 66 : { 67 0 : msr->type = msrTypeV1Airborne; 68 : } 69 4228 : else if (buffer[PBASE + 1] == 0xFE && buffer[PBASE + 2] == 0xE0) 70 : { 71 0 : msr->type = msrTypeV1Surface; 72 : } 73 4228 : else if (buffer[PBASE + 1] == 0x7F && buffer[PBASE + 2] == 0xE0) 74 : { 75 0 : msr->type = msrTypeV2Airborne; 76 : } 77 4228 : else if (buffer[PBASE + 1] == 0xFF && buffer[PBASE + 2] == 0xE0) 78 : { 79 0 : msr->type = msrTypeV2Surface; 80 : } 81 : 82 4228 : msr->flags = buffer[PBASE + 3]; 83 4228 : msr->addr = toInt32(&buffer[PBASE + 4]) & 0xFFFFFF; 84 4228 : msr->addrType = buffer[PBASE + 7] & 0xFF; 85 : 86 4228 : uint8_t ofs = 8; 87 : 88 4228 : if (fields[0] & MS_PARAM_TOA) 89 : { 90 0 : msr->toa = toTOA(&buffer[PBASE + ofs]); 91 0 : ofs += 2; 92 : } 93 : 94 4228 : if (fields[0] & MS_PARAM_ADSBVER) 95 : { 96 0 : msr->version = buffer[PBASE + ofs]; 97 0 : ofs++; 98 : } 99 : 100 4228 : if (fields[0] & MS_PARAM_CALLSIGN) 101 : { 102 4228 : memset(msr->callsign, 0, 9); 103 4228 : memcpy(msr->callsign, &buffer[PBASE + ofs], 8); 104 4228 : ofs += 8; 105 : } 106 : 107 4228 : if (fields[0] & MS_PARAM_CATEMITTER) 108 : { 109 0 : msr->emitter = buffer[PBASE + ofs]; 110 0 : ofs++; 111 : } 112 : 113 4228 : if (fields[1] & MS_PARAM_AVLEN) 114 : { 115 0 : msr->size = buffer[PBASE + ofs]; 116 0 : ofs++; 117 : } 118 : 119 4228 : if (fields[1] & MS_PARAM_PRIORITY) 120 : { 121 0 : msr->priority = buffer[PBASE + ofs]; 122 0 : ofs++; 123 : } 124 : 125 4228 : if (fields[1] & MS_PARAM_CAPCODES) 126 : { 127 0 : uint8_t cap = buffer[PBASE + ofs + 0]; 128 0 : msr->capability.b2low = cap & MS_CAP_B2LOW; 129 : 130 0 : cap = buffer[PBASE + ofs + 1]; 131 0 : msr->capability.uat = cap & MS_CAP_UAT; 132 0 : msr->capability.tcr = (cap & MS_CAP_TCR) >> 2; 133 0 : msr->capability.tsr = cap & MS_CAP_TSR; 134 0 : msr->capability.arv = cap & MS_CAP_ARV; 135 0 : msr->capability.adsb = cap & MS_CAP_ADSB; 136 0 : msr->capability.tcas = cap & MS_CAP_TCAS; 137 : 138 0 : ofs += 3; 139 : } 140 : 141 4228 : if (fields[1] & MS_PARAM_OPMODE) 142 : { 143 0 : uint8_t op = buffer[PBASE + ofs + 0]; 144 0 : msr->opMode.gpsLatFmt = (op & MS_OP_GPS_LATFMT) == 0; 145 0 : msr->opMode.gpsLonFmt = (op & MS_OP_GPS_LONFMT) == 0; 146 0 : msr->opMode.tcasRA = op & MS_OP_TCAS_RA; 147 0 : msr->opMode.ident = op & MS_OP_IDENT; 148 0 : msr->opMode.singleAnt = op & MS_OP_SINGLE_ANT; 149 : 150 0 : op = buffer[PBASE + ofs + 1]; 151 0 : msr->opMode.gpsLatOfs = op >> 5; 152 0 : msr->opMode.gpsLonOfs = op & 0x17; 153 : 154 0 : ofs += 2; 155 : } 156 : 157 4228 : if (fields[1] & MS_PARAM_NACP) 158 : { 159 0 : msr->svQuality.nacp = buffer[PBASE + ofs]; 160 0 : ofs++; 161 : } 162 : 163 4228 : if (fields[1] & MS_PARAM_NACV) 164 : { 165 0 : msr->svQuality.nacv = buffer[PBASE + ofs]; 166 0 : ofs++; 167 : } 168 : 169 4228 : if (fields[1] & MS_PARAM_SDA) 170 : { 171 0 : uint8_t sda = buffer[PBASE + ofs]; 172 0 : msr->svQuality.sda = (sda & 0x18) >> 3; 173 0 : msr->svQuality.silSupp = (sda & 0x04); 174 0 : msr->svQuality.sil = (sda & 0x03); 175 0 : ofs++; 176 : } 177 : 178 4228 : if (fields[1] & MS_PARAM_GVA) 179 : { 180 0 : msr->svQuality.gva = buffer[PBASE + ofs]; 181 0 : ofs++; 182 : } 183 : 184 4228 : if (fields[2] & MS_PARAM_NIC) 185 : { 186 0 : msr->svQuality.nicBaro = buffer[PBASE + ofs]; 187 0 : ofs++; 188 : } 189 : 190 4228 : if (fields[2] & MS_PARAM_HEADING) 191 : { 192 0 : msr->trackHeading = buffer[PBASE + ofs]; 193 0 : ofs++; 194 : } 195 : 196 4228 : if (fields[2] & MS_PARAM_VRATE) 197 : { 198 0 : msr->vrateType = buffer[PBASE + ofs]; 199 0 : ofs++; 200 : } 201 : 202 4228 : return true; 203 : }