(test->master) dfm09/17: guess DFM subtype, check delta(diff(cnt,sec))

pull/47/head
Zilog80 2022-02-06 20:27:45 +01:00
rodzic 716496dd7b
commit d29b7af192
1 zmienionych plików z 452 dodań i 252 usunięć

Wyświetl plik

@ -34,6 +34,28 @@
#include "demod_mod.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
@ -75,14 +97,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"
hsbit_t frame[BITFRAME_LEN+4]; // char frame_bits[BITFRAME_LEN+4];
char dat_str[9][13+1];
@ -90,8 +117,11 @@ 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;
} gpx_t;
@ -434,24 +464,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]
@ -468,7 +500,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];
@ -476,7 +508,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
@ -494,7 +526,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);
}
@ -533,13 +565,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
@ -550,6 +582,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;
@ -571,17 +611,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
@ -595,10 +636,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:
@ -614,6 +656,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;
@ -628,19 +671,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;
@ -651,41 +692,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;
}
@ -721,6 +801,27 @@ static void 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) { // only ecc-valid/json diffs ?
jsonout = 0;
gpx->sonde_typ = 0;
reset_cfgchk(gpx);
}
gpx->prev_cntsec_diff = cntsec_diff;
}
}
if (output & 0xF000) {
if (gpx->option.raw == 2) {
@ -746,34 +847,45 @@ static void 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;
}
}
@ -793,26 +905,21 @@ static void print_gpx(gpx_t *gpx) {
if (gpx->option.jsn && jsonout && gpx->sek < 60.0)
{
char *ver_jsn = NULL;
unsigned long sec_gps = 0;
int week = 0;
int tow = 0;
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: seconds since GPS (ignoring leap seconds, DFM=UTC)
datetime2GPSweek(gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, (int)(gpx->sek+0.5), &week, &tow);
sec_gps = week*604800 + tow; // SECONDS_IN_WEEK=7*86400=604800
// 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\": %lu, ", sec_gps); // gpx->frnr
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)
@ -822,7 +929,12 @@ static void 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);
}
@ -863,7 +975,28 @@ static int print_frame(gpx_t *gpx) {
ret2 = hamming(gpx->option.ecc, hamming_dat2, 13, block_dat2);
ret = ret0 | ret1 | ret2;
if (gpx->option.raw == 1) {
if (gpx->option.raw == 9) {
int diff = 0;
for (i = 0; i < CONF; i++) {
diff += ( (gpx->frame[i].hb & 1) != (dfm_header[i] & 1) );
}
if (diff == 0)
{
ui8_t byte = 0;
printf("%c", gpx->option.inv?'-':'+');
printf("<%7.1f> ", gpx->_frmcnt);
for (i = CONF; i < BITFRAME_LEN; i++) {
if (i == DAT1 || i == DAT2) printf(" ");
byte |= (gpx->frame[i].hb&1)<<(i%4); // little endian
if (i % 4 == 3) {
printf("%1X", byte & 0xF);
byte = 0;
}
}
printf("\n");
}
}
else if (gpx->option.raw == 1) {
for (i = 0; i < 7; i++) {
nib = bits2val(block_conf+S*i, S);
@ -903,7 +1036,7 @@ static int print_frame(gpx_t *gpx) {
printf("\n");
}
if ( gpx->option.raw != 1 || gpx->option.jsn )
if ( (gpx->option.raw&1) != 1 || gpx->option.jsn )
{
if (gpx->option.ecc) {
@ -959,6 +1092,7 @@ int main(int argc, char **argv) {
int wavloaded = 0;
int sel_wavch = 0; // audio channel: left
int spike = 0;
int rawhex = 0;
int cfreq = -1;
FILE *fp = NULL;
@ -1026,6 +1160,9 @@ int main(int argc, char **argv) {
else if ( (strcmp(*argv, "-R") == 0) || (strcmp(*argv, "--RAW") == 0) ) {
option_raw = 2;
}
else if ( (strcmp(*argv, "--rawecc") == 0) ) {
option_raw = 9;
}
else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) {
option_inv = 0x1;
}
@ -1098,6 +1235,7 @@ int main(int argc, char **argv) {
}
else if (strcmp(*argv, "--dbg") == 0) { gpx.option.dbg = 1; }
else if (strcmp(*argv, "--sat") == 0) { gpx.option.sat = 1; }
else if (strcmp(*argv, "--rawhex") == 0) { rawhex = 1; } // raw hex input
else if (strcmp(*argv, "-") == 0) {
int sample_rate = 0, bits_sample = 0, channels = 0;
++argv;
@ -1182,196 +1320,258 @@ int main(int argc, char **argv) {
}
#endif
if (!option_bin && !option_softin) {
if (option_iq == 0 && option_pcmraw) {
fclose(fp);
fprintf(stderr, "error: raw data not IQ\n");
return -1;
}
if (option_iq) sel_wavch = 0;
if (!rawhex) {
pcm.sel_ch = sel_wavch;
if (option_pcmraw == 0) {
k = read_wav_header(&pcm, fp);
if ( k < 0 ) {
if (!option_bin && !option_softin) {
if (option_iq == 0 && option_pcmraw) {
fclose(fp);
fprintf(stderr, "error: wav header\n");
fprintf(stderr, "error: raw data not IQ\n");
return -1;
}
if (option_iq) sel_wavch = 0;
pcm.sel_ch = sel_wavch;
if (option_pcmraw == 0) {
k = read_wav_header(&pcm, fp);
if ( k < 0 ) {
fclose(fp);
fprintf(stderr, "error: wav header\n");
return -1;
}
}
if (cfreq > 0) {
int fq_kHz = (cfreq - dsp.xlt_fq*pcm.sr + 500)/1e3;
gpx.jsn_freq = fq_kHz;
}
// dfm: BT=1?, h=2.4?
symlen = 2;
// init dsp
//
dsp.fp = fp;
dsp.sr = pcm.sr;
dsp.bps = pcm.bps;
dsp.nch = pcm.nch;
dsp.ch = pcm.sel_ch;
dsp.br = (float)BAUD_RATE;
dsp.sps = (float)dsp.sr/dsp.br;
dsp.symlen = symlen;
dsp.symhd = symlen;
dsp._spb = dsp.sps*symlen;
dsp.hdr = dfm_rawheader;
dsp.hdrlen = strlen(dfm_rawheader);
dsp.BT = 0.5; // bw/time (ISI) // 0.3..0.5
dsp.h = 1.8; // 2.4 modulation index abzgl. BT
dsp.opt_iq = option_iq;
dsp.opt_iqdc = option_iqdc;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = lpIQ_bw; // 12e3; // IF lowpass bandwidth
dsp.lpFM_bw = 4e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 8 ) {
fprintf(stderr, "note: sample rate low\n");
}
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
}
bitofs += shift;
}
else {
if (option_bin && option_softin) option_bin = 0;
// init circular header bit buffer
hdb.hdr = dfm_rawheader;
hdb.len = strlen(dfm_rawheader);
hdb.thb = 1.0 - 2.1/(float)hdb.len; // 1.0-max_bit_errors/hdrlen // max 1.1 !!
hdb.bufpos = -1;
hdb.buf = calloc(hdb.len, sizeof(char));
if (hdb.buf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
hdb.ths = 0.7; // caution/test false positive
hdb.sbuf = calloc(hdb.len, sizeof(float));
if (hdb.sbuf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
}
if (cfreq > 0) {
int fq_kHz = (cfreq - dsp.xlt_fq*pcm.sr + 500)/1e3;
gpx.jsn_freq = fq_kHz;
}
// dfm: BT=1?, h=2.4?
symlen = 2;
// init dsp
//
dsp.fp = fp;
dsp.sr = pcm.sr;
dsp.bps = pcm.bps;
dsp.nch = pcm.nch;
dsp.ch = pcm.sel_ch;
dsp.br = (float)BAUD_RATE;
dsp.sps = (float)dsp.sr/dsp.br;
dsp.symlen = symlen;
dsp.symhd = symlen;
dsp._spb = dsp.sps*symlen;
dsp.hdr = dfm_rawheader;
dsp.hdrlen = strlen(dfm_rawheader);
dsp.BT = 0.5; // bw/time (ISI) // 0.3..0.5
dsp.h = 1.8; // 2.4 modulation index abzgl. BT
dsp.opt_iq = option_iq;
dsp.opt_iqdc = option_iqdc;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = lpIQ_bw; // 12e3; // IF lowpass bandwidth
dsp.lpFM_bw = 4e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 8 ) {
fprintf(stderr, "note: sample rate low\n");
}
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
}
bitofs += shift;
}
else {
if (option_bin && option_softin) option_bin = 0;
// init circular header bit buffer
hdb.hdr = dfm_rawheader;
hdb.len = strlen(dfm_rawheader);
hdb.thb = 1.0 - 2.1/(float)hdb.len; // 1.0-max_bit_errors/hdrlen // max 1.1 !!
hdb.bufpos = -1;
hdb.buf = calloc(hdb.len, sizeof(char));
if (hdb.buf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
hdb.ths = 0.7; // caution/test false positive
hdb.sbuf = calloc(hdb.len, sizeof(float));
if (hdb.sbuf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
}
while ( 1 )
{
if (option_bin) { // aka find_binrawhead()
header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits?
hdrcnt += nfrms;
}
else if (option_softin) {
header_found = find_softbinhead(fp, &hdb, &_mv);
hdrcnt += nfrms;
}
else { //2 (false positive) // FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
}
if (header_found == EOF) break;
// mv == correlation score
if (_mv *(0.5-gpx.option.inv) < 0) {
if (gpx.option.aut == 0) header_found = 0;
else gpx.option.inv ^= 0x1;
}
if (header_found)
while ( 1 )
{
bitpos = 0;
pos = headerlen;
pos /= 2;
if (option_bin) { // aka find_binrawhead()
header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits?
hdrcnt += nfrms;
}
else if (option_softin) {
header_found = find_softbinhead(fp, &hdb, &_mv);
hdrcnt += nfrms;
}
else { //2 (false positive) // FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
}
if (header_found == EOF) break;
//if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count
// mv == correlation score
if (_mv *(0.5-gpx.option.inv) < 0) {
if (gpx.option.aut == 0) header_found = 0;
else gpx.option.inv ^= 0x1;
}
frm = 0;
while ( frm < nfrms ) { // nfrms=1,2,4,8
if (option_bin || option_softin) {
gpx._frmcnt = hdrcnt + frm;
}
else {
gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm;
}
while ( pos < BITFRAME_LEN )
{
if (option_bin) {
// symbols or bits?
// manchester1 1->10,0->01: 1.bit (DFM-06)
// manchester2 0->10,1->01: 2.bit (DFM-09)
bitQ = fgetc(fp);
if (bitQ != EOF) {
hsbit.hb = bitQ & 0x1;
bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester)
if (bitQ != EOF) hsbit.hb = bitQ & 0x1; // 2.bit (DFM-09)
hsbit.sb = 2*hsbit.hb - 1;
}
}
else if (option_softin) {
float s1 = 0.0;
float s2 = 0.0;
float s = 0.0;
bitQ = f32soft_read(fp, &s1);
if (bitQ != EOF) {
bitQ = f32soft_read(fp, &s2);
if (bitQ != EOF) {
s = s2-s1; // integrate both symbols // only 2nd Manchester symbol: s2
hsbit.sb = s;
hsbit.hb = (s>=0.0);
}
}
if (header_found)
{
bitpos = 0;
pos = headerlen;
pos /= 2;
//if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count
frm = 0;
while ( frm < nfrms ) { // nfrms=1,2,4,8
if (option_bin || option_softin) {
gpx._frmcnt = hdrcnt + frm;
}
else {
float bl = -1;
if (option_iq >= 2) spike = 0;
if (option_iq > 2) bl = 4.0;
bitQ = read_softbit(&dsp, &hsbit, 0, bitofs, bitpos, bl, spike); // symlen=2
// optional:
// normalize soft bit s_j by
// rhsbit.sb /= dsp._spb+1; // all samples in [-1,+1]
gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm;
}
if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF
while ( pos < BITFRAME_LEN )
{
if (option_bin) {
// symbols or bits?
// manchester1 1->10,0->01: 1.bit (DFM-06)
// manchester2 0->10,1->01: 2.bit (DFM-09)
bitQ = fgetc(fp);
if (bitQ != EOF) {
hsbit.hb = bitQ & 0x1;
bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester)
if (bitQ != EOF) hsbit.hb = bitQ & 0x1; // 2.bit (DFM-09)
hsbit.sb = 2*hsbit.hb - 1;
}
}
else if (option_softin) {
float s1 = 0.0;
float s2 = 0.0;
float s = 0.0;
bitQ = f32soft_read(fp, &s1);
if (bitQ != EOF) {
bitQ = f32soft_read(fp, &s2);
if (bitQ != EOF) {
s = s2-s1; // integrate both symbols // only 2nd Manchester symbol: s2
hsbit.sb = s;
hsbit.hb = (s>=0.0);
}
}
}
else {
float bl = -1;
if (option_iq >= 2) spike = 0;
if (option_iq > 2) bl = 4.0;
bitQ = read_softbit(&dsp, &hsbit, 0, bitofs, bitpos, bl, spike); // symlen=2
// optional:
// normalize soft bit s_j by
// rhsbit.sb /= dsp._spb+1; // all samples in [-1,+1]
}
if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF
if (gpx.option.inv) {
hsbit.hb ^= 1;
hsbit.sb = -hsbit.sb;
if (gpx.option.inv) {
hsbit.hb ^= 1;
hsbit.sb = -hsbit.sb;
}
gpx.frame[pos] = hsbit;
pos++;
bitpos += 1;
}
gpx.frame[pos] = hsbit;
pos++;
bitpos += 1;
if (pos < BITFRAME_LEN) break;
ret = print_frame(&gpx);
pos = 0;
frm += 1;
//if (ret < 0) frms += 1;
}
ret = print_frame(&gpx);
if (pos < BITFRAME_LEN) break;
pos = 0;
frm += 1;
//if (ret < 0) frms += 1;
}
header_found = 0;
pos = headerlen;
}
header_found = 0;
pos = headerlen;
if (!option_bin && !option_softin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
}
else //if (rawhex)
{
#define BUFLEN (BITFRAME_LEN/4+12)
char buffer_rawhex[BUFLEN+1]; // no header
char *pbuf = NULL;
int len, i, j;
int ch = 0;
int pos = 0;
float _frmcnt = -1.0f;
memset(buffer_rawhex, BUFLEN+1, 0);
while ( (ch=fgetc(fp)) != EOF)
{
if (ch == ' ') continue;
if (ch == '\n') {
buffer_rawhex[pos] = '\0';
//
// +/-<gpx._frmcnt> gpx.frame[].hb ...
//
gpx.option.inv = buffer_rawhex[0]=='-' ? 1 : 0;
sscanf(buffer_rawhex+1, "<%f>", &_frmcnt);
pbuf = strchr(buffer_rawhex, '>');
if (pbuf != NULL)
{
pbuf++;
len = strlen(pbuf);
if (len*4 == BITFRAME_LEN-CONF) {
gpx._frmcnt = _frmcnt;
for (i = 0; i < len; i++) {
ui8_t nib = 0xFF;
sscanf(pbuf+i, "%1hhx", &nib);
for (j = 0; j < 4; j++) {
gpx.frame[CONF+4*i+j].hb = (nib>>j) & 0x1; // little endian
gpx.frame[CONF+4*i+j].sb = 2*gpx.frame[CONF+4*i+j].hb - 1;
}
}
print_frame(&gpx);
}
}
pos = 0;
}
else {
if ( ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F'
|| ch == '+' || ch == '-' || ch == '<' || ch == '.' || ch == '>') {
if (pos < BUFLEN) {
buffer_rawhex[pos] = ch;
pos++;
}
}
else {
// frame error
}
}
}
}
if (!option_bin && !option_softin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
fclose(fp);
return 0;