Merge pull request #283 from darksidelemm/testing

Add M20 decoder for testing.
pull/291/head
Mark Jessop 2020-06-27 11:18:35 +09:30 zatwierdzone przez GitHub
commit 9c4441bfc9
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 265 dodań i 115 usunięć

Wyświetl plik

@ -468,7 +468,7 @@ def telemetry_filter(telemetry):
meisei_callsign_valid = False
# If Vaisala or DFMs, check the callsigns are valid. If M10, iMet or LMS6, just pass it through.
if vaisala_callsign_valid or dfm_callsign_valid or meisei_callsign_valid or ('M10' in telemetry['type']) or ('LMS' in telemetry['type']) or ('IMET' in telemetry['type']):
if vaisala_callsign_valid or dfm_callsign_valid or meisei_callsign_valid or ('M10' in telemetry['type']) or ('M20' in telemetry['type']) or ('LMS' in telemetry['type']) or ('IMET' in telemetry['type']):
return "OK"
else:
_id_msg = "Payload ID %s is invalid." % telemetry['id']

Wyświetl plik

@ -17,7 +17,7 @@ except ImportError:
# MINOR - New sonde type support, other fairly big changes that may result in telemetry or config file incompatability issus.
# PATCH - Small changes, or minor feature additions.
__version__ = "1.3.2-beta6"
__version__ = "1.3.2-beta7"
# Global Variables

Wyświetl plik

@ -21,7 +21,7 @@ from .sonde_specific import *
from .fsk_demod import FSKDemodStats
# Global valid sonde types list.
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'IMET', 'MK2LMS', 'LMS6', 'MEISEI', 'UDP']
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'M20', 'IMET', 'MK2LMS', 'LMS6', 'MEISEI', 'UDP']
# Known 'Drifty' Radiosonde types
# NOTE: Due to observed adjacent channel detections of RS41s, the adjacent channel decoder restriction
@ -70,7 +70,7 @@ class SondeDecoder(object):
}
# TODO: Use the global valid sonde type list.
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'IMET', 'MK2LMS', 'LMS6', 'MEISEI', 'UDP']
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'M20', 'IMET', 'MK2LMS', 'LMS6', 'MEISEI', 'UDP']
def __init__(self,
sonde_type="None",
@ -580,6 +580,31 @@ class SondeDecoder(object):
demod_stats = FSKDemodStats(averaging_time=2.0, peak_hold=True)
self.rx_frequency = _freq
elif self.sonde_type == "M20":
# M20 Sondes
# 9600 baud.
_sdr_rate = 48000
_baud_rate = 9600
_offset = 0.25 # Place the sonde frequency in the centre of the passband.
_lower = int(0.025 * _sdr_rate) # Limit the frequency estimation window to not include the passband edges.
_upper = int(0.475 * _sdr_rate)
_freq = int(self.sonde_freq - _sdr_rate*_offset)
demod_cmd = "%s %s-p %d -d %s %s-M raw -F9 -s %d -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, _sdr_rate, _freq)
# Add in tee command to save IQ to disk if debugging is enabled.
if self.save_decode_iq:
demod_cmd += " tee decode_IQ_%s.bin |" % str(self.device_idx)
demod_cmd += "./fsk_demod --cs16 -b %d -u %d -s -p 5 --stats=%d 2 %d %d - -" % (_lower, _upper, _stats_rate, _sdr_rate, _baud_rate)
# M20 decoder
decode_cmd = "./mXXmod --json --ptu -vvv --softin -i 2>/dev/null"
# M20 sondes transmit in short, irregular pulses - average over the last 2 frames, and use a peak hold
demod_stats = FSKDemodStats(averaging_time=2.0, peak_hold=True)
self.rx_frequency = _freq
elif self.sonde_type.startswith("LMS"):
# LMS6 (400 MHz variant) Decoder command.
_sdr_rate = 48000 # IQ rate. Lower rate = lower CPU usage, but less frequency tracking ability.

Wyświetl plik

@ -10,7 +10,7 @@ echo "Building dft_detect"
cd ../scan/
gcc dft_detect.c -lm -o dft_detect -DNOC34C50
echo "Building RS92/RS41/DFM/LMS6/iMS Demodulators"
echo "Building RS92/RS41/DFM/LMS6/iMS/M10/M20 Demodulators"
#cd ../demod/
#gcc -c demod.c
#gcc -c demod_dft.c
@ -65,6 +65,7 @@ cp ../mk2a/mk2a_lms1680 .
cp ../demod/mod/rs41mod .
cp ../demod/mod/dfm09mod .
cp ../demod/mod/m10mod .
cp ../demod/mod/mXXmod .
cp ../demod/mod/rs92mod .
cp ../demod/mod/lms6Xmod .
cp ../demod/mod/meisei100mod .

Wyświetl plik

@ -772,8 +772,8 @@ static void print_gpx(gpx_t *gpx) {
// 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\": %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, \"sats\": %d",
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, gpx->gps.nSV);
if (gpx->ptu_out >= 0xA && gpx->status[0] > 0) { // DFM>=09(P): Battery (STM32)
printf(", \"batt\": %.2f", gpx->status[0]);
}
@ -926,6 +926,8 @@ int main(int argc, char **argv) {
float thres = 0.65;
float _mv = 0.0;
float lpIQ_bw = 12e3;
int symlen = 2;
int bitofs = 2; // +1 .. +2
int shift = 0;
@ -1023,6 +1025,14 @@ int main(int argc, char **argv) {
option_min = 1;
}
else if (strcmp(*argv, "--dbg") == 0) { gpx.option.dbg = 1; }
else if (strcmp(*argv, "--lpbw") == 0) { // IQ lowpass BW / kHz
double bw = 0.0;
++argv;
if (*argv) bw = atof(*argv);
else return -1;
if (bw > 4.6 && bw < 24.0) lpIQ_bw = bw*1e3;
option_lp = 1;
}
else if (strcmp(*argv, "--sat") == 0) { gpx.option.sat = 1; }
else if (strcmp(*argv, "-") == 0) {
int sample_rate = 0, bits_sample = 0, channels = 0;
@ -1138,7 +1148,7 @@ int main(int argc, char **argv) {
dsp.h = 1.8; // 2.4 modulation index abzgl. BT
dsp.opt_iq = option_iq;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = 12e3; // IF lowpass bandwidth
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;

Wyświetl plik

@ -89,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 +450,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;
}
@ -867,6 +866,7 @@ 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) {
@ -886,7 +886,6 @@ static int print_pos(gpx_t *gpx, int csOK) {
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) {
@ -925,7 +924,6 @@ static int print_pos(gpx_t *gpx, int csOK) {
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) {
@ -1003,6 +1001,8 @@ 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);
fprintf(stdout, " }\n");
fprintf(stdout, "\n");
@ -1401,7 +1401,7 @@ int main(int argc, char **argv) {
if (option_iq >= 2) spike = 0;
if (option_iq > 2) bl = 4.0;
//bitQ = read_slbit(&dsp, &bit, 0, bitofs, bitpos, bl, spike); // symlen=2
bitQ = read_softbit2p(&dsp, &hsbit, 0, bitofs, bitpos, bl, spike, &hsbit1); // symlen=1
bitQ = read_softbit2p(&dsp, &hsbit, 0, bitofs, bitpos, bl, spike, &hsbit1); // symlen=2
bit = hsbit.hb;
if (option_chk == 3 && option_iq) {
//if (hsbit.sb*hsbit1.sb < 0)

Wyświetl plik

@ -75,6 +75,11 @@ static char rawheader[] = "10011001100110010100110010011001";
#define BITAUX_LEN (AUX_LEN*BITS)
#define t_M2K2 0x8F
#define t_M10 0x9F
#define t_M10plus 0xAF
#define t_M20 0x20
typedef struct {
int week; int tow_ms; int gpssec;
int jahr; int monat; int tag;
@ -86,10 +91,12 @@ typedef struct {
ui8_t numSV;
ui8_t utc_ofs;
char SN[12];
ui8_t SNraw[3];
ui8_t frame_bytes[FRAME_LEN+AUX_LEN+4];
char frame_bits[BITFRAME_LEN+BITAUX_LEN+8];
int auxlen; // 0 .. 0x76-0x64
int auxlen; // ? 0 .. 0x57-0x45
option_t option;
ui8_t type;
} gpx_t;
@ -177,10 +184,9 @@ frame[0x1C..0x1F]: GPS latitude
frame[0x20..0x23]: GPS longitude
frame[0x44..0x45]: frame check
*/
#define stdFLEN 0x64 // pos[0]=0x45 // M20: 0x45 (0x43) M10: 0x64
#define stdFLEN 0x45 // pos[0]=0x45 // M20: 0x45 (0x43) M10: 0x64
#define pos_GPSTOW 0x0F // 3 byte
#define pos_GPSlat 0x1C // 4 byte
#define pos_GPSlon 0x20 // 4 byte
@ -372,21 +378,20 @@ static int get_GPSvel(gpx_t *gpx) {
ui8_t gpsVel_bytes[2];
short vel16;
double vx, vy, dir, alpha;
const double ms2kn100 = 1e2; //2e2; // m/s -> knots: 1 m/s = 3.6/1.852 kn = 1.94 kn
for (i = 0; i < 2; i++) {
byte = gpx->frame_bytes[pos_GPSvE + i];
gpsVel_bytes[i] = byte;
}
vel16 = gpsVel_bytes[0] << 8 | gpsVel_bytes[1];
vx = vel16 / ms2kn100; // ost
vx = vel16 / 1e2; // ost
for (i = 0; i < 2; i++) {
byte = gpx->frame_bytes[pos_GPSvN + i];
gpsVel_bytes[i] = byte;
}
vel16 = gpsVel_bytes[0] << 8 | gpsVel_bytes[1];
vy= vel16 / ms2kn100; // nord
vy= vel16 / 1e2; // nord
gpx->vx = vx;
gpx->vy = vy;
@ -406,11 +411,32 @@ static int get_GPSvel(gpx_t *gpx) {
gpsVel_bytes[i] = byte;
}
vel16 = gpsVel_bytes[0] << 8 | gpsVel_bytes[1];
gpx->vV = vel16 / ms2kn100;
gpx->vV = vel16 / 1e2;
return 0;
}
static int get_SN(gpx_t *gpx) {
int i;
ui8_t b0 = gpx->frame_bytes[pos_SN]; //0x12
ui32_t s2 = (gpx->frame_bytes[pos_SN+2]<<8) | gpx->frame_bytes[pos_SN+1];
ui8_t ym = b0 & 0x7F; // #{0x0,..,0x77}=120=10*12
ui8_t y = ym / 12;
ui8_t m = (ym % 12)+1; // there is b0=0x69<0x80 from 2018-09-19 ...
for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0';
for (i = 0; i < 3; i++) {
gpx->SNraw[i] = gpx->frame_bytes[pos_SN + i];
}
sprintf(gpx->SN, "%u%02u", y, m); // more samples needed
sprintf(gpx->SN+3, " %u ", (s2&0x3)+2); // (b0>>7)+1? (s2&0x3)+2?
sprintf(gpx->SN+6, "%u", (s2>>(2+13))&0x1); // ?(s2>>(2+13))&0x1 ?? (s2&0x3)?
sprintf(gpx->SN+7, "%04u", (s2>>2)&0x1FFF);
return 0;
}
/* -------------------------------------------------------------------------- */
/*
@ -518,17 +544,22 @@ static float get_Tntc0(gpx_t *gpx) {
static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
int err, err2;
err = 0;
err |= get_GPSweek(gpx);
err |= get_GPStime(gpx);
err |= get_GPSlat(gpx);
err |= get_GPSlon(gpx);
err |= get_GPSalt(gpx);
err2 = get_GPSvel(gpx);
if (1 || gpx->type == t_M20)
{
err = 0;
err |= get_GPSweek(gpx);
err |= get_GPStime(gpx);
err |= get_GPSlat(gpx);
err |= get_GPSlon(gpx);
err |= get_GPSalt(gpx);
err2 = get_GPSvel(gpx);
}
else err = 0xFF;
if (!err) {
Gps2Date(gpx->week, gpx->gpssec, &gpx->jahr, &gpx->monat, &gpx->tag);
get_SN(gpx);
if (gpx->option.col) {
fprintf(stdout, col_TXT);
@ -545,16 +576,8 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
if (!err2) {
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 >= 3 && (bcOK || csOK)) { // SN
ui8_t b0 = gpx->frame_bytes[pos_SN]; //0x12
ui32_t s2 = (gpx->frame_bytes[pos_SN+2]<<8) | gpx->frame_bytes[pos_SN+1];
ui8_t ym = b0 & 0x7F; // #{0x0,..,0x77}=120=10*12
ui8_t y = ym / 12;
ui8_t m = (ym % 12)+1; // there is b0=0x69<0x80 from 2018-09-19 ...
fprintf(stdout, " (%u%02u", y, m); // more samples needed
fprintf(stdout, " _ "); // (b0>>7)+1? (s2&0x3)+2?
fprintf(stdout, "_"); // ?(s2>>(2+13))&0x1 ?? (s2&0x3)?
fprintf(stdout, "%04u)", (s2>>2)&0x1FFF);
if (gpx->option.vbs >= 2 && (bcOK || csOK)) { // SN
fprintf(stdout, " SN: "col_SN"%s"col_TXT, gpx->SN);
}
if (gpx->option.vbs >= 2) {
fprintf(stdout, " # ");
@ -585,6 +608,9 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
if (!err2) {
fprintf(stdout, " vH: %.1f D: %.1f vV: %.1f ", gpx->vH, gpx->vD, gpx->vV);
}
if (gpx->option.vbs >= 2 && (bcOK || csOK)) { // SN
fprintf(stdout, " SN: %s", gpx->SN);
}
if (gpx->option.vbs >= 2) {
fprintf(stdout, " # ");
if (bcOK) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)");
@ -599,6 +625,27 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
}
fprintf(stdout, "\n");
if (gpx->option.jsn) {
// Print out telemetry data as JSON
if (csOK) {
int j;
char sn_id[4+12] = "M20-";
double sec_gps0 = (double)gpx->week*SECONDS_IN_WEEK + gpx->tow_ms/1e3;
strncpy(sn_id+4, gpx->SN, 12);
sn_id[15] = '\0';
for (j = 0; sn_id[j]; j++) { if (sn_id[j] == ' ') sn_id[j] = '-'; }
fprintf(stdout, "{ \"type\": \"%s\"", "M20");
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",
sn_id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV);
fprintf(stdout, ", \"rawid\": \"M20_%02X%02X%02X\"", gpx->frame_bytes[pos_SN], gpx->frame_bytes[pos_SN+1], gpx->frame_bytes[pos_SN+2]); // gpx->type
fprintf(stdout, ", \"subtype\": \"0x%02X\"", gpx->type);
fprintf(stdout, " }\n");
fprintf(stdout, "\n");
}
}
}
@ -617,7 +664,7 @@ static int print_frame(gpx_t *gpx, int pos) {
if (flen == stdFLEN) gpx->auxlen = 0;
else {
gpx->auxlen = flen - stdFLEN;
//if (gpx->auxlen < 0 || gpx->auxlen > AUX_LEN) gpx->auxlen = 0;
//if (gpx->auxlen < 0 || gpx->auxlen > AUX_LEN) gpx->auxlen = 0; // 0x43,0x45
}
cs1 = (gpx->frame_bytes[pos_Check+gpx->auxlen] << 8) | gpx->frame_bytes[pos_Check+gpx->auxlen+1];
@ -626,11 +673,19 @@ static int print_frame(gpx_t *gpx, int pos) {
bc1 = (gpx->frame_bytes[pos_BlkChk] << 8) | gpx->frame_bytes[pos_BlkChk+1];
bc2 = blk_checkM10(len_BlkChk, gpx->frame_bytes+2); // len(essentialBlock+chk16) = 0x16
switch (gpx->frame_bytes[1]) {
case 0x8F: gpx->type = t_M2K2; break;
case 0x9F: gpx->type = t_M10; break;
case 0xAF: gpx->type = t_M10plus; break;
case 0x20: gpx->type = t_M20; break;
default : gpx->type = t_M10;
}
if (gpx->option.raw) {
if (gpx->option.col && gpx->frame_bytes[1] != 0x49) {
if (gpx->option.col /* && gpx->frame_bytes[1] != 0x49 */) {
fprintf(stdout, col_FRTXT);
for (i = 0; i < FRAME_LEN+gpx->auxlen; i++) {
for (i = 0; i < flen+1; i++) {
byte = gpx->frame_bytes[i];
if (i == 1) fprintf(stdout, col_Mtype);
if ((i >= pos_GPSTOW) && (i < pos_GPSTOW+3)) fprintf(stdout, col_GPSTOW);
@ -658,7 +713,7 @@ static int print_frame(gpx_t *gpx, int pos) {
fprintf(stdout, ANSI_COLOR_RESET"\n");
}
else {
for (i = 0; i < FRAME_LEN+gpx->auxlen; i++) {
for (i = 0; i < flen+1; i++) {
byte = gpx->frame_bytes[i];
fprintf(stdout, "%02x", byte);
}
@ -671,6 +726,7 @@ static int print_frame(gpx_t *gpx, int pos) {
}
}
/*
else if (gpx->frame_bytes[1] == 0x49) {
if (gpx->option.vbs == 3) {
for (i = 0; i < FRAME_LEN+gpx->auxlen; i++) {
@ -680,11 +736,14 @@ static int print_frame(gpx_t *gpx, int pos) {
fprintf(stdout, "\n");
}
}
*/
else print_pos(gpx, bc1 == bc2, cs1 == cs2);
return (gpx->frame_bytes[0]<<8)|gpx->frame_bytes[1];
}
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv) {
@ -698,6 +757,7 @@ int main(int argc, char **argv) {
int option_iq = 0;
int option_lp = 0;
int option_dc = 0;
int option_softin = 0;
int option_pcmraw = 0;
int wavloaded = 0;
int sel_wavch = 0; // audio channel: left
@ -714,6 +774,7 @@ int main(int argc, char **argv) {
int bitpos = 0;
int bitQ;
int pos;
hsbit_t hsbit, hsbit1;
//int headerlen = 0;
@ -729,6 +790,8 @@ int main(int argc, char **argv) {
pcm_t pcm = {0};
dsp_t dsp = {0}; //memset(&dsp, 0, sizeof(dsp));
hdb_t hdb = {0};
gpx_t gpx = {0};
@ -767,7 +830,7 @@ int main(int argc, char **argv) {
++argv;
if (*argv) {
baudrate = atof(*argv);
if (baudrate < 9000 || baudrate > 10000) baudrate = BAUD_RATE; // default: 9615
if (baudrate < 9000 || baudrate > 10000) baudrate = BAUD_RATE; // default: M20:9600, M10:9615
}
else return -1;
}
@ -779,6 +842,7 @@ int main(int argc, char **argv) {
spike = 1;
}
else if ( (strcmp(*argv, "--ch2") == 0) ) { sel_wavch = 1; } // right channel (default: 0=left)
else if (strcmp(*argv, "--softin") == 0) { option_softin = 1; } // float32 soft input
else if ( (strcmp(*argv, "--ths") == 0) ) {
++argv;
if (*argv) {
@ -843,6 +907,7 @@ int main(int argc, char **argv) {
if (!wavloaded) fp = stdin;
// init gpx
gpx.option.inv = option_inv; // irrelevant
gpx.option.vbs = option_verbose;
gpx.option.raw = option_raw;
@ -850,77 +915,111 @@ int main(int argc, char **argv) {
gpx.option.col = option_color;
// init gpx
if (option_iq == 0 && option_pcmraw) {
fclose(fp);
fprintf(stderr, "error: raw data not IQ\n");
return -1;
#ifdef EXT_FSK
if (!option_softin) {
option_softin = 1;
fprintf(stderr, "reading float32 soft symbols\n");
}
if (option_iq) sel_wavch = 0;
#endif
pcm.sel_ch = sel_wavch;
if (option_pcmraw == 0) {
k = read_wav_header(&pcm, fp);
if ( k < 0 ) {
if (!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;
}
}
// m10: BT>1?, h=1.2 ?
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 = 1; // M10!header
dsp._spb = dsp.sps*symlen;
dsp.hdr = rawheader;
dsp.hdrlen = strlen(rawheader);
dsp.BT = 1.8; // bw/time (ISI) // 1.0..2.0 // M20 ?
dsp.h = 0.9; // 1.2 modulation index // M20 ?
dsp.opt_iq = option_iq;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = 24e3; // IF lowpass bandwidth
dsp.lpFM_bw = 10e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 8 ) {
fprintf(stderr, "note: sample rate low (%.1f sps)\n", dsp.sps);
}
if (baudrate > 0) {
dsp.br = (float)baudrate;
dsp.sps = (float)dsp.sr/dsp.br;
fprintf(stderr, "sps corr: %.4f\n", dsp.sps);
}
//headerlen = dsp.hdrlen;
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
}
bitofs += shift;
}
else {
// init circular header bit buffer
hdb.hdr = rawheader;
hdb.len = strlen(rawheader);
//hdb.thb = 1.0 - 3.1/(float)hdb.len; // 1.0-max_bit_errors/hdrlen
hdb.bufpos = -1;
hdb.buf = NULL;
/*
calloc(hdb.len, sizeof(char));
if (hdb.buf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
*/
hdb.ths = 0.8; // caution 0.7: false positive / offset
hdb.sbuf = calloc(hdb.len, sizeof(float));
if (hdb.sbuf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
}
// m10: BT>1?, h=1.2 ?
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 = 1; // M10!header
dsp._spb = dsp.sps*symlen;
dsp.hdr = rawheader;
dsp.hdrlen = strlen(rawheader);
dsp.BT = 1.8; // bw/time (ISI) // 1.0..2.0 // M20 ?
dsp.h = 0.9; // 1.2 modulation index // M20 ?
dsp.opt_iq = option_iq;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = 24e3; // IF lowpass bandwidth
dsp.lpFM_bw = 10e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 8 ) {
fprintf(stderr, "note: sample rate low (%.1f sps)\n", dsp.sps);
}
if (baudrate > 0) {
dsp.br = (float)baudrate;
dsp.sps = (float)dsp.sr/dsp.br;
fprintf(stderr, "sps corr: %.4f\n", dsp.sps);
}
//headerlen = dsp.hdrlen;
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
};
bitofs += shift;
while ( 1 )
{
// FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
if (option_softin) {
header_found = find_softbinhead(fp, &hdb, &_mv);
}
else { // 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;
@ -938,15 +1037,27 @@ int main(int argc, char **argv) {
while ( pos < BITFRAME_LEN+BITAUX_LEN ) {
if (option_iq >= 2) {
float bl = -1;
if (option_iq > 2) bl = 4.0;
bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, bl, 0);
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
bit = (s>=0.0); // no soft decoding
}
}
}
else {
bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike); // symlen=2
float bl = -1;
if (option_iq >= 2) spike = 0;
if (option_iq > 2) bl = 4.0;
//bitQ = read_slbit(&dsp, &bit, 0, bitofs, bitpos, bl, spike); // symlen=2
bitQ = read_softbit2p(&dsp, &hsbit, 0, bitofs, bitpos, bl, spike, &hsbit1); // symlen=2
bit = hsbit.hb;
}
if ( bitQ == EOF ) { break; }
gpx.frame_bits[pos] = 0x31 ^ (bit0 ^ bit);
@ -963,7 +1074,7 @@ int main(int argc, char **argv) {
// bis Ende der Sekunde vorspulen; allerdings Doppel-Frame alle 10 sek
if (gpx.option.vbs < 3) { // && (regulare frame) // print_frame-return?
while ( bitpos < 5*BITFRAME_LEN ) {
bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike); // symlen=2
bitQ = read_slbit(&dsp, &bit, 0, bitofs, bitpos, -1, 0); // symlen=2
if ( bitQ == EOF) break;
bitpos++;
}
@ -974,7 +1085,10 @@ int main(int argc, char **argv) {
}
free_buffers(&dsp);
if (!option_softin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
fclose(fp);