diff --git a/demod/multi/dfm09base.c b/demod/multi/dfm09base.c index 3ba2d07..99a1650 100644 --- a/demod/multi/dfm09base.c +++ b/demod/multi/dfm09base.c @@ -3,7 +3,7 @@ * dfm09 (dfm06) * sync header: correlation/matched filter * compile: - * gcc -c dfm09mod.c + * gcc -c dfm09base.c * * author: zilog80 */ @@ -23,11 +23,33 @@ #include "demod_base.h" +enum dfmtyp_keys_t { + UNDEF, + UNKNW, + DFM06, + PS15, + DFM09, + DFM09P, + DFM17, + DFM17P +}; + +static char *DFM_types[] = { + [UNDEF] = "", + [UNKNW] = "DFMxX", + [DFM06] = "DFM06", + [PS15] = "PS15", + [DFM09] = "DFM09", + [DFM09P] = "DFM09P", + [DFM17] = "DFM17", + [DFM17P] = "DFM17P" +}; + typedef struct { i8_t vbs; // verbose output i8_t raw; // raw frames i8_t crc; // CRC check output - i8_t ecc; // Reed-Solomon ECC + i8_t ecc; // Hamming ECC i8_t sat; // GPS sat data i8_t ptu; // PTU: temperature i8_t inv; @@ -51,6 +73,12 @@ typedef struct { ui32_t chX[2]; } sn_t; +typedef struct { + ui32_t prn; // SVs used (PRN) + float dMSL; // Alt_MSL - Alt_ellipsoid = -N = - geoid_height = ellipsoid - geoid + ui8_t nSV; // numSVs used +} gpsdat_t; + #define BITFRAME_LEN 280 typedef struct { @@ -58,14 +86,19 @@ typedef struct { int sonde_typ; ui32_t SN6; ui32_t SN; - int week; int gpssec; + int week; int tow; ui32_t sec_gps; int jahr; int monat; int tag; int std; int min; float sek; double lat; double lon; double alt; double dir; double horiV; double vertV; - float meas24[5+2]; - float status[2]; + //float T; + float Rf; float _frmcnt; + float meas24[9]; + float status[2]; + ui32_t val24[9]; + ui8_t cfgchk24[9]; + int cfgchk; char sonde_id[16]; // "ID__:xxxxxxxx\0\0" char frame_bits[BITFRAME_LEN+4]; char dat_str[9][13+1]; @@ -73,7 +106,12 @@ typedef struct { pcksts_t pck[9]; option_t option; int ptu_out; + char sensortyp0xC; + char *dfmtyp; int jsn_freq; // freq/kHz (SDR) + gpsdat_t gps; + int prev_cntsec_diff; + int prev_manpol; } gpx_t; @@ -87,6 +125,27 @@ static char dfm_header[] = "0100010111001111"; #define BAUD_RATE 2500 /* ------------------------------------------------------------------------------------ */ +static int datetime2GPSweek(int yy, int mm, int dd, + int hr, int min, int sec, + int *week, int *tow) { + int ww = 0; + int tt = 0; + int gpsDays = 0; + + if ( mm < 3 ) { yy -= 1; mm += 12; } + + gpsDays = (int)(365.25*yy) + (int)(30.6001*(mm+1.0)) + dd - 723263; // 1980-01-06 + + ww = gpsDays / 7; + tt = gpsDays % 7; + tt = tt*86400 + hr*3600 + min*60 + sec; + + *week = ww; + *tow = tt; + + return 0; +} +/* ------------------------------------------------------------------------------------ */ #define B 8 // codeword: 8 bit @@ -98,6 +157,15 @@ static char dfm_header[] = "0100010111001111"; #define DAT2 (16+160) // 104 bit // frame: 280 bit +static ui8_t G[8][4] = // Generator + {{ 1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 1, 0}, + { 0, 0, 0, 1}, + { 0, 1, 1, 1}, + { 1, 0, 1, 1}, + { 1, 1, 0, 1}, + { 1, 1, 1, 0}}; static ui8_t H[4][8] = // Parity-Check {{ 0, 1, 1, 1, 1, 0, 0, 0}, { 1, 0, 1, 1, 0, 1, 0, 0}, @@ -220,6 +288,9 @@ static int dat_out(gpx_t *gpx, ui8_t *dat_bits, int ec) { } } + // GPS data + // SiRF msg ID 41: Geodetic Navigation Data + if (fr_id == 0) { //start = 0x1000; frnr = bits2val(dat_bits+24, 8); @@ -227,7 +298,8 @@ static int dat_out(gpx_t *gpx, ui8_t *dat_bits, int ec) { } if (fr_id == 1) { - // 00..31: ? GPS-Sats in Sicht? + // 00..31: GPS-Sats in solution (bitmap) + gpx->gps.prn = bits2val(dat_bits, 32); // SV/PRN used msek = bits2val(dat_bits+32, 16); // UTC (= GPS - 18sec ab 1.1.2017) gpx->sek = msek/1000.0; } @@ -254,6 +326,8 @@ static int dat_out(gpx_t *gpx, ui8_t *dat_bits, int ec) { } if (fr_id == 5) { + short dMSL = bits2val(dat_bits, 16); + gpx->gps.dMSL = dMSL/1e2; } if (fr_id == 6) { // sat data @@ -268,6 +342,7 @@ static int dat_out(gpx_t *gpx, ui8_t *dat_bits, int ec) { gpx->tag = bits2val(dat_bits+16, 5); gpx->std = bits2val(dat_bits+21, 5); gpx->min = bits2val(dat_bits+26, 6); + gpx->gps.nSV = bits2val(dat_bits+32, 8); } ret = fr_id; @@ -314,24 +389,26 @@ static float get_Temp(gpx_t *gpx) { // meas[0..4] // meas0 = g*(R + Rs) // meas3 = g*Rs , Rs: dfm6:10k, dfm9:20k // meas4 = g*Rf , Rf=220k + float T = 0; // T/Kelvin float f = gpx->meas24[0], f1 = gpx->meas24[3], f2 = gpx->meas24[4]; - if (gpx->ptu_out >= 0xC) { + if (gpx->sensortyp0xC == 'P') { // 0xC: "P+" DFM-09P , "T-" DFM-17TU ; 0xD: "P-" DFM-17P ? f = gpx->meas24[0+1]; f1 = gpx->meas24[3+2]; f2 = gpx->meas24[4+2]; } - //float *meas = gpx->meas24; - float B0 = 3260.0; // B/Kelvin, fit -55C..+40C - float T0 = 25 + 273.15; // t0=25C - float R0 = 5.0e3; // R0=R25=5k - float Rf = 220e3; // Rf = 220k - float g = f2/Rf; - float R = (f-f1) / g; // meas[0,3,4] > 0 ? - float T = 0; // T/Kelvin - if (f*f1*f2 == 0) R = 0; - if (R > 0) T = 1/(1/T0 + 1/B0 * log(R/R0)); + if (gpx->cfgchk) { + //float *meas = gpx->meas24; + float B0 = 3260.0; // B/Kelvin, fit -55C..+40C + float T0 = 25 + 273.15; // t0=25C + float R0 = 5.0e3; // R0=R25=5k + float Rf = gpx->Rf; // Rf = DFM09:220k , DFM17:332k + float g = f2/Rf; + float R = (f-f1) / g; // meas[0,3,4] > 0 ? + if (f*f1*f2 == 0) R = 0; + if (R > 0) T = 1/(1/T0 + 1/B0 * log(R/R0)); + } return T - 273.15; // Celsius // DFM-06: meas20 * 16 = meas24 // -> (meas24[0]-meas24[3])/meas24[4]=(meas20[0]-meas20[3])/meas20[4] @@ -348,7 +425,7 @@ static float get_Temp2(gpx_t *gpx) { // meas[0..4] float f = gpx->meas24[0], f1 = gpx->meas24[3], f2 = gpx->meas24[4]; - if (gpx->ptu_out >= 0xC) { + if (gpx->ptu_out >= 0xC && gpx->meas24[6] < 220e3) { f = gpx->meas24[0+1]; f1 = gpx->meas24[3+2]; f2 = gpx->meas24[4+2]; @@ -356,7 +433,7 @@ static float get_Temp2(gpx_t *gpx) { // meas[0..4] float B0 = 3260.0; // B/Kelvin, fit -55C..+40C float T0 = 25 + 273.15; // t0=25C float R0 = 5.0e3; // R0=R25=5k - float Rf2 = 220e3; // Rf2 = Rf = 220k + float Rf2 = 220e3; // Rf2 = Rf = DFM09:220k , DFM17:332k float g_o = f2/Rf2; // approx gain float Rs_o = f1/g_o; // = Rf2 * f1/f2; float Rf1 = Rs_o; // Rf1 = Rs: dfm6:10k, dfm9:20k @@ -374,7 +451,7 @@ static float get_Temp2(gpx_t *gpx) { // meas[0..4] R = (f-f1)/g; // meas[0,3,4] > 0 ? if (R > 0) T = 1/(1/T0 + 1/B0 * log(R/R0)); - if (gpx->option.ptu && gpx->ptu_out && gpx->option.dbg) { + if (gpx->option.ptu && gpx->ptu_out && gpx->option.dbg && gpx->option.vbs == 3) { printf(" (Rso: %.1f , Rb: %.1f)", Rs_o/1e3, Rb/1e3); } @@ -413,13 +490,13 @@ static float get_Temp4(gpx_t *gpx) { // meas[0..4] float f = gpx->meas24[0], f1 = gpx->meas24[3], f2 = gpx->meas24[4]; - if (gpx->ptu_out >= 0xC) { + if (gpx->ptu_out >= 0xC && gpx->meas24[6] < 220e3) { f = gpx->meas24[0+1]; f1 = gpx->meas24[3+2]; f2 = gpx->meas24[4+2]; } //float *meas = gpx->meas24; - float Rf = 220e3; // Rf = 220k + float Rf = 220e3; // Rf = DFM09:220k , DFM17:332k float g = f2/Rf; float R = (f-f1) / g; // f,f1,f2 > 0 ? float T = 0; // T/Kelvin @@ -430,6 +507,14 @@ static float get_Temp4(gpx_t *gpx) { // meas[0..4] } +static int reset_cfgchk(gpx_t *gpx) { + int j; + for (j = 0; j < 9; j++) gpx->cfgchk24[j] = 0; + gpx->cfgchk = 0; + gpx->ptu_out = 0; + return 0; +} + #define SNbit 0x0100 static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { int ret = 0; @@ -451,17 +536,18 @@ static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { { // reset if 0x5A, 0x5B (DFM-06) gpx->sonde_typ = 0; gpx->snc.max_ch = conf_id; + reset_cfgchk(gpx); } if (conf_id > 5 && conf_id > gpx->snc.max_ch && ec == 0) { // mind. 6 Kanaele if (bits2val(conf_bits+4, 4) == 0xC) { // 0xsCaaaab gpx->snc.max_ch = conf_id; // reset? } -/* + /* if (bits2val(conf_bits, 8) == 0x70) { // 0x70aaaab gpx->snc.max_ch = conf_id; // reset? } -*/ + */ } // SN: mind. 6 Kanaele @@ -475,10 +561,11 @@ static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { if (SN6 == gpx->SN6 && SN6 != 0) { // nur Nibble-Werte 0..9 gpx->sonde_typ = SNbit | 6; gpx->ptu_out = 6; // <-> DFM-06 - sprintf(gpx->sonde_id, "ID06:%6X", gpx->SN6); + sprintf(gpx->sonde_id, "IDx%1X:%6X", gpx->sonde_typ & 0xF, gpx->SN6); } else { // reset gpx->sonde_typ = 0; + reset_cfgchk(gpx); } gpx->SN6 = SN6; } // SN in last pck/channel, #{pcks} depends on (sensor) config; observed: @@ -494,6 +581,7 @@ static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { gpx->snc.chXbit = 0; gpx->snc.chX[0] = 0; gpx->snc.chX[1] = 0; + reset_cfgchk(gpx); } gpx->snc.sn_ch = sn_ch; gpx->snc.chX[hl] = (val >> 4) & 0xFFFF; @@ -508,19 +596,17 @@ static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { gpx->ptu_out = 0; if (sn_ch == 0xA /*&& (sn2_ch & 0xF) == 0xC*/) gpx->ptu_out = sn_ch; // <+> DFM-09 if (sn_ch == 0xB /*&& (sn2_ch & 0xF) == 0xC*/) gpx->ptu_out = sn_ch; // <-> DFM-17 - if (sn_ch == 0xC) gpx->ptu_out = sn_ch; // <+> DFM-09P(?) - if (sn_ch == 0xD) gpx->ptu_out = sn_ch; // <-> DFM-17P? + if (sn_ch == 0xC) gpx->ptu_out = sn_ch; // <+> DFM-09P(?) , <-> DFM-17TU(?) + if (sn_ch == 0xD) gpx->ptu_out = sn_ch; // <-> DFM-17P(?) // PS-15 ? (sn2_ch & 0xF) == 0x0 : gpx->ptu_out = 0 // <-> PS-15 - if ( (gpx->sonde_typ & 0xF) == 0xA) { - sprintf(gpx->sonde_id, "ID09:%6u", gpx->SN); - } - else { - sprintf(gpx->sonde_id, "ID-%1X:%6u", gpx->sonde_typ & 0xF, gpx->SN); + if ( (gpx->sonde_typ & 0xF) > 6) { + sprintf(gpx->sonde_id, "IDx%1X:%6u", gpx->sonde_typ & 0xF, gpx->SN); } } else { // reset gpx->sonde_typ = 0; + reset_cfgchk(gpx); } gpx->snc.SN_X = SN; gpx->snc.chXbit = 0; @@ -531,41 +617,80 @@ static int conf_out(gpx_t *gpx, ui8_t *conf_bits, int ec) { } - if (conf_id >= 0 && conf_id <= 4) { + if (conf_id >= 0 && conf_id <= 8) { + gpx->cfgchk24[conf_id] = 1; val = bits2val(conf_bits+4, 4*6); - gpx->meas24[conf_id] = fl24(val); + gpx->val24[conf_id] = val; + gpx->meas24[conf_id] = fl24(val); //0xA: 0..4 // DFM-09 (STM32): 24bit 0exxxxx // DFM-06 (NXP8): 20bit 0exxxx0 // fl20(bits2val(conf_bits+4, 4*5)) // = fl20(exxxx) // = fl24(exxxx0)/2^4 // meas20 * 16 = meas24 + gpx->cfgchk = 0; + if (gpx->ptu_out >= 0x5) gpx->cfgchk = gpx->cfgchk24[0]*gpx->cfgchk24[1]*gpx->cfgchk24[2] + *gpx->cfgchk24[3]*gpx->cfgchk24[4]*gpx->cfgchk24[5]; + if (gpx->ptu_out >= 0x7) gpx->cfgchk *= gpx->cfgchk24[6]*gpx->cfgchk24[7]; + if (gpx->ptu_out >= 0x8) gpx->cfgchk *= gpx->cfgchk24[8]; } - if (gpx->ptu_out >= 0xC) { // DFM>=09(P) - if (conf_id >= 5 && conf_id <= 6) { - val = bits2val(conf_bits+4, 4*6); - gpx->meas24[conf_id] = fl24(val); + + gpx->sensortyp0xC = 'T'; + gpx->Rf = 220e3; + if (gpx->cfgchk) + { // 0xC: "P+" DFM-09P , "T-" DFM-17TU ; 0xD: "P-" DFM-17P ? + if (gpx->ptu_out >= 0xD || (gpx->ptu_out >= 0xC && gpx->meas24[6] < 220e3)) { // gpx->meas24[6] < 220e3 <=> gpx->meas24[0] > 1e6 ? + gpx->sensortyp0xC = 'P'; // gpx->meas24[0] > 1e6 ? + } + if ( ((gpx->ptu_out == 0xB || gpx->ptu_out == 0xC) && gpx->sensortyp0xC == 'T') || gpx->ptu_out >= 0xD) gpx->Rf = 332e3; // DFM-17 ? + + // STM32-status: Bat, MCU-Temp + if (gpx->ptu_out >= 0xA) { // DFM>=09(P) (STM32) + ui8_t ofs = 0; + if (gpx->sensortyp0xC == 'P') ofs = 2; + // + if (conf_id == 0x5+ofs) { // voltage + val = bits2val(conf_bits+8, 4*4); + gpx->status[0] = val/1000.0; + } + if (conf_id == 0x6+ofs) { // T-intern (STM32) + val = bits2val(conf_bits+8, 4*4); + gpx->status[1] = val/100.0; + } + } + else { + gpx->status[0] = 0; + gpx->status[1] = 0; } } - // STM32-status: Bat, MCU-Temp - if (gpx->ptu_out >= 0xA) { // DFM>=09(P) (STM32) - ui8_t ofs = 0; - if (gpx->ptu_out >= 0xC) ofs = 2; - if (conf_id == 0x5+ofs) { // voltage - val = bits2val(conf_bits+8, 4*4); - gpx->status[0] = val/1000.0; - } - if (conf_id == 0x6+ofs) { // T-intern (STM32) - val = bits2val(conf_bits+8, 4*4); - gpx->status[1] = val/100.0; - } + /* guess DFM type + V/Ti Tf012 Rf + 0xA DFM-09 5/6 0,3,4 'T+' 220k + 0xC DFM-09P 7/8 1,5,6 'P+' 220k + 0xB DFM-17 5/6 0,3,4 'T-' 332k + 0xC DFM-17TU 5/6 0,3,4 'T-' 332k + 0xD DFM-17P 7/8 1,5,6 'P-' 332k + */ + gpx->dfmtyp = DFM_types[UNDEF]; + switch (gpx->sonde_typ & 0xF) { + case 0x6: gpx->dfmtyp = DFM_types[DFM06]; + break; + case 0x7: + case 0x8: gpx->dfmtyp = DFM_types[PS15]; + break; + case 0xA: gpx->dfmtyp = DFM_types[DFM09]; + break; + case 0xB: gpx->dfmtyp = DFM_types[DFM17]; + break; + case 0xC: if (gpx->sensortyp0xC == 'P') gpx->dfmtyp = DFM_types[DFM09P]; + else /*'T'*/ gpx->dfmtyp = DFM_types[DFM17]; + break; + case 0xD: gpx->dfmtyp = DFM_types[DFM17P]; + break; + default: gpx->dfmtyp = DFM_types[UNKNW]; + break; } - else { - gpx->status[0] = 0; - gpx->status[1] = 0; - } - return ret; } @@ -602,6 +727,29 @@ static int print_gpx(gpx_t *gpx) { jsonout = 0; } + if (!gpx->option.raw || gpx->option.jsn) { + + // seconds since GPS (ignoring leap seconds, DFM=UTC) + datetime2GPSweek(gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, (int)(gpx->sek+0.5), &(gpx->week), &(gpx->tow)); + gpx->sec_gps = gpx->week*604800 + gpx->tow; // SECONDS_IN_WEEK=7*86400=604800 + + if (contgps) { + ui8_t secmod256 = (ui8_t)gpx->sec_gps; // % 256 + int cntsec_diff = secmod256 - gpx->frnr; + if (cntsec_diff < 0) cntsec_diff += 256; + // DFM06: cntsec_diff might drift slowly (30sec sync), but recovers faster + // DFM09: delta(diff)=1 could indicate decoding error + if (gpx->option.jsn && (cntsec_diff != gpx->prev_cntsec_diff || gpx->option.inv != gpx->prev_manpol)) { + // initial state not relevant + jsonout = 0; + gpx->sonde_typ = 0; + reset_cfgchk(gpx); + } + gpx->prev_cntsec_diff = cntsec_diff; + gpx->prev_manpol = gpx->option.inv; + } + } + if (output & 0xF000) { if (gpx->option.raw == 2) { @@ -612,6 +760,7 @@ static int print_gpx(gpx_t *gpx) { for (i = 0; i < 9; i++) { for (j = 0; j < 13; j++) gpx->dat_str[i][j] = ' '; } + printf("\n"); } else { if (gpx->option.aut && gpx->option.vbs >= 2) printf("<%c> ", gpx->option.inv?'-':'+'); @@ -626,57 +775,70 @@ static int print_gpx(gpx_t *gpx) { printf(" vH: %5.2f ", gpx->horiV); printf(" D: %5.1f ", gpx->dir); printf(" vV: %5.2f ", gpx->vertV); - if (gpx->option.ptu && gpx->ptu_out) { - float t = get_Temp(gpx); - if (t > -270.0) printf(" T=%.1fC ", t); - if (gpx->option.dbg) { - float t2 = get_Temp2(gpx); - float t4 = get_Temp4(gpx); - if (t2 > -270.0) printf(" T2=%.1fC ", t2); - if (t4 > -270.0) printf(" T4=%.1fC ", t4); - printf(" f0: %.2f ", gpx->meas24[0]); - printf(" f1: %.2f ", gpx->meas24[1]); - printf(" f2: %.2f ", gpx->meas24[2]); - printf(" f3: %.2f ", gpx->meas24[3]); - printf(" f4: %.2f ", gpx->meas24[4]); - if (gpx->ptu_out >= 0xC) { - printf(" f5: %.2f ", gpx->meas24[5]); - printf(" f6: %.2f ", gpx->meas24[6]); - } + if (gpx->cfgchk) + { + if (gpx->option.ptu && gpx->ptu_out) { + float t = get_Temp(gpx); + if (t > -270.0) { + printf(" T=%.1fC ", t); // 0xC:P+ DFM-09P , 0xC:T- DFM-17TU , 0xD:P- DFM-17P ? + if (gpx->option.vbs == 3) printf(" (0x%X:%c%c) ", gpx->sonde_typ & 0xF, gpx->sensortyp0xC, gpx->option.inv?'-':'+'); + } + if (gpx->option.dbg) { + float t2 = get_Temp2(gpx); + float t4 = get_Temp4(gpx); + if (t2 > -270.0) printf(" T2=%.1fC ", t2); + if (t4 > -270.0) printf(" T4=%.1fC ", t4); + } + } + if (gpx->option.vbs == 3 && gpx->ptu_out >= 0xA) { + if (gpx->status[0]> 0.0) printf(" U: %.2fV ", gpx->status[0]); + if (gpx->status[1]> 0.0) printf(" Ti: %.1fK ", gpx->status[1]); } } - if (gpx->option.vbs == 3 && gpx->ptu_out >= 0xA) { - printf(" U: %.2fV ", gpx->status[0]); - printf(" Ti: %.1fK ", gpx->status[1]); + if (gpx->option.dbg) { + printf(" f0:%.1f", gpx->meas24[0]); + printf(" f1:%.1f", gpx->meas24[1]); + printf(" f2:%.1f", gpx->meas24[2]); + printf(" f3:%.1f", gpx->meas24[3]); + printf(" f4:%.1f", gpx->meas24[4]); + if (gpx->ptu_out >= 0xA /*0xC*/) { + printf(" f5:%.1f", gpx->meas24[5]); + printf(" f6:%.1f", gpx->meas24[6]); + } + printf(" "); } if (gpx->option.vbs) { if (gpx->sonde_typ & SNbit) { - printf(" (%s) ", gpx->sonde_id); + printf(" (%s", gpx->sonde_id); + if (gpx->option.vbs > 1 && *gpx->dfmtyp) printf(":%s", gpx->dfmtyp); + printf(") "); gpx->sonde_typ ^= SNbit; } } + printf("\n"); } - printf("\n"); - if (gpx->option.jsn && jsonout) + if (gpx->option.jsn && jsonout && gpx->sek < 60.0) { - // JSON Buffer to store sonde ID char json_sonde_id[] = "DFM-xxxxxxxx\0\0"; - ui8_t dfm_typ = (gpx->sonde_typ & 0xF); - switch ( dfm_typ ) { + ui8_t dfmXtyp = (gpx->sonde_typ & 0xF); + switch ( dfmXtyp ) { case 0: sprintf(json_sonde_id, "DFM-xxxxxxxx"); break; //json_sonde_id[0] = '\0'; case 6: sprintf(json_sonde_id, "DFM-%6X", gpx->SN6); break; // DFM-06 case 0xA: sprintf(json_sonde_id, "DFM-%6u", gpx->SN); break; // DFM-09 - // 0x7:PS-15?, 0xB:DFM-17? 0xC:DFM-09P? 0xD:DFM-17P? + // 0x7:PS-15?, 0xB:DFM-17? 0xC:DFM-09P?DFM-17TU? 0xD:DFM-17P? default : sprintf(json_sonde_id, "DFM-%6u", gpx->SN); } + // JSON frame counter: gpx->sec_gps , seconds since GPS (ignoring leap seconds, DFM=UTC) + // Print JSON blob // valid sonde_ID? printf("{ \"type\": \"%s\"", "DFM"); - printf(", \"frame\": %d, \"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f", - gpx->frnr, json_sonde_id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->horiV, gpx->dir, gpx->vertV); + printf(", \"frame\": %u, ", gpx->sec_gps); // gpx->frnr + printf("\"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f, \"sats\": %d", + json_sonde_id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->horiV, gpx->dir, gpx->vertV, gpx->gps.nSV); if (gpx->ptu_out >= 0xA && gpx->status[0] > 0) { // DFM>=09(P): Battery (STM32) printf(", \"batt\": %.2f", gpx->status[0]); } @@ -684,10 +846,21 @@ static int print_gpx(gpx_t *gpx) { float t = get_Temp(gpx); // ecc-valid temperature? if (t > -270.0) printf(", \"temp\": %.1f", t); } - if (dfm_typ > 0) printf(", \"subtype\": \"0x%1X\"", dfm_typ); + //if (dfmXtyp > 0) printf(", \"subtype\": \"0x%1X\"", dfmXtyp); + if (dfmXtyp > 0) { + printf(", \"subtype\": \"0x%1X", dfmXtyp); + if (*gpx->dfmtyp) printf(":%s", gpx->dfmtyp); + printf("\""); + } if (gpx->jsn_freq > 0) { printf(", \"freq\": %d", gpx->jsn_freq); } + + // Reference time/position + printf(", \"ref_datetime\": \"%s\"", "UTC" ); // {"GPS", "UTC"} GPS-UTC=leap_sec + printf(", \"ref_position\": \"%s\"", "GPS" ); // {"GPS", "MSL"} GPS=ellipsoid , MSL=geoid + printf(", \"diff_GPS_MSL\": %+.2f", -gpx->gps.dMSL ); // MSL = GPS + gps.dMSL + printf(" }\n"); printf("\n"); } diff --git a/demod/multi/lms6Xbase.c b/demod/multi/lms6Xbase.c index 048dca1..332e073 100644 --- a/demod/multi/lms6Xbase.c +++ b/demod/multi/lms6Xbase.c @@ -84,6 +84,7 @@ static ui8_t rs_sync[] = { 0x00, 0x58, 0xf3, 0x3f, 0xb8}; static char blk_syncbits[] = "0000000000000000""0000001101011101""0100100111000010""0100111111110010""0110100001101011"; static ui8_t frm_sync6[] = { 0x24, 0x54, 0x00, 0x00}; +//static ui8_t frm_sync6_05[] = { 0x24, 0x54, 0x00, 0x05}; static ui8_t frm_syncX[] = { 0x24, 0x46, 0x05, 0x00}; @@ -551,8 +552,8 @@ static int get_GPSlat(gpx_t *gpx) { for (i = 0; i < 4; i++) { gpslat |= gpslat_bytes[i] << (8*(3-i)); } - if (gpx->typ == 6) lat = gpslat / B60B60; - else /*typ==10*/ lat = gpslat / 1e7; + if ((gpx->typ & 0xFF) == 6) lat = gpslat / B60B60; + else /* gpx->typ == 10 */ lat = gpslat / 1e7; gpx->lat = lat; @@ -572,8 +573,8 @@ static int get_GPSlon(gpx_t *gpx) { gpslon |= gpslon_bytes[i] << (8*(3-i)); } - if (gpx->typ == 6) lon = gpslon / B60B60; - else /*typ==10*/ lon = gpslon / 1e7; + if ((gpx->typ & 0xFF) == 6) lon = gpslon / B60B60; + else /* gpx->typ == 10 */ lon = gpslon / 1e7; gpx->lon = lon; @@ -593,8 +594,8 @@ static int get_GPSalt(gpx_t *gpx) { gpsheight |= gpsheight_bytes[i] << (8*(3-i)); } - if (gpx->typ == 6) alt = gpsheight / 1000.0; - else /*typ==10*/ alt = gpsheight / 100.0; + if ((gpx->typ & 0xFF) == 6) alt = gpsheight / 1000.0; + else /* gpx->typ == 10 */ alt = gpsheight / 100.0; gpx->alt = alt; @@ -702,7 +703,7 @@ static int print_frame(gpx_t *gpx, int crc_err, int len) { get_GPSlat(gpx); get_GPSlon(gpx); err2 = get_GPSalt(gpx); - if (gpx->typ == 6) + if ((gpx->typ & 0xFF) == 6) { err1 = get_GPStime(gpx, crc_err); get_GPSvel24(gpx); @@ -739,18 +740,25 @@ static int print_frame(gpx_t *gpx, int crc_err, int len) { // Print JSON output required by auto_rx. if (crc_err==0) { // CRC-OK // UTC oder GPS? - char sntyp[] = "LMS6-"; - if (gpx->typ == 10) sntyp[3] = 'X'; + char sntyp[] = "LMS6-"; + char subtyp[] = "LMS6-403\0\0"; + if (gpx->typ == 10) { sntyp[3] = 'X'; subtyp[3] = 'X'; } + else if (gpx->typ == 0x0206) strcpy(subtyp, "LMS6-403-2"); printf("{ \"type\": \"%s\"", "LMS"); printf(", \"frame\": %d, \"id\": \"%s%d\", \"datetime\": \"", gpx->frnr, sntyp, gpx->sn ); //if (gpx->week > 0) printf("%04d-%02d-%02dT", gpx->jahr, gpx->monat, gpx->tag ); printf("%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f", gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV ); printf(", \"gpstow\": %d", gpx->gpstow ); - printf(", \"subtype\": \"%c\"", sntyp[3]); // "6":LMS6-403, "X":lms6X, "MK2A":LMS6-1680/Mk2a + printf(", \"subtype\": \"%s\"", subtyp); // "LMS6-403", "LMS6-403-2", "LMSX-403"; "MK2A":LMS6-1680/Mk2a if (gpx->jsn_freq > 0) { printf(", \"freq\": %d", gpx->jsn_freq); } + + // Reference time/position + printf(", \"ref_datetime\": \"%s\"", "GPS" ); // {"GPS", "UTC"} GPS-UTC=leap_sec + printf(", \"ref_position\": \"%s\"", "GPS" ); // {"GPS", "MSL"} GPS=ellipsoid , MSL=geoid + printf(" }\n"); printf("\n"); } @@ -781,10 +789,17 @@ static int frmsync_6(gpx_t *gpx, ui8_t block_bytes[], int blk_pos) { int j; while ( blk_pos-SYNC_LEN < FRM_LEN ) { + int sf6_00 = 0; + int sf6_05 = 0; gpx->sf6 = 0; - for (j = 0; j < 4; j++) gpx->sf6 += (block_bytes[blk_pos+j] == frm_sync6[j]); - if (gpx->sf6 == 4) { + for (j = 0; j < 3; j++) gpx->sf6 += (block_bytes[blk_pos+j] == frm_sync6[j]); + sf6_00 = gpx->sf6 + (block_bytes[blk_pos+3] == 0x00); + sf6_05 = gpx->sf6 + (block_bytes[blk_pos+3] == 0x05); + if (sf6_00 == 4 || sf6_05 == 4) { + gpx->sf6 = 4; gpx->frm_pos = 0; + gpx->typ = 6; + if (sf6_05 == 4) gpx->typ |= 0x0200; break; } blk_pos++; @@ -854,7 +869,7 @@ static void proc_frame(gpx_t *gpx, int len, dsp_t *dsp) { blk_pos = SYNC_LEN; - if (gpx->typ == 6) + if ((gpx->typ & 0xFF) == 6) { if (gpx->option.ecc) { for (j = 0; j < rs_N; j++) rs_cw[rs_N-1-j] = block_bytes[SYNC_LEN+j]; @@ -908,11 +923,20 @@ static void proc_frame(gpx_t *gpx, int len, dsp_t *dsp) { if (gpx->sfX < 4) { //blk_pos = SYNC_LEN; while ( blk_pos-SYNC_LEN < FRM_LEN ) { + int sf6_00 = 0; + int sf6_05 = 0; gpx->sf6 = 0; - for (j = 0; j < 4; j++) gpx->sf6 += (block_bytes[blk_pos+j] == frm_sync6[j]); - if (gpx->sf6 == 4) { + for (j = 0; j < 3; j++) gpx->sf6 += (block_bytes[blk_pos+j] == frm_sync6[j]); + sf6_00 = gpx->sf6 + (block_bytes[blk_pos+3] == 0x00); + sf6_05 = gpx->sf6 + (block_bytes[blk_pos+3] == 0x05); + if (sf6_00 == 4 || sf6_05 == 4) { + gpx->sf6 = 4; gpx->frm_pos = 0; - if (gpx->auto_detect) { gpx->typ = 6; gpx->reset_dsp = 1; } + if (gpx->auto_detect) { + gpx->reset_dsp = 1; + gpx->typ = 6; + if (sf6_05 == 4) gpx->typ |= 0x0200; + } break; } blk_pos++; @@ -922,7 +946,11 @@ static void proc_frame(gpx_t *gpx, int len, dsp_t *dsp) { // LMS6: frm_rate = 4800.0 * FRAME_LEN/BLOCK_LEN = 4800*300/260 = 5538 // LMSX: delta_mp = 4797.8 (longer timesync-frames possible) if (gpx->frm_rate > 5000.0 || gpx->frm_rate < 4000.0) { // lms6-blocklen = 260/300 sr, sync wird ueberlesen ... - if (gpx->auto_detect) { gpx->typ = 6; gpx->reset_dsp = 1; } + if (gpx->auto_detect) { + gpx->reset_dsp = 1; + gpx->typ = 6; + //if (sf6_05 == 4) gpx->typ |= 0x0200; + } } } else @@ -1184,7 +1212,7 @@ void *thd_lms6X(void *targs) { // pcm_t *pcm, double xlt_fq bitofs = bitofsX + shift; } - if (gpx->typ == 6) { + if ((gpx->typ & 0xFF) == 6) { // set lms6 rawbitblock_len = RAWBITBLOCK_LEN_6; dsp.br = (float)BAUD_RATE6; diff --git a/demod/multi/m10base.c b/demod/multi/m10base.c index 3bb9a4e..1afc4a6 100644 --- a/demod/multi/m10base.c +++ b/demod/multi/m10base.c @@ -27,13 +27,14 @@ typedef struct { i8_t vbs; // verbose output i8_t raw; // raw frames i8_t crc; // CRC check output - i8_t ecc; // Reed-Solomon ECC + i8_t ecc; // M10/M20: no ECC i8_t sat; // GPS sat data i8_t ptu; // PTU: temperature i8_t inv; i8_t aut; i8_t col; // colors i8_t jsn; // JSON output (auto_rx) + i8_t slt; // silent (only raw/json) } option_t; @@ -88,6 +89,7 @@ typedef struct { ui8_t numSV; ui8_t utc_ofs; char SN[12]; + ui8_t SNraw[5]; ui8_t frame_bytes[FRAME_LEN+AUX_LEN+4]; char frame_bits[BITFRAME_LEN+BITAUX_LEN+8]; int auxlen; // 0 .. 0x76-0x64 @@ -449,19 +451,17 @@ static int get_GPSvel(gpx_t *gpx) { static int get_SN(gpx_t *gpx) { int i; unsigned byte; - ui8_t sn_bytes[5]; for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0'; for (i = 0; i < 5; i++) { - byte = gpx->frame_bytes[pos_SN + i]; - sn_bytes[i] = byte; + gpx->SNraw[i] = gpx->frame_bytes[pos_SN + i]; } - byte = sn_bytes[2]; + byte = gpx->SNraw[2]; sprintf(gpx->SN, "%1X%02u", (byte>>4)&0xF, byte&0xF); - byte = sn_bytes[3] | (sn_bytes[4]<<8); - sprintf(gpx->SN+3, " %1X %1u%04u", sn_bytes[0]&0xF, (byte>>13)&0x7, byte&0x1FFF); + byte = gpx->SNraw[3] | (gpx->SNraw[4]<<8); + sprintf(gpx->SN+3, " %1X %1u%04u", gpx->SNraw[0]&0xF, (byte>>13)&0x7, byte&0x1FFF); return 0; } @@ -646,7 +646,7 @@ static float get_Temp(gpx_t *gpx) { // [ 30.0 , 4.448 ] // [ 35.0 , 3.704 ] // [ 40.0 , 3.100 ] -// -> Steinhart–Hart coefficients (polyfit): +// -> Steinhart-Hart coefficients (polyfit): float p0 = 1.07303516e-03, p1 = 2.41296733e-04, p2 = 2.26744154e-06, @@ -742,7 +742,7 @@ static float get_Tntc2(gpx_t *gpx) { // float R25 = 2.2e3; // float b = 3650.0; // B/Kelvin // float T25 = 25.0 + 273.15; // T0=25C, R0=R25=5k -// -> Steinhart–Hart coefficients (polyfit): +// -> Steinhart-Hart coefficients (polyfit): float p0 = 4.42606809e-03, p1 = -6.58184309e-04, p2 = 8.95735557e-05, @@ -867,85 +867,88 @@ static int print_pos(gpx_t *gpx, int csOK) { gpx->_RH = get_RH(gpx); gpx->Ti = get_intTemp(gpx); gpx->batV = get_BatV(gpx); + get_SN(gpx); - if (gpx->option.col) { - fprintf(stdout, col_TXT); - if (gpx->type == t_M10) - { - if (gpx->option.vbs >= 3) fprintf(stdout, " (W "col_GPSweek"%d"col_TXT") ", gpx->week); - fprintf(stdout, col_GPSTOW"%s"col_TXT" ", weekday[gpx->wday]); + + if ( !gpx->option.slt ) + { + if (gpx->option.col) { + fprintf(stdout, col_TXT); + if (gpx->type == t_M10) + { + if (gpx->option.vbs >= 3) fprintf(stdout, " (W "col_GPSweek"%d"col_TXT") ", gpx->week); + fprintf(stdout, col_GPSTOW"%s"col_TXT" ", weekday[gpx->wday]); + } + fprintf(stdout, col_GPSdate"%04d-%02d-%02d"col_TXT" "col_GPSTOW"%02d:%02d:%06.3f"col_TXT" ", + gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek); + fprintf(stdout, " lat: "col_GPSlat"%.5f"col_TXT" ", gpx->lat); + fprintf(stdout, " lon: "col_GPSlon"%.5f"col_TXT" ", gpx->lon); + fprintf(stdout, " alt: "col_GPSalt"%.2f"col_TXT" ", gpx->alt); + if (!err2) { + //if (gpx->option.vbs == 2) fprintf(stdout, " "col_GPSvel"(%.1f , %.1f : %.1f)"col_TXT" ", gpx->vx, gpx->vy, gpx->vD2); + fprintf(stdout, " vH: "col_GPSvel"%.1f"col_TXT" D: "col_GPSvel"%.1f"col_TXT" vV: "col_GPSvel"%.1f"col_TXT" ", gpx->vH, gpx->vD, gpx->vV); + } + if (gpx->option.vbs >= 2) { + fprintf(stdout, " SN: "col_SN"%s"col_TXT, gpx->SN); + } + if (gpx->option.vbs >= 2) { + fprintf(stdout, " # "); + if (csOK) fprintf(stdout, " "col_CSok"[OK]"col_TXT); + else fprintf(stdout, " "col_CSno"[NO]"col_TXT); + } + if (gpx->option.ptu && csOK) { + if (gpx->T > -270.0) fprintf(stdout, " T=%.1fC", gpx->T); + if (gpx->option.vbs >= 2) { if (gpx->_RH > -0.5) fprintf(stdout, " _RH=%.0f%%", gpx->_RH); } + if (gpx->option.vbs >= 3) { + float t2 = get_Tntc2(gpx); + float fq555 = get_TLC555freq(gpx); + fprintf(stdout, " (Ti:%.1fC)", gpx->Ti); + if (t2 > -270.0) fprintf(stdout, " (T2:%.1fC) (%.3fkHz)", t2, fq555/1e3); + } + } + if (gpx->option.vbs >= 3 && csOK) { + fprintf(stdout, " (bat:%.2fV)", gpx->batV); + } + fprintf(stdout, ANSI_COLOR_RESET""); } - fprintf(stdout, col_GPSdate"%04d-%02d-%02d"col_TXT" "col_GPSTOW"%02d:%02d:%06.3f"col_TXT" ", - gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek); - fprintf(stdout, " lat: "col_GPSlat"%.5f"col_TXT" ", gpx->lat); - fprintf(stdout, " lon: "col_GPSlon"%.5f"col_TXT" ", gpx->lon); - fprintf(stdout, " alt: "col_GPSalt"%.2f"col_TXT" ", gpx->alt); - if (!err2) { - //if (gpx->option.vbs == 2) fprintf(stdout, " "col_GPSvel"(%.1f , %.1f : %.1f)"col_TXT" ", gpx->vx, gpx->vy, gpx->vD2); - fprintf(stdout, " vH: "col_GPSvel"%.1f"col_TXT" D: "col_GPSvel"%.1f"col_TXT" vV: "col_GPSvel"%.1f"col_TXT" ", gpx->vH, gpx->vD, gpx->vV); - } - if (gpx->option.vbs >= 2) { - get_SN(gpx); - fprintf(stdout, " SN: "col_SN"%s"col_TXT, gpx->SN); - } - if (gpx->option.vbs >= 2) { - fprintf(stdout, " # "); - if (csOK) fprintf(stdout, " "col_CSok"[OK]"col_TXT); - else fprintf(stdout, " "col_CSno"[NO]"col_TXT); - } - if (gpx->option.ptu && csOK) { - if (gpx->T > -270.0) fprintf(stdout, " T=%.1fC", gpx->T); - if (gpx->option.vbs >= 2) { if (gpx->_RH > -0.5) fprintf(stdout, " _RH=%.0f%%", gpx->_RH); } - if (gpx->option.vbs >= 3) { - float t2 = get_Tntc2(gpx); - float fq555 = get_TLC555freq(gpx); - fprintf(stdout, " (Ti:%.1fC)", gpx->Ti); - if (t2 > -270.0) fprintf(stdout, " (T2:%.1fC) (%.3fkHz)", t2, fq555/1e3); + else { + if (gpx->type == t_M10) + { + if (gpx->option.vbs >= 3) fprintf(stdout, " (W %d) ", gpx->week); + fprintf(stdout, "%s ", weekday[gpx->wday]); + } + fprintf(stdout, "%04d-%02d-%02d %02d:%02d:%06.3f ", + gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek); + fprintf(stdout, " lat: %.5f ", gpx->lat); + fprintf(stdout, " lon: %.5f ", gpx->lon); + fprintf(stdout, " alt: %.2f ", gpx->alt); + if (!err2) { + //if (gpx->option.vbs == 2) fprintf(stdout, " (%.1f , %.1f : %.1f) ", gpx->vx, gpx->vy, gpx->vD2); + fprintf(stdout, " vH: %.1f D: %.1f vV: %.1f ", gpx->vH, gpx->vD, gpx->vV); + } + if (gpx->option.vbs >= 2) { + fprintf(stdout, " SN: %s", gpx->SN); + } + if (gpx->option.vbs >= 2) { + fprintf(stdout, " # "); + if (csOK) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]"); + } + if (gpx->option.ptu && csOK) { + if (gpx->T > -270.0) fprintf(stdout, " T=%.1fC", gpx->T); + if (gpx->option.vbs >= 2) { if (gpx->_RH > -0.5) fprintf(stdout, " _RH=%.0f%%", gpx->_RH); } + if (gpx->option.vbs >= 3) { + float t2 = get_Tntc2(gpx); + float fq555 = get_TLC555freq(gpx); + fprintf(stdout, " (Ti:%.1fC)", gpx->Ti); + if (t2 > -270.0) fprintf(stdout, " (T2:%.1fC) (%.3fkHz)", t2, fq555/1e3); + } + } + if (gpx->option.vbs >= 3 && csOK) { + fprintf(stdout, " (bat:%.2fV)", gpx->batV); } } - if (gpx->option.vbs >= 3 && csOK) { - fprintf(stdout, " (bat:%.2fV)", gpx->batV); - } - fprintf(stdout, ANSI_COLOR_RESET""); + fprintf(stdout, "\n"); } - else { - if (gpx->type == t_M10) - { - if (gpx->option.vbs >= 3) fprintf(stdout, " (W %d) ", gpx->week); - fprintf(stdout, "%s ", weekday[gpx->wday]); - } - fprintf(stdout, "%04d-%02d-%02d %02d:%02d:%06.3f ", - gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek); - fprintf(stdout, " lat: %.5f ", gpx->lat); - fprintf(stdout, " lon: %.5f ", gpx->lon); - fprintf(stdout, " alt: %.2f ", gpx->alt); - if (!err2) { - //if (gpx->option.vbs == 2) fprintf(stdout, " (%.1f , %.1f : %.1f) ", gpx->vx, gpx->vy, gpx->vD2); - fprintf(stdout, " vH: %.1f D: %.1f vV: %.1f ", gpx->vH, gpx->vD, gpx->vV); - } - if (gpx->option.vbs >= 2) { - get_SN(gpx); - fprintf(stdout, " SN: %s", gpx->SN); - } - if (gpx->option.vbs >= 2) { - fprintf(stdout, " # "); - if (csOK) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]"); - } - if (gpx->option.ptu && csOK) { - if (gpx->T > -270.0) fprintf(stdout, " T=%.1fC", gpx->T); - if (gpx->option.vbs >= 2) { if (gpx->_RH > -0.5) fprintf(stdout, " _RH=%.0f%%", gpx->_RH); } - if (gpx->option.vbs >= 3) { - float t2 = get_Tntc2(gpx); - float fq555 = get_TLC555freq(gpx); - fprintf(stdout, " (Ti:%.1fC)", gpx->Ti); - if (t2 > -270.0) fprintf(stdout, " (T2:%.1fC) (%.3fkHz)", t2, fq555/1e3); - } - } - if (gpx->option.vbs >= 3 && csOK) { - fprintf(stdout, " (bat:%.2fV)", gpx->batV); - } - } - fprintf(stdout, "\n"); if (gpx->option.jsn) { @@ -986,8 +989,11 @@ static int print_pos(gpx_t *gpx, int csOK) { fprintf(stdout, "{ \"type\": \"%s\"", "M10"); fprintf(stdout, ", \"frame\": %lu, ", (unsigned long)(sec_gps0+0.5)); - fprintf(stdout, "\"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f, \"sats\": %d", - sn_id, utc_jahr, utc_monat, utc_tag, utc_std, utc_min, utc_sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV, gpx->numSV); + fprintf(stdout, "\"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f", + sn_id, utc_jahr, utc_monat, utc_tag, utc_std, utc_min, utc_sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV); + if (gpx->type == t_M10) { + fprintf(stdout, ", \"sats\": %d", gpx->numSV); + } // APRS id, 9 characters aprs_id[0] = gpx->frame_bytes[pos_SN+2]; aprs_id[1] = gpx->frame_bytes[pos_SN] & 0xF; @@ -1002,10 +1008,18 @@ static int print_pos(gpx_t *gpx, int csOK) { if (gpx->_RH > -0.5) fprintf(stdout, ", \"humidity\": %.1f", gpx->_RH); } } + fprintf(stdout, ", \"rawid\": \"M10_%02X%02X%02X%02X%02X\"", gpx->frame_bytes[pos_SN], gpx->frame_bytes[pos_SN+1], + gpx->frame_bytes[pos_SN+2], gpx->frame_bytes[pos_SN+3], gpx->frame_bytes[pos_SN+4]); // gpx->type fprintf(stdout, ", \"subtype\": \"0x%02X\"", gpx->type); if (gpx->jsn_freq > 0) { fprintf(stdout, ", \"freq\": %d", gpx->jsn_freq); } + + // Reference time/position (M10 time ref UTC only for json) + fprintf(stdout, ", \"ref_datetime\": \"%s\"", "UTC" ); // {"GPS", "UTC"} GPS-UTC=leap_sec + fprintf(stdout, ", \"ref_position\": \"%s\"", "GPS" ); // {"GPS", "MSL"} GPS=ellipsoid , MSL=geoid + fprintf(stdout, ", \"gpsutc_leapsec\": %d", gpx->utc_ofs); // GPS-UTC offset, utc_s = gpx->gpssec - gpx->utc_ofs; + fprintf(stdout, " }\n"); fprintf(stdout, "\n"); } @@ -1088,7 +1102,9 @@ static int print_frame(gpx_t *gpx, int pos, dsp_t *dsp) { } fprintf(stdout, "\n"); } - + if (gpx->option.slt /*&& gpx->option.jsn*/) { + print_pos(gpx, cs1 == cs2); + } } else if (gpx->frame_bytes[1] == 0x49) { if (gpx->option.vbs == 3) { diff --git a/demod/multi/rs41base.c b/demod/multi/rs41base.c index d40def2..af9936a 100644 --- a/demod/multi/rs41base.c +++ b/demod/multi/rs41base.c @@ -45,7 +45,7 @@ typedef struct { i8_t inv; i8_t aut; i8_t jsn; // JSON output (auto_rx) - i8_t slt; // silent + i8_t slt; // silent (only raw/json) } option_t; typedef struct { @@ -537,7 +537,7 @@ static float get_T(gpx_t *gpx, ui32_t f, ui32_t f1, ui32_t f2, float *ptu_co, fl // (data:) ftp://ftp-cdc.dwd.de/climate_environment/CDC/observations_germany/radiosondes/ // (diffAlt: Ellipsoid-Geoid) // (note: humidity sensor has significant time-lag at low temperatures) -static float get_RH(gpx_t *gpx, ui32_t f, ui32_t f1, ui32_t f2, float T) { +static float get_RHemp(gpx_t *gpx, ui32_t f, ui32_t f1, ui32_t f2, float T) { float a0 = 7.5; // empirical float a1 = 350.0/gpx->ptu_calH[0]; // empirical float fh = (f-f1)/(float)(f2-f1); @@ -758,7 +758,7 @@ static int get_PTU(gpx_t *gpx, int ofs, int pck, int valid_alt) { gpx->TH = TH; if (bH && Tc > -273.0) { - RH = get_RH(gpx, meas[3], meas[4], meas[5], Tc); // TH, TH-Tc (sensorT - T) + RH = get_RHemp(gpx, meas[3], meas[4], meas[5], Tc); // TH, TH-Tc (sensorT - T) } gpx->RH = RH; @@ -1021,7 +1021,7 @@ static int get_GPS3(gpx_t *gpx, int ofs) { static int get_Aux(gpx_t *gpx, int out, int pos) { // -// "Ozone Sounding with Vaisala Radiosonde RS41" user's guide +// "Ozone Sounding with Vaisala Radiosonde RS41" user's guide M211486EN // int auxlen, auxcrc, count7E, pos7E; int i, n; @@ -1589,6 +1589,16 @@ static int print_position(gpx_t *gpx, int ec) { if (gpx->freq > 0) fq_kHz = gpx->freq; fprintf(stdout, ", \"freq\": %d", fq_kHz); } + + // Include frequency derived from subframe information if available. + if (gpx->freq > 0) { + fprintf(stdout, ", \"tx_frequency\": %d", gpx->freq ); + } + + // Reference time/position + fprintf(stdout, ", \"ref_datetime\": \"%s\"", "GPS" ); // {"GPS", "UTC"} GPS-UTC=leap_sec + fprintf(stdout, ", \"ref_position\": \"%s\"", "GPS" ); // {"GPS", "MSL"} GPS=ellipsoid , MSL=geoid + fprintf(stdout, " }\n"); fprintf(stdout, "\n"); }