Skip to content

Commit

Permalink
Show mainboard type on web interface if not RSM412, upload RS41 subfr…
Browse files Browse the repository at this point in the history
…ame data to sondehub, and optionally save it to disk.
  • Loading branch information
Mark Jessop authored and Mark Jessop committed Oct 3, 2023
1 parent 5fa3605 commit 3ca10ea
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 10 deletions.
5 changes: 4 additions & 1 deletion auto_rx/auto_rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,10 @@ def main():
# Start our exporter options
# Telemetry Logger
if config["per_sonde_log"]:
_logger = TelemetryLogger(log_directory=logging_path)
_logger = TelemetryLogger(
log_directory=logging_path,
save_cal_data=config["save_cal_data"]
)
exporter_objects.append(_logger)
exporter_functions.append(_logger.add)

Expand Down
2 changes: 1 addition & 1 deletion auto_rx/autorx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.1-beta3"
__version__ = "1.7.1-beta4"


# Global Variables
Expand Down
12 changes: 12 additions & 0 deletions auto_rx/autorx/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def read_auto_rx_config(filename, no_sdr_test=False):
"save_raw_hex": False,
"save_system_log": False,
"enable_debug_logging": False,
"save_cal_data": False,
# URL for the Habitat DB Server.
# As of July 2018 we send via sondehub.org, which will allow us to eventually transition away
# from using the habhub.org tracker, and leave it for use by High-Altitude Balloon Hobbyists.
Expand Down Expand Up @@ -775,6 +776,17 @@ def read_auto_rx_config(filename, no_sdr_test=False):
)
auto_rx_config["wideband_sondes"] = False

# 1.7.1 - Save RS41 Calibration Data
try:
auto_rx_config["save_cal_data"] = config.getboolean(
"logging", "save_cal_data"
)
except:
logging.warning(
"Config - Missing save_cal_data option (new in v1.7.1), using default (False)"
)
auto_rx_config["save_cal_data"] = False

# If we are being called as part of a unit test, just return the config now.
if no_sdr_test:
return auto_rx_config
Expand Down
20 changes: 18 additions & 2 deletions auto_rx/autorx/decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ def __init__(
self.imet_prev_time = None
self.imet_prev_frame = None

# Keep a record of which RS41 serials we have uploaded complete subframe data for.
self.rs41_subframe_uploads = []

# This will become our decoder thread.
self.decoder = None

Expand Down Expand Up @@ -394,7 +397,7 @@ def generate_decoder_command(self):
if self.save_decode_audio:
decode_cmd += f" tee {self.save_decode_audio_path} |"

decode_cmd += "./rs41mod --ptu2 --json 2>/dev/null"
decode_cmd += "./rs41mod --ptu2 --json --jsnsubfrm1 2>/dev/null"

elif self.sonde_type == "RS92":
# Decoding a RS92 requires either an ephemeris or an almanac file.
Expand Down Expand Up @@ -830,7 +833,7 @@ def generate_decoder_command_experimental(self):
_baud_rate,
)

decode_cmd = f"./rs41mod --ptu2 --json --softin -i {self.raw_file_option} 2>/dev/null"
decode_cmd = f"./rs41mod --ptu2 --json --jsnsubfrm1 --softin -i {self.raw_file_option} 2>/dev/null"

# RS41s transmit pulsed beacons - average over the last 2 frames, and use a peak-hold
demod_stats = FSKDemodStats(averaging_time=2.0, peak_hold=True)
Expand Down Expand Up @@ -1705,6 +1708,19 @@ def handle_decoder_line(self, data):
"%Y-%m-%dT%H:%M:%SZ"
)

# RS41 Subframe Data Actions
# We only upload the subframe data once.
if 'rs41_calconf320' in _telemetry:
# Remove subframe data if we have already uploaded it once.
if _telemetry['id'] in self.rs41_subframe_uploads:
_telemetry.pop('rs41_calconf320')
else:
self.rs41_subframe_uploads.append(_telemetry['id'])
self.log_info(f"Received complete calibration dataset for {_telemetry['id']}.")
_telemetry['rs41_subframe'] = _telemetry['rs41_calconf320']
_telemetry.pop('rs41_calconf320')



# Grab a snapshot of modem statistics, if we are using an experimental decoder.
if self.demod_stats is not None:
Expand Down
53 changes: 52 additions & 1 deletion auto_rx/autorx/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Copyright (C) 2018 Mark Jessop <vk5qi@rfhead.net>
# Released under GNU GPL v3 or later
#
import codecs
import datetime
import glob
import logging
Expand Down Expand Up @@ -50,7 +51,9 @@ class TelemetryLogger(object):

LOG_HEADER = "timestamp,serial,frame,lat,lon,alt,vel_v,vel_h,heading,temp,humidity,pressure,type,freq_mhz,snr,f_error_hz,sats,batt_v,burst_timer,aux_data\n"

def __init__(self, log_directory="./log"):
def __init__(self,
log_directory="./log",
save_cal_data=False):
""" Initialise and start a sonde logger.
Args:
Expand All @@ -59,6 +62,7 @@ def __init__(self, log_directory="./log"):
"""

self.log_directory = log_directory
self.save_cal_data = save_cal_data

# Dictionary to contain file handles.
# Each sonde id is added as a unique key. Under each key are the contents:
Expand Down Expand Up @@ -214,6 +218,7 @@ def write_telemetry(self, telemetry):
self.open_logs[_id] = {
"log": open(_log_file_name, "a"),
"last_time": time.time(),
"subframe_saved": False
}
else:
# Create a new log file.
Expand All @@ -229,6 +234,7 @@ def write_telemetry(self, telemetry):
self.open_logs[_id] = {
"log": open(_log_file_name, "a"),
"last_time": time.time(),
"subframe_saved": False
}

# Write in a header line.
Expand All @@ -244,6 +250,15 @@ def write_telemetry(self, telemetry):
self.open_logs[_id]["last_time"] = time.time()
self.log_debug("Wrote line: %s" % _log_line.strip())

# Save out RS41 subframe data once, if we have it.
if ('rs41_subframe' in telemetry) and self.save_cal_data:
if self.open_logs[_id]['subframe_saved'] == False:
self.open_logs[_id]['subframe_saved'] = self.write_rs41_subframe(telemetry)





def cleanup_logs(self):
""" Close any open logs that have not had telemetry added in X seconds. """

Expand All @@ -262,6 +277,42 @@ def cleanup_logs(self):
except Exception as e:
self.log_error("Error closing log for %s - %s" % (_id, str(e)))

def write_rs41_subframe(self, telemetry):
""" Write RS41 subframe data to disk """

_id = telemetry["id"]
_type = telemetry["type"]

if 'aux' in telemetry:
_type += "-XDATA"

_subframe_log_suffix = "%s_%s_%s_%d_subframe.bin" % (
datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S"),
_id,
_type,
int(telemetry["freq_float"] * 1e3), # Convert frequency to kHz
)
_log_file_name = os.path.join(self.log_directory, _subframe_log_suffix)


try:
_subframe_data = codecs.decode(telemetry['rs41_subframe'], 'hex')
except Exception as e:
self.log_error("Error parsing RS41 subframe data")

if _subframe_data:
_subframe_file = open(_log_file_name, 'wb')
_subframe_file.write(_subframe_data)
_subframe_file.close()

self.log_info(f"Wrote subframe data for {telemetry['id']} to {_subframe_log_suffix}")
return True
else:
return False




def close(self):
""" Close input processing thread. """
self.input_processing_running = False
Expand Down
12 changes: 12 additions & 0 deletions auto_rx/autorx/sondehub.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# Released under GNU GPL v3 or later
#
import autorx
import base64
import codecs
import datetime
import glob
import gzip
Expand Down Expand Up @@ -297,6 +299,16 @@ def reformat_data(self, telemetry):
if "rs41_mainboard_fw" in telemetry:
_output["rs41_mainboard_fw"] = str(telemetry["rs41_mainboard_fw"])

if 'rs41_subframe' in telemetry:
# RS41 calibration subframe data.
# We try to base64 encode this.
try:
_calbytes = codecs.decode(telemetry['rs41_subframe'], 'hex')
_output['rs41_subframe'] = base64.b64encode(_calbytes).decode()
except Exception as e:
self.log_error(f"Error handling RS41 subframe data.")


# Handle the additional SNR and frequency estimation if we have it
if "snr" in telemetry:
_output["snr"] = telemetry["snr"]
Expand Down
8 changes: 8 additions & 0 deletions auto_rx/autorx/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,14 @@

// Add data into the 'other' field.
sonde_id_data.other = "";

if(sonde_id_data.hasOwnProperty('rs41_mainboard')){
// Only print mainboard type if it's not the 'original' mainboard.
if(sonde_id_data.rs41_mainboard !== 'RSM412'){
sonde_id_data.other += sonde_id_data.rs41_mainboard + " ";
}
}

// Burst timer for RS41s
if (sonde_id_data.hasOwnProperty('bt')){
if ((sonde_id_data.bt >= 0) && (sonde_id_data.bt < 65535)) {
Expand Down
3 changes: 3 additions & 0 deletions auto_rx/station.cfg.example
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ save_system_log = False
# auto_rx operational issues.
enable_debug_logging = False

# Enable logging of RS41 Calibration data ('subframe' data)
# This is saved as a binary file with file suffix _subframe.bin
save_cal_data = False

###########################
# WEB INTERFACE SETTINNGS #
Expand Down
4 changes: 4 additions & 0 deletions auto_rx/station.cfg.example.network
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,10 @@ save_system_log = False
# auto_rx operational issues.
enable_debug_logging = False

# Enable logging of RS41 Calibration data ('subframe' data)
# This is saved as a binary file with file suffix _subframe.bin
save_cal_data = False

###########################
# WEB INTERFACE SETTINNGS #
###########################
Expand Down
Loading

0 comments on commit 3ca10ea

Please sign in to comment.