diff --git a/auto_rx/auto_rx.py b/auto_rx/auto_rx.py index 85f69d41..bf081498 100644 --- a/auto_rx/auto_rx.py +++ b/auto_rx/auto_rx.py @@ -631,7 +631,8 @@ def telemetry_filter(telemetry): vaisala_callsign_valid = re.match(r"[C-Z][\d][\d][\d]\d{4}", _serial) # Just make sure we're not getting the 'xxxxxxxx' unknown serial from the DFM decoder. - if "DFM" in telemetry["type"]: + # Also applies to PS15 sondes. + if "DFM" in telemetry["type"] or "PS15" in telemetry["type"]: dfm_callsign_valid = "x" not in _serial.split("-")[1] else: dfm_callsign_valid = False diff --git a/auto_rx/autorx/__init__.py b/auto_rx/autorx/__init__.py index fd1b8348..bbfcd04c 100644 --- a/auto_rx/autorx/__init__.py +++ b/auto_rx/autorx/__init__.py @@ -12,7 +12,7 @@ # 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.7.3" +__version__ = "1.7.4" # Global Variables diff --git a/auto_rx/autorx/decode.py b/auto_rx/autorx/decode.py index 6f577174..03336c2a 100644 --- a/auto_rx/autorx/decode.py +++ b/auto_rx/autorx/decode.py @@ -977,7 +977,8 @@ def generate_decoder_command_experimental(self): if self.save_decode_iq: demod_cmd += f" tee {self.save_decode_iq_path} |" - demod_cmd += "./fsk_demod --cs16 -b %d -u %d -s --stats=%d 2 %d %d - -" % ( + # NOTE - Using inverted soft decision outputs, so DFM type detection works correctly. + demod_cmd += "./fsk_demod --cs16 -b %d -u %d -s -i --stats=%d 2 %d %d - -" % ( _lower, _upper, _stats_rate, @@ -991,7 +992,7 @@ def generate_decoder_command_experimental(self): self.raw_file_option = "--rawecc" decode_cmd = ( - f"./dfm09mod -vv --ecc --json --dist --auto --softin -i {self.raw_file_option} 2>/dev/null" + f"./dfm09mod -vv --ecc --json --dist --auto --softin {self.raw_file_option} 2>/dev/null" ) # DFM sondes transmit continuously - average over the last 2 frames, and peak hold diff --git a/auto_rx/autorx/sondehub.py b/auto_rx/autorx/sondehub.py index 804a9250..58edcf4b 100644 --- a/auto_rx/autorx/sondehub.py +++ b/auto_rx/autorx/sondehub.py @@ -168,6 +168,18 @@ def reformat_data(self, telemetry): # for our packets to pass the Sondehub z-check. self.slower_uploads = True + elif telemetry["type"] == "PS15": + _output["manufacturer"] = "Graw" + _output["type"] = "PS-15" + _output["subtype"] = "PS-15" + _output["serial"] = telemetry["id"].split("-")[1] + if "dfmcode" in telemetry: + _output["dfmcode"] = telemetry["dfmcode"] + + # We are handling DFM packets. We need a few more of these in an upload + # for our packets to pass the Sondehub z-check. + self.slower_uploads = True + elif telemetry["type"].startswith("M10") or telemetry["type"].startswith("M20"): _output["manufacturer"] = "Meteomodem" _output["type"] = telemetry["type"] diff --git a/auto_rx/autorx/utils.py b/auto_rx/autorx/utils.py index ac5f3c5e..3dd5a449 100644 --- a/auto_rx/autorx/utils.py +++ b/auto_rx/autorx/utils.py @@ -186,6 +186,8 @@ def short_type_lookup(type_name): return "Vaisala " + type_name elif type_name.startswith("DFM"): return "Graw " + type_name + elif type_name == "PS15": + return "Graw PS15" elif type_name.startswith("M10"): return "Meteomodem M10" elif type_name.startswith("M20"): @@ -260,6 +262,8 @@ def short_short_type_lookup(type_name): return "WXR301" elif type_name == "WXRPN9": return "WXR301(PN9)" + elif type_name == "PS15": + return "PS15" else: return "Unknown" @@ -273,7 +277,7 @@ def generate_aprs_id(sonde_data): if ("RS92" in sonde_data["type"]) or ("RS41" in sonde_data["type"]): # We can use the Vaisala sonde ID directly. _object_name = sonde_data["id"].strip() - elif "DFM" in sonde_data["type"]: + elif "DFM" in sonde_data["type"] or "PS15" in sonde_data["type"]: # As per agreement with other radiosonde decoding software developers, we will now # use the DFM serial number verbatim in the APRS ID, prefixed with 'D'. # For recent DFM sondes, this will result in a object ID of: Dyynnnnnn @@ -288,9 +292,6 @@ def generate_aprs_id(sonde_data): # Create the object name _object_name = "D%d" % _dfm_id - # Convert to upper-case hex, and take the last 5 nibbles. - _id_suffix = hex(_dfm_id).upper()[-5:] - elif "M10" in sonde_data["type"]: # Use the generated id same as dxlAPRS _object_name = sonde_data["aprsid"] diff --git a/utils/fsk_demod.c b/utils/fsk_demod.c index ecd57421..8b1adee2 100644 --- a/utils/fsk_demod.c +++ b/utils/fsk_demod.c @@ -77,12 +77,14 @@ int main(int argc,char *argv[]){ int nsym = FSK_DEFAULT_NSYM; int mask = 0; int tx_tone_separation = 100; + int softinv = 0; int o = 0; int opt_idx = 0; while( o != -1 ){ static struct option long_opts[] = { {"help", no_argument, 0, 'h'}, + {"softinv", no_argument, 0, 'i'}, {"conv", required_argument, 0, 'p'}, {"cs16", no_argument, 0, 'c'}, {"cu8", no_argument, 0, 'd'}, @@ -96,7 +98,7 @@ int main(int argc,char *argv[]){ {0, 0, 0, 0} }; - o = getopt_long(argc,argv,"fhlp:cdt::sb:u:m",long_opts,&opt_idx); + o = getopt_long(argc,argv,"fhilp:cdt::sb:u:m",long_opts,&opt_idx); switch(o){ case 'c': @@ -110,6 +112,9 @@ int main(int argc,char *argv[]){ case 'f': testframe_mode = 1; break; + case 'i': + softinv = 1; + break; case 't': enable_stats = 1; if(optarg != NULL){ @@ -415,6 +420,13 @@ int main(int argc,char *argv[]){ } if(soft_dec_mode){ + // Invert soft decision polarity. + if(softinv){ + for(j=0; jNbits; j++) { + sdbuf[j] = sdbuf[j]*-1.0; + } + } + fwrite(sdbuf,sizeof(float),fsk->Nbits,fout); }else{ fwrite(bitbuf,sizeof(uint8_t),fsk->Nbits,fout);