2020-06-26 13:02:19 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Horus Telemetry GUI - Configuration
|
|
|
|
#
|
|
|
|
# Mark Jessop <vk5qi@rfhead.net>
|
|
|
|
#
|
2020-07-12 04:58:10 +00:00
|
|
|
import json
|
2020-06-26 13:02:19 +00:00
|
|
|
import logging
|
|
|
|
import os
|
2020-07-05 05:19:51 +00:00
|
|
|
from pyqtgraph.Qt import QtCore
|
2020-06-26 13:02:19 +00:00
|
|
|
from ruamel.yaml import YAML
|
|
|
|
from . import __version__
|
2020-07-06 08:43:29 +00:00
|
|
|
from .modem import populate_modem_settings
|
2020-07-16 09:10:25 +00:00
|
|
|
from .audio import populate_sample_rates
|
2021-09-04 09:47:45 +00:00
|
|
|
from horusdemodlib.payloads import download_latest_payload_id_list, download_latest_custom_field_list, read_payload_list, read_custom_field_list
|
2020-07-12 04:58:10 +00:00
|
|
|
import horusdemodlib.payloads
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
default_config = {
|
2020-07-05 05:19:51 +00:00
|
|
|
"version": __version__,
|
2020-06-26 13:04:05 +00:00
|
|
|
"audio_device": "None",
|
2020-07-16 09:10:25 +00:00
|
|
|
"audio_sample_rate": "48000",
|
2020-06-26 13:04:05 +00:00
|
|
|
"modem": "Horus Binary v1 (Legacy)",
|
2020-07-06 08:43:29 +00:00
|
|
|
"baud_rate": -1,
|
2020-06-26 13:04:05 +00:00
|
|
|
"habitat_upload_enabled": True,
|
|
|
|
"habitat_call": "N0CALL",
|
|
|
|
"habitat_lat": 0.0,
|
|
|
|
"habitat_lon": 0.0,
|
2022-03-19 00:55:02 +00:00
|
|
|
"habitat_alt": 0.0,
|
2020-06-26 13:04:05 +00:00
|
|
|
"habitat_antenna": "",
|
2020-07-10 11:50:04 +00:00
|
|
|
"habitat_radio": "",
|
2020-06-26 13:04:05 +00:00
|
|
|
"horus_udp_enabled": True,
|
|
|
|
"horus_udp_port": 55672,
|
2020-10-05 07:24:15 +00:00
|
|
|
"ozimux_enabled": False,
|
|
|
|
"ozimux_udp_port": 55683,
|
2022-03-06 05:17:08 +00:00
|
|
|
"rotator_type": "rotctld",
|
|
|
|
"rotator_host": "localhost",
|
|
|
|
"rotator_port": 4533,
|
2020-07-12 04:58:10 +00:00
|
|
|
"payload_list": json.dumps(horusdemodlib.payloads.HORUS_PAYLOAD_LIST),
|
|
|
|
"custom_field_list": json.dumps({})
|
2020-06-26 13:02:19 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
qt_settings = QtCore.QSettings("Project Horus", "Horus-GUI")
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-06 08:55:03 +00:00
|
|
|
def ValueToBool(Value):
|
2020-07-12 04:58:10 +00:00
|
|
|
""" Helper function to deal with QSettings inconsistency in handling boolean values """
|
2020-07-06 08:55:03 +00:00
|
|
|
if isinstance(Value, bool):
|
|
|
|
RetVal = Value
|
|
|
|
else:
|
|
|
|
RetVal = None
|
|
|
|
if isinstance(Value, str):
|
|
|
|
if Value.lower() == 'true':
|
|
|
|
RetVal = True
|
|
|
|
elif Value.lower() == 'false':
|
|
|
|
RetVal = False
|
|
|
|
else:
|
|
|
|
RetVal = bool(Value)
|
|
|
|
|
|
|
|
return RetVal
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
def write_config():
|
|
|
|
""" Write global settings into QSettings """
|
|
|
|
global default_config, qt_settings
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
# Write all settings
|
|
|
|
for _setting in default_config:
|
|
|
|
qt_settings.setValue(_setting, default_config[_setting])
|
|
|
|
|
2020-07-12 04:58:10 +00:00
|
|
|
logging.info("Current configuration saved.")
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
def read_config(widgets):
|
|
|
|
""" Read in configuration settings from Qt """
|
|
|
|
global qt_settings, default_config
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2022-09-17 10:26:10 +00:00
|
|
|
OK_VERSIONS = [__version__, '0.3.8', '0.3.7', '0.3.6', '0.3.5', '0.3.4', '0.3.1', '0.2.1']
|
2021-01-30 00:28:14 +00:00
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
# Try and read in the version parameter from QSettings
|
2021-01-30 00:28:14 +00:00
|
|
|
if qt_settings.value("version") not in OK_VERSIONS:
|
2020-07-05 05:19:51 +00:00
|
|
|
logging.debug("Configuration out of date, clearing and overwriting.")
|
|
|
|
write_config()
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
for _setting in default_config:
|
2022-03-06 05:17:08 +00:00
|
|
|
try:
|
|
|
|
_new_setting = qt_settings.value(_setting)
|
|
|
|
if _new_setting:
|
|
|
|
default_config[_setting] = _new_setting
|
|
|
|
except Exception as e:
|
|
|
|
logging.debug("Missing config setting: " + _setting)
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
if widgets:
|
|
|
|
# Habitat Settings
|
2020-07-06 08:55:03 +00:00
|
|
|
widgets["habitatUploadSelector"].setChecked(ValueToBool(default_config["habitat_upload_enabled"]))
|
2020-07-05 05:19:51 +00:00
|
|
|
widgets["userCallEntry"].setText(str(default_config["habitat_call"]))
|
|
|
|
widgets["userLatEntry"].setText(str(default_config["habitat_lat"]))
|
|
|
|
widgets["userLonEntry"].setText(str(default_config["habitat_lon"]))
|
2022-03-19 00:55:02 +00:00
|
|
|
widgets["userAltEntry"].setText(str(default_config["habitat_alt"]))
|
2020-07-05 05:19:51 +00:00
|
|
|
widgets["userAntennaEntry"].setText(str(default_config["habitat_antenna"]))
|
|
|
|
widgets["userRadioEntry"].setText(str(default_config["habitat_radio"]))
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
# Horus Settings
|
2020-07-06 08:55:03 +00:00
|
|
|
widgets["horusUploadSelector"].setChecked(ValueToBool(default_config["horus_udp_enabled"]))
|
2020-07-05 05:19:51 +00:00
|
|
|
widgets["horusUDPEntry"].setText(str(default_config["horus_udp_port"]))
|
2020-10-05 07:24:15 +00:00
|
|
|
widgets["ozimuxUploadSelector"].setChecked(ValueToBool(default_config["ozimux_enabled"]))
|
|
|
|
widgets["ozimuxUDPEntry"].setText(str(default_config["ozimux_udp_port"]))
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
# Try and set the audio device.
|
|
|
|
# If the audio device is not in the available list of devices, this will fail silently.
|
2020-07-05 05:19:51 +00:00
|
|
|
widgets["audioDeviceSelector"].setCurrentText(default_config["audio_device"])
|
2020-07-16 09:10:25 +00:00
|
|
|
# Populate the list of valid sample rates
|
|
|
|
populate_sample_rates(widgets)
|
|
|
|
# Attempt to set the configured sample rate. This will fail silently if it does not exist.
|
|
|
|
widgets["audioSampleRateSelector"].setCurrentText(str(default_config["audio_sample_rate"]))
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
# Try and set the modem. If the modem is not valid, this will fail silently.
|
2020-07-05 05:19:51 +00:00
|
|
|
widgets["horusModemSelector"].setCurrentText(default_config["modem"])
|
2020-07-06 08:43:29 +00:00
|
|
|
# Populate the default settings.
|
|
|
|
populate_modem_settings(widgets)
|
|
|
|
|
2022-03-06 05:17:08 +00:00
|
|
|
# Rotator Settings
|
|
|
|
widgets["rotatorTypeSelector"].setCurrentText(default_config["rotator_type"])
|
|
|
|
widgets["rotatorHostEntry"].setText(str(default_config["rotator_host"]))
|
|
|
|
widgets["rotatorPortEntry"].setText(str(default_config["rotator_port"]))
|
|
|
|
|
2020-07-06 08:43:29 +00:00
|
|
|
if default_config['baud_rate'] != -1:
|
|
|
|
widgets["horusModemRateSelector"].setCurrentText(str(default_config['baud_rate']))
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-12 04:58:10 +00:00
|
|
|
if 'payload_list' in default_config:
|
|
|
|
_payloads = json.loads(default_config['payload_list'])
|
|
|
|
# JSON converts the int dictionary keys into strings... annoying!
|
|
|
|
_temp = {}
|
|
|
|
for _key in _payloads:
|
|
|
|
_temp[int(_key)] = _payloads[_key]
|
|
|
|
|
|
|
|
default_config['payload_list'] = _temp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
|
2020-07-05 05:19:51 +00:00
|
|
|
def save_config(widgets):
|
2020-06-26 13:02:19 +00:00
|
|
|
""" Write out settings to a config file """
|
|
|
|
global default_config
|
|
|
|
|
|
|
|
if widgets:
|
2020-06-26 13:04:05 +00:00
|
|
|
default_config["habitat_upload_enabled"] = widgets[
|
|
|
|
"habitatUploadSelector"
|
|
|
|
].isChecked()
|
|
|
|
default_config["habitat_call"] = widgets["userCallEntry"].text()
|
|
|
|
default_config["habitat_lat"] = float(widgets["userLatEntry"].text())
|
|
|
|
default_config["habitat_lon"] = float(widgets["userLonEntry"].text())
|
2022-03-19 00:55:02 +00:00
|
|
|
default_config["habitat_alt"] = float(widgets["userAltEntry"].text())
|
2020-06-26 13:04:05 +00:00
|
|
|
default_config["habitat_antenna"] = widgets["userAntennaEntry"].text()
|
|
|
|
default_config["habitat_radio"] = widgets["userRadioEntry"].text()
|
|
|
|
default_config["horus_udp_enabled"] = widgets["horusUploadSelector"].isChecked()
|
|
|
|
default_config["horus_udp_port"] = int(widgets["horusUDPEntry"].text())
|
2020-10-05 07:24:15 +00:00
|
|
|
default_config["ozimux_enabled"] = widgets["ozimuxUploadSelector"].isChecked()
|
|
|
|
default_config["ozimux_udp_port"] = int(widgets["ozimuxUDPEntry"].text())
|
2020-06-26 13:04:05 +00:00
|
|
|
default_config["audio_device"] = widgets["audioDeviceSelector"].currentText()
|
2020-07-16 09:10:25 +00:00
|
|
|
default_config["audio_sample_rate"] = widgets["audioSampleRateSelector"].currentText()
|
2020-06-26 13:04:05 +00:00
|
|
|
default_config["modem"] = widgets["horusModemSelector"].currentText()
|
2020-07-06 08:43:29 +00:00
|
|
|
default_config["baud_rate"] = int(widgets["horusModemRateSelector"].currentText())
|
2022-03-06 05:17:08 +00:00
|
|
|
default_config["rotator_type"] = widgets["rotatorTypeSelector"].currentText()
|
|
|
|
default_config["rotator_host"] = widgets["rotatorHostEntry"].text()
|
|
|
|
default_config["rotator_port"] = int(widgets["rotatorPortEntry"].text())
|
2020-06-26 13:04:05 +00:00
|
|
|
|
2020-07-12 04:58:10 +00:00
|
|
|
default_config["payload_list"] = json.dumps(horusdemodlib.payloads.HORUS_PAYLOAD_LIST)
|
|
|
|
default_config["custom_field_list"] = json.dumps(horusdemodlib.payloads.HORUS_CUSTOM_FIELDS)
|
|
|
|
|
2020-06-26 13:04:05 +00:00
|
|
|
# Write out to config file
|
2020-07-05 05:19:51 +00:00
|
|
|
write_config()
|
2020-06-26 13:02:19 +00:00
|
|
|
|
|
|
|
|
2021-09-04 09:47:45 +00:00
|
|
|
def init_payloads(payload_id_list=None, custom_field_list=None):
|
2020-07-12 04:58:10 +00:00
|
|
|
""" Attempt to download the latest payload / config data, and update local configs """
|
|
|
|
global default_config
|
|
|
|
|
|
|
|
# Attempt to grab the payload list.
|
2021-09-04 09:47:45 +00:00
|
|
|
if payload_id_list is None:
|
|
|
|
_payload_list = download_latest_payload_id_list(timeout=3)
|
|
|
|
else:
|
|
|
|
logging.info(f"Using supplied Payload ID list file: {payload_id_list}")
|
|
|
|
_payload_list = read_payload_list(payload_id_list)
|
|
|
|
|
2020-07-12 04:58:10 +00:00
|
|
|
if _payload_list:
|
|
|
|
# Sanity check the result
|
|
|
|
if 0 in _payload_list:
|
|
|
|
horusdemodlib.payloads.HORUS_PAYLOAD_LIST = _payload_list
|
|
|
|
logging.info(f"Updated Payload List Successfuly!")
|
|
|
|
else:
|
2021-09-04 09:47:45 +00:00
|
|
|
logging.critical("Could not read payload list!")
|
2020-07-12 04:58:10 +00:00
|
|
|
else:
|
|
|
|
if 'payload_list' in default_config:
|
|
|
|
# Maybe we have a stored config we can use.
|
|
|
|
try:
|
|
|
|
_payload_list = default_config['payload_list']
|
|
|
|
if 0 in _payload_list:
|
|
|
|
horusdemodlib.payloads.HORUS_PAYLOAD_LIST = _payload_list
|
|
|
|
logging.warning(f"Loaded Payload List from local cache, may be out of date!")
|
|
|
|
else:
|
|
|
|
logging.critical("Could not read stored payload list!")
|
|
|
|
except Exception as e:
|
|
|
|
logging.critical(f"Could not read stored payload list - {str(e)}")
|
|
|
|
else:
|
|
|
|
logging.critical("Payload list not available in local storage!")
|
|
|
|
|
|
|
|
logging.info(f"Payload List contains {len(list(horusdemodlib.payloads.HORUS_PAYLOAD_LIST.keys()))} entries.")
|
|
|
|
|
2021-09-04 09:47:45 +00:00
|
|
|
if custom_field_list is None:
|
|
|
|
_custom_fields = download_latest_custom_field_list(timeout=3)
|
|
|
|
else:
|
|
|
|
logging.info(f"Using supplied Custom Field List file: {custom_field_list}")
|
|
|
|
_custom_fields = read_custom_field_list(custom_field_list)
|
|
|
|
|
2020-07-12 04:58:10 +00:00
|
|
|
if _custom_fields:
|
|
|
|
# Sanity Check
|
2021-09-04 09:47:45 +00:00
|
|
|
if '4FSKTEST-V2' in _custom_fields:
|
2020-07-12 04:58:10 +00:00
|
|
|
horusdemodlib.payloads.HORUS_CUSTOM_FIELDS = _custom_fields
|
|
|
|
logging.info(f"Updated Custom Field List Successfuly!")
|
|
|
|
else:
|
2021-09-04 09:47:45 +00:00
|
|
|
logging.critical("Could not read custom field list!")
|
2020-07-12 04:58:10 +00:00
|
|
|
else:
|
|
|
|
if 'custom_field_list' in default_config:
|
|
|
|
# Maybe we have a stored config we can use.
|
|
|
|
try:
|
|
|
|
_custom_fields = json.loads(default_config['custom_field_list'])
|
2021-09-04 09:47:45 +00:00
|
|
|
if '4FSKTEST-V2' in _custom_fields:
|
2020-07-12 04:58:10 +00:00
|
|
|
horusdemodlib.payloads.HORUS_CUSTOM_FIELDS = _custom_fields
|
|
|
|
logging.warning("Loaded Custom Fields List from local cache, may be out of date!")
|
|
|
|
else:
|
|
|
|
logging.critical("Could not read stored custom fields list!")
|
|
|
|
except Exception as e:
|
|
|
|
logging.critical(f"Could not read stored custom fields list - {str(e)}")
|
|
|
|
else:
|
|
|
|
logging.critical("Custom Field list not available in local storage!")
|
|
|
|
|
|
|
|
logging.info(f"Custom Field list contains {len(list(horusdemodlib.payloads.HORUS_CUSTOM_FIELDS.keys()))} entries.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
if __name__ == "__main__":
|
2020-07-05 05:19:51 +00:00
|
|
|
import sys
|
|
|
|
# Setup Logging
|
|
|
|
logging.basicConfig(
|
|
|
|
format="%(asctime)s %(levelname)s: %(message)s", level=logging.DEBUG
|
|
|
|
)
|
|
|
|
|
|
|
|
if len(sys.argv) >= 2:
|
|
|
|
write_config()
|
|
|
|
|
2020-06-26 13:02:19 +00:00
|
|
|
read_config(None)
|