def decode_rs41(frequency, ppm=0, gain='automatic', bias=False, rx_queue=None, timeout=120): """ Decode a RS41 sonde """ global latest_sonde_data, internet_push_queue, ozi_push_queue # Add a -T option if bias is enabled bias_option = "-T " if bias else "" decode_cmd = "rtl_fm %s-p %d -M fm -s 15k -f %d 2>/dev/null |" % (bias_option, int(ppm), frequency) decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |" # Note: I've got the check-CRC option hardcoded in here as always on. # I figure this is prudent if we're going to proceed to push this telemetry data onto a map. decode_cmd += "./rs41ecc --crc --ecc " # if this doesn't work try -i at the end rx_last_line = time.time() # Receiver subprocess. Discard stderr, and feed stdout into an asynchronous read class. rx = subprocess.Popen(decode_cmd, shell=True, stdin=None, stdout=subprocess.PIPE, preexec_fn=os.setsid) rx_stdout = AsynchronousFileReader(rx.stdout, autostart=True) while not rx_stdout.eof(): for line in rx_stdout.readlines(): if (line != None) and (line != ""): try: data = process_rs_line(line) # Reset timeout counter. rx_last_line = time.time() if data != None: # Add in a few fields that don't come from the sonde telemetry. data['freq'] = "%.3f MHz" % (frequency/1e6) data['type'] = "RS41" update_flight_stats(data) latest_sonde_data = data if rx_queue != None: try: internet_push_queue.put_nowait(data) ozi_push_queue.put_nowait(data) except: pass except: traceback.print_exc() logging.error("Error parsing line: %s" % line) # Check timeout counter. if time.time() > (rx_last_line+timeout): logging.error("RX Timed out.") break # Sleep for a short time. time.sleep(0.1) logging.error("Closing RX Thread.") os.killpg(os.getpgid(rx.pid), signal.SIGTERM) rx_stdout.stop() rx_stdout.join() return
def decode_rs92(frequency, ppm=0, gain=-1, bias=False, rx_queue=None, almanac=None, ephemeris=None, timeout=120): """ Decode a RS92 sonde """ global latest_sonde_data, internet_push_queue, ozi_push_queue # Before we get started, do we need to download GPS data? if ephemeris == None: # If no ephemeris data defined, attempt to download it. # get_ephemeris will either return the saved file name, or None. ephemeris = get_ephemeris(destination="ephemeris.dat") # If ephemeris is still None, then we failed to download the ephemeris data. # Try and grab the almanac data instead if ephemeris == None: logging.error("Could not obtain ephemeris data, trying to download an almanac.") almanac = get_almanac(destination="almanac.txt") if almanac == None: # We probably don't have an internet connection. Bomb out, since we can't do much with the sonde telemetry without an almanac! logging.critical("Could not obtain GPS ephemeris or almanac data.") return False # Add a -T option if bias is enabled bias_option = "-T " if bias else "" # Add a gain parameter if we have been provided one. if gain != -1: gain_param = '-g %.1f ' % gain else: gain_param = '' decode_cmd = "rtl_fm %s-p %d %s-M fm -s 12k -f %d 2>/dev/null |" % (bias_option, int(ppm), gain_param, frequency) decode_cmd += "sox -t raw -r 12k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2500 highpass 20 2>/dev/null |" # Note: I've got the check-CRC option hardcoded in here as always on. # I figure this is prudent if we're going to proceed to push this telemetry data onto a map. if ephemeris != None: decode_cmd += "./rs92ecc -v --crc --ecc --vel -e %s" % ephemeris elif almanac != None: decode_cmd += "./rs92ecc -v --crc --ecc --vel -a %s" % almanac logging.debug("Running command: %s" % decode_cmd) rx_last_line = time.time() # Receiver subprocess. Discard stderr, and feed stdout into an asynchronous read class. rx = subprocess.Popen(decode_cmd, shell=True, stdin=None, stdout=subprocess.PIPE, preexec_fn=os.setsid) rx_stdout = AsynchronousFileReader(rx.stdout, autostart=True) while not rx_stdout.eof(): for line in rx_stdout.readlines(): if (line != None) and (line != ""): try: data = process_rs_line(line) # Reset timeout counter. rx_last_line = time.time() if data != None: # Add in a few fields that don't come from the sonde telemetry. data['freq'] = "%.3f MHz" % (frequency/1e6) data['type'] = "RS92" update_flight_stats(data) if rx_queue != None: try: internet_push_queue.put_nowait(data) ozi_push_queue.put_nowait(data) except: pass except: traceback.print_exc() logging.error("Error parsing line: %s" % line) # Check timeout counter. if time.time() > (rx_last_line+timeout): logging.error("RX Timed out.") break # Sleep for a short time. time.sleep(0.1) logging.error("Closing RX Thread.") os.killpg(os.getpgid(rx.pid), signal.SIGTERM) rx_stdout.stop() rx_stdout.join() return
def decode_rs41(frequency, ppm=0, gain=-1, bias=False, rx_queue=None, timeout=120, save_log=False): """ Decode a RS41 sonde """ global latest_sonde_data, internet_push_queue, ozi_push_queue # Add a -T option if bias is enabled bias_option = "-T " if bias else "" # Add a gain parameter if we have been provided one. if gain != -1: gain_param = '-g %.1f ' % gain else: gain_param = '' # Note: Have removed a 'highpass 20' filter from the sox line, will need to re-evaluate if adding that is useful in the future. decode_cmd = "rtl_fm %s-p %d %s-M fm -F9 -s 15k -f %d 2>/dev/null |" % ( bias_option, int(ppm), gain_param, frequency) decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2600 2>/dev/null |" # Note: I've got the check-CRC option hardcoded in here as always on. # I figure this is prudent if we're going to proceed to push this telemetry data onto a map. decode_cmd += "./rs41ecc --crc --ecc " # if this doesn't work try -i at the end logging.debug("Running command: %s" % decode_cmd) rx_last_line = time.time() # Receiver subprocess. Discard stderr, and feed stdout into an asynchronous read class. rx = subprocess.Popen(decode_cmd, shell=True, stdin=None, stdout=subprocess.PIPE, preexec_fn=os.setsid) rx_stdout = AsynchronousFileReader(rx.stdout, autostart=True) _log_file = None while not rx_stdout.eof(): for line in rx_stdout.readlines(): if (line != None) and (line != ""): try: data = process_rs_line(line) # Reset timeout counter. rx_last_line = time.time() if data != None: # Add in a few fields that don't come from the sonde telemetry. data['freq'] = "%.3f MHz" % (frequency / 1e6) data['type'] = "RS41" # Per-Sonde Logging if save_log: if _log_file is None: _log_file_name = "./log/%s_%s_%s_%d.log" % ( datetime.datetime.utcnow().strftime( "%Y%m%d-%H%M%S"), data['id'], data['type'], int(frequency / 1e3)) _log_file = open(_log_file_name, 'wb') # Write a log line # datetime,id,frame_no,lat,lon,alt,type,frequency _log_line = "%s,%s,%d,%.5f,%.5f,%.1f,%s,%.3f\n" % ( data['datetime_str'], data['id'], data['frame'], data['lat'], data['lon'], data['alt'], data['type'], frequency / 1e6) _log_file.write(_log_line) _log_file.flush() update_flight_stats(data) latest_sonde_data = data if rx_queue != None: try: internet_push_queue.put_nowait(data) ozi_push_queue.put_nowait(data) except: pass except: traceback.print_exc() logging.error("Error parsing line: %s" % line) # Check timeout counter. if time.time() > (rx_last_line + timeout): logging.error("RX Timed out.") break # Sleep for a short time. time.sleep(0.1) # If we were writing a log, close the file. if _log_file != None: _log_file.flush() _log_file.close() logging.error("Closing RX Thread.") os.killpg(os.getpgid(rx.pid), signal.SIGTERM) rx_stdout.stop() rx_stdout.join() return
def decode_rs92(frequency, ppm=0, gain=-1, bias=False, rx_queue=None, almanac=None, ephemeris=None, timeout=120, save_log=False): """ Decode a RS92 sonde """ global latest_sonde_data, internet_push_queue, ozi_push_queue # Before we get started, do we need to download GPS data? if ephemeris == None: # If no ephemeris data defined, attempt to download it. # get_ephemeris will either return the saved file name, or None. ephemeris = get_ephemeris(destination="ephemeris.dat") # If ephemeris is still None, then we failed to download the ephemeris data. # Try and grab the almanac data instead if ephemeris == None: logging.error( "Could not obtain ephemeris data, trying to download an almanac.") almanac = get_almanac(destination="almanac.txt") if almanac == None: # We probably don't have an internet connection. Bomb out, since we can't do much with the sonde telemetry without an almanac! logging.critical("Could not obtain GPS ephemeris or almanac data.") return False # Add a -T option if bias is enabled bias_option = "-T " if bias else "" # Add a gain parameter if we have been provided one. if gain != -1: gain_param = '-g %.1f ' % gain else: gain_param = '' # Example command: # rtl_fm -p 0 -g 26.0 -M fm -F9 -s 12k -f 400500000 | sox -t raw -r 12k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 lowpass 2500 2>/dev/null | ./rs92ecc decode_cmd = "rtl_fm %s-p %d %s-M fm -F9 -s 12k -f %d 2>/dev/null |" % ( bias_option, int(ppm), gain_param, frequency) decode_cmd += "sox -t raw -r 12k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2500 highpass 20 2>/dev/null |" # Note: I've got the check-CRC option hardcoded in here as always on. # I figure this is prudent if we're going to proceed to push this telemetry data onto a map. if ephemeris != None: decode_cmd += "./rs92ecc -vx -v --crc --ecc --vel -e %s" % ephemeris elif almanac != None: decode_cmd += "./rs92ecc -vx -v --crc --ecc --vel -a %s" % almanac logging.debug("Running command: %s" % decode_cmd) rx_last_line = time.time() # Receiver subprocess. Discard stderr, and feed stdout into an asynchronous read class. rx = subprocess.Popen(decode_cmd, shell=True, stdin=None, stdout=subprocess.PIPE, preexec_fn=os.setsid) rx_stdout = AsynchronousFileReader(rx.stdout, autostart=True) _log_file = None while not rx_stdout.eof(): for line in rx_stdout.readlines(): if (line != None) and (line != ""): try: data = process_rs_line(line) # Reset timeout counter. rx_last_line = time.time() if data != None: # Add in a few fields that don't come from the sonde telemetry. data['freq'] = "%.3f MHz" % (frequency / 1e6) data['type'] = "RS92" # If we are seeing any aux data (i.e. there is something strapped to this RS92), append '-Ozone' to the type. if 'aux' in data.keys(): _ozone = "-Ozone" else: _ozone = "" # Per-Sonde Logging if save_log: if _log_file is None: _log_file_name = "./log/%s_%s_%s_%d.log" % ( datetime.datetime.utcnow().strftime( "%Y%m%d-%H%M%S"), data['id'], (data['type'] + _ozone), int(frequency / 1e3)) _log_file = open(_log_file_name, 'wb') # Write a log line # datetime,id,frame_no,lat,lon,alt,type,frequency _log_line = "%s,%s,%d,%.5f,%.5f,%.1f,%s,%.3f\n" % ( data['datetime_str'], data['id'], data['frame'], data['lat'], data['lon'], data['alt'], (data['type'] + _ozone), frequency / 1e6) _log_file.write(_log_line) _log_file.flush() update_flight_stats(data) if rx_queue != None: try: internet_push_queue.put_nowait(data) ozi_push_queue.put_nowait(data) except: pass except: traceback.print_exc() logging.error("Error parsing line: %s" % line) # Check timeout counter. if time.time() > (rx_last_line + timeout): logging.error("RX Timed out.") break # Sleep for a short time. time.sleep(0.1) # If we were writing a log, close the file. if _log_file != None: _log_file.flush() _log_file.close() logging.error("Closing RX Thread.") os.killpg(os.getpgid(rx.pid), signal.SIGTERM) rx_stdout.stop() rx_stdout.join() return