kopia lustrzana https://github.com/projecthorus/radiosonde_auto_rx
				
				
				
			Merge pull request #806 from darksidelemm/testing
Further updates to make WxR-301D decoding work.pull/805/head
						commit
						0877ecc3d6
					
				| 
						 | 
				
			
			@ -653,6 +653,7 @@ def telemetry_filter(telemetry):
 | 
			
		|||
        or ("LMS" in telemetry["type"])
 | 
			
		||||
        or ("IMET" in telemetry["type"])
 | 
			
		||||
        or ("MTS01" in telemetry["type"])
 | 
			
		||||
        or ("WXR" in telemetry["type"])
 | 
			
		||||
    ):
 | 
			
		||||
        return "OK"
 | 
			
		||||
    else:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ from queue import Queue
 | 
			
		|||
# 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.6.3-beta4"
 | 
			
		||||
__version__ = "1.6.3-beta5"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Global Variables
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -456,7 +456,7 @@ def read_auto_rx_config(filename, no_sdr_test=False):
 | 
			
		|||
            "MEISEI": True,
 | 
			
		||||
            "MTS01": False, # Until we test it
 | 
			
		||||
            "MRZ": False,  # .... except for the MRZ, until we know it works.
 | 
			
		||||
            "WXR301": False, # No fsk_demod chain for this yet.
 | 
			
		||||
            "WXR301": True, # No fsk_demod chain for this yet.
 | 
			
		||||
            "UDP": False,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1266,6 +1266,49 @@ class SondeDecoder(object):
 | 
			
		|||
            demod_stats = FSKDemodStats(averaging_time=1.0, peak_hold=True)
 | 
			
		||||
            self.rx_frequency = self.sonde_freq
 | 
			
		||||
 | 
			
		||||
        elif self.sonde_type == "WXR301":
 | 
			
		||||
            # Weathex WxR-301D Sondes.
 | 
			
		||||
 | 
			
		||||
            _baud_rate = 4800
 | 
			
		||||
            _sample_rate = 96000
 | 
			
		||||
 | 
			
		||||
            # Limit FSK estimator window to roughly +/- 40 kHz
 | 
			
		||||
            _lower = -40000
 | 
			
		||||
            _upper = 40000
 | 
			
		||||
 | 
			
		||||
            demod_cmd = get_sdr_iq_cmd(
 | 
			
		||||
                sdr_type = self.sdr_type,
 | 
			
		||||
                frequency = self.sonde_freq,
 | 
			
		||||
                sample_rate = _sample_rate,
 | 
			
		||||
                sdr_hostname = self.sdr_hostname,
 | 
			
		||||
                sdr_port = self.sdr_port,
 | 
			
		||||
                ss_iq_path = self.ss_iq_path,
 | 
			
		||||
                rtl_device_idx = self.rtl_device_idx,
 | 
			
		||||
                ppm = self.ppm,
 | 
			
		||||
                gain = self.gain,
 | 
			
		||||
                bias = self.bias,
 | 
			
		||||
                dc_block = True
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # Add in tee command to save IQ to disk if debugging is enabled.
 | 
			
		||||
            if self.save_decode_iq:
 | 
			
		||||
                demod_cmd += f" tee {self.save_decode_iq_path} |"
 | 
			
		||||
 | 
			
		||||
            demod_cmd += "./fsk_demod --cs16 -s -b %d -u %d --stats=%d 2 %d %d - -" % (
 | 
			
		||||
                _lower,
 | 
			
		||||
                _upper,
 | 
			
		||||
                _stats_rate,
 | 
			
		||||
                _sample_rate,
 | 
			
		||||
                _baud_rate,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # Soft-decision decoding, inverted.
 | 
			
		||||
            decode_cmd = f"./weathex301d --softin -i --json 2>/dev/null"
 | 
			
		||||
 | 
			
		||||
            # Weathex sondes transmit continuously - average over the last frame, and use a peak hold
 | 
			
		||||
            demod_stats = FSKDemodStats(averaging_time=5.0, peak_hold=True)
 | 
			
		||||
            self.rx_frequency = self.sonde_freq
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1660,6 +1703,7 @@ class SondeDecoder(object):
 | 
			
		|||
                    "%Y-%m-%dT%H:%M:%SZ"
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            # Grab a snapshot of modem statistics, if we are using an experimental decoder.
 | 
			
		||||
            if self.demod_stats is not None:
 | 
			
		||||
                if self.demod_stats.snr != -999.0:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -486,6 +486,8 @@ def detect_sonde(
 | 
			
		|||
        else:
 | 
			
		||||
            _score = float(_score.strip())
 | 
			
		||||
            _offset_est = 0.0
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        logging.error(
 | 
			
		||||
            "Scanner - Error parsing dft_detect output: %s" % ret_output.strip()
 | 
			
		||||
| 
						 | 
				
			
			@ -608,6 +610,9 @@ def detect_sonde(
 | 
			
		|||
            % (_sdr_name, _score, _offset_est)
 | 
			
		||||
        )
 | 
			
		||||
        _sonde_type = "WXR301"
 | 
			
		||||
        # Clear out the offset estimate for WxR-301's as it's not accurate
 | 
			
		||||
        # to do no whitening on the signal.
 | 
			
		||||
        _offset_est = 0.0
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        _sonde_type = None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -306,6 +306,12 @@ def generate_aprs_id(sonde_data):
 | 
			
		|||
            _id_suffix = int(sonde_data["id"].split("-")[1])
 | 
			
		||||
            _id_hex = hex(_id_suffix).upper()
 | 
			
		||||
            _object_name = "LMS6" + _id_hex[-5:]
 | 
			
		||||
        
 | 
			
		||||
        elif "WXR" in sonde_data["type"]:
 | 
			
		||||
            # Use the last 6 hex digits of the sonde ID.
 | 
			
		||||
            _id_suffix = int(sonde_data["id"].split("-")[1])
 | 
			
		||||
            _id_hex = hex(_id_suffix).upper()
 | 
			
		||||
            _object_name = "WXR" + _id_hex[-6:]
 | 
			
		||||
 | 
			
		||||
        elif "MEISEI" in sonde_data["type"] or "IMS100" in sonde_data["type"] or "RS11G" in sonde_data["type"]:
 | 
			
		||||
            # Convert the serial number to an int
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ int option_verbose = 0,
 | 
			
		|||
    option_b = 0,
 | 
			
		||||
    option_json = 0,
 | 
			
		||||
    option_timestamp = 0,
 | 
			
		||||
    option_softin = 0,
 | 
			
		||||
    wavloaded = 0;
 | 
			
		||||
int wav_channel = 0;     // audio channel: left
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -229,6 +230,28 @@ int read_rawbit(FILE *fp, int *bit) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int f32soft_read(FILE *fp, float *s) {
 | 
			
		||||
    unsigned int word = 0;
 | 
			
		||||
    short *b = (short*)&word;
 | 
			
		||||
    float *f = (float*)&word;
 | 
			
		||||
    int bps = 32;
 | 
			
		||||
 | 
			
		||||
    if (fread( &word, bps/8, 1, fp) != 1) return EOF;
 | 
			
		||||
 | 
			
		||||
    if (bps == 32) {
 | 
			
		||||
        *s = *f;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        if (bps ==  8) { *b -= 128; }
 | 
			
		||||
        *s = *b/128.0;
 | 
			
		||||
        if (bps == 16) { *s /= 256.0; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int compare() {
 | 
			
		||||
    int i=0;
 | 
			
		||||
    while ((i < HEADLEN) && (buf[(bufpos+i) % HEADLEN] == header[HEADLEN+HEADOFS-1-i])) {
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +451,7 @@ int print_frame() {
 | 
			
		|||
            val = xframe[OFS+13] | (xframe[OFS+14]<<8) | (xframe[OFS+15]<<16);
 | 
			
		||||
            val >>= 4;
 | 
			
		||||
            val &= 0x7FFFF; // int19 ?
 | 
			
		||||
            //if (val & 0x40000) val -= 0x80000;
 | 
			
		||||
            //if (val & 0x40000) val -= 0x80000; ?? or sign bit ?
 | 
			
		||||
            float alt = val / 10.0f;
 | 
			
		||||
            printf(" alt: %.1f ", alt);  // MSL
 | 
			
		||||
            gpx.alt = alt;
 | 
			
		||||
| 
						 | 
				
			
			@ -436,16 +459,16 @@ int print_frame() {
 | 
			
		|||
            // lat
 | 
			
		||||
            val = xframe[OFS+15] | (xframe[OFS+16]<<8) | (xframe[OFS+17]<<16) | (xframe[OFS+18]<<24);
 | 
			
		||||
            val >>= 7;
 | 
			
		||||
            val &= 0x1FFFFFF; // int25 ?
 | 
			
		||||
            if (val & 0x1000000) val -= 0x2000000; // sign ?  (or 90 -> -90 wrap ?)
 | 
			
		||||
            val &= 0x1FFFFFF; // int25 ?  ?? sign NMEA N/S ?
 | 
			
		||||
            //if (val & 0x1000000) val -= 0x2000000; // sign bit ?  (or 90 -> -90 wrap ?)
 | 
			
		||||
            float lat = val / 1e5f;
 | 
			
		||||
            printf(" lat: %.4f ", lat);
 | 
			
		||||
            gpx.lat = lat;
 | 
			
		||||
 | 
			
		||||
            // lon
 | 
			
		||||
            val = xframe[OFS+19] | (xframe[OFS+20]<<8) | (xframe[OFS+21]<<16)| (xframe[OFS+22]<<24);
 | 
			
		||||
            val &= 0x3FFFFFF; // int26 ?
 | 
			
		||||
            if (val & 0x2000000) val -= 0x4000000; // sign ?  (or 180 -> -180 wrap ?)
 | 
			
		||||
            val &= 0x3FFFFFF; // int26 ?  ?? sign NMEA E/W ?
 | 
			
		||||
            //if (val & 0x2000000) val -= 0x4000000; // or sign bit ?  (or 180 -> -180 wrap ?)
 | 
			
		||||
            float lon = val / 1e5f;
 | 
			
		||||
            printf(" lon: %.4f ", lon);
 | 
			
		||||
            gpx.lon = lon;
 | 
			
		||||
| 
						 | 
				
			
			@ -518,6 +541,7 @@ int main(int argc, char **argv) {
 | 
			
		|||
        else if ( (strcmp(*argv, "-v") == 0) || (strcmp(*argv, "--verbose") == 0) ) {
 | 
			
		||||
            option_verbose = 1;
 | 
			
		||||
        }
 | 
			
		||||
        else if   (strcmp(*argv, "--softin") == 0) { option_softin = 1; }  // float32 soft input
 | 
			
		||||
        else if   (strcmp(*argv, "-b" ) == 0) { option_b = 1; }
 | 
			
		||||
        else if   (strcmp(*argv, "-t" ) == 0) { option_timestamp = 1; }
 | 
			
		||||
        else if ( (strcmp(*argv, "-r") == 0) || (strcmp(*argv, "--raw") == 0) ) {
 | 
			
		||||
| 
						 | 
				
			
			@ -549,8 +573,10 @@ int main(int argc, char **argv) {
 | 
			
		|||
    if (!wavloaded) fp = stdin;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    i = read_wav_header(fp);
 | 
			
		||||
    if (i) return -1;
 | 
			
		||||
    if ( !option_softin ) {
 | 
			
		||||
        i = read_wav_header(fp);
 | 
			
		||||
        if (i) return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (cfreq > 0) gpx.jsn_freq = (cfreq+500)/1000;
 | 
			
		||||
| 
						 | 
				
			
			@ -558,17 +584,18 @@ int main(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
    bit_count = 0;
 | 
			
		||||
    frames = 0;
 | 
			
		||||
    while (!read_bits_fsk(fp, &bit, &len)) {
 | 
			
		||||
 | 
			
		||||
        if (len == 0) {
 | 
			
		||||
            bufpos--;
 | 
			
		||||
            if (bufpos < 0) bufpos = HEADLEN-1;
 | 
			
		||||
            buf[bufpos] = 'x';
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
    if (option_softin)
 | 
			
		||||
    {
 | 
			
		||||
        float s = 0.0f;
 | 
			
		||||
        int bit = 0;
 | 
			
		||||
        sample_rate = BAUD_RATE;
 | 
			
		||||
        sample_count = 0;
 | 
			
		||||
 | 
			
		||||
        while (!f32soft_read(fp, &s)) {
 | 
			
		||||
 | 
			
		||||
            bit = option_inv ? (s<=0.0f) : (s>=0.0f);  // softbit s: bit=0 <=> s<0 , bit=1 <=> s>=0
 | 
			
		||||
 | 
			
		||||
        for (j = 0; j < len; j++) {
 | 
			
		||||
            bufpos--;
 | 
			
		||||
            if (bufpos < 0) bufpos = HEADLEN-1;
 | 
			
		||||
            buf[bufpos] = 0x30 + bit;
 | 
			
		||||
| 
						 | 
				
			
			@ -597,23 +624,69 @@ int main(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
                print_frame();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        if (header_found && option_b) {
 | 
			
		||||
            bitstart = 1;
 | 
			
		||||
 | 
			
		||||
            while ( bit_count < BITFRAMELEN ) {
 | 
			
		||||
                if (read_rawbit(fp, &bit) == EOF) break;
 | 
			
		||||
                frame_bits[bit_count] = 0x30 + bit;
 | 
			
		||||
                bit_count += 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bit_count = 0;
 | 
			
		||||
            header_found = 0;
 | 
			
		||||
 | 
			
		||||
            print_frame();
 | 
			
		||||
            sample_count += 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        while (!read_bits_fsk(fp, &bit, &len)) {
 | 
			
		||||
 | 
			
		||||
            if (len == 0) {
 | 
			
		||||
                bufpos--;
 | 
			
		||||
                if (bufpos < 0) bufpos = HEADLEN-1;
 | 
			
		||||
                buf[bufpos] = 'x';
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            for (j = 0; j < len; j++) {
 | 
			
		||||
                bufpos--;
 | 
			
		||||
                if (bufpos < 0) bufpos = HEADLEN-1;
 | 
			
		||||
                buf[bufpos] = 0x30 + bit;
 | 
			
		||||
 | 
			
		||||
                if (!header_found)
 | 
			
		||||
                {
 | 
			
		||||
                    h = compare(); //h2 = compare2();
 | 
			
		||||
                    if ((h >= HEADLEN)) {
 | 
			
		||||
                        header_found = 1;
 | 
			
		||||
                        fflush(stdout);
 | 
			
		||||
                        if (option_timestamp) printf("<%8.3f> ", sample_count/(double)sample_rate);
 | 
			
		||||
                        strncpy(frame_bits, header, HEADLEN);
 | 
			
		||||
                        bit_count += HEADLEN;
 | 
			
		||||
                        frames++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    frame_bits[bit_count] = 0x30 + bit;
 | 
			
		||||
                    bit_count += 1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (bit_count >= BITFRAMELEN) {
 | 
			
		||||
                    bit_count = 0;
 | 
			
		||||
                    header_found = 0;
 | 
			
		||||
 | 
			
		||||
                    print_frame();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            if (header_found && option_b) {
 | 
			
		||||
                bitstart = 1;
 | 
			
		||||
 | 
			
		||||
                while ( bit_count < BITFRAMELEN ) {
 | 
			
		||||
                    if (read_rawbit(fp, &bit) == EOF) break;
 | 
			
		||||
                    frame_bits[bit_count] = 0x30 + bit;
 | 
			
		||||
                    bit_count += 1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                bit_count = 0;
 | 
			
		||||
                header_found = 0;
 | 
			
		||||
 | 
			
		||||
                print_frame();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("\n");
 | 
			
		||||
 | 
			
		||||
    fclose(fp);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue