kopia lustrzana https://github.com/projecthorus/horus-gui
				
				
				
			Updates to support v2 telemetry
							rodzic
							
								
									38628217be
								
							
						
					
					
						commit
						6becf68ebf
					
				| 
						 | 
				
			
			@ -3,10 +3,10 @@
 | 
			
		|||
Telemetry demodulator for the following modems in use by Project Horus
 | 
			
		||||
* Horus Binary Modes (4FSK)
 | 
			
		||||
  * v1 - Legacy 22 byte mode, Golay(23,12) FEC
 | 
			
		||||
  * v2 - 16/32-byte modes, LDPC FEC (Under development)
 | 
			
		||||
  * v2 - 32-byte mode, Golay(23,12) FEC
 | 
			
		||||
* RTTY (7N1, 7N2 and 8N2, standard [UKHAS sentences](https://ukhas.org.uk/communication:protocol) with CRC16 only)
 | 
			
		||||
 | 
			
		||||
This project serves as a graphical front-end to [horusdemodlib](https://github.com/projecthorus/horusdemodlib) a Python/C library of telemetry demodulators based off the [codec2](https://github.com/drowe67/codec2) FSK modem. The core modem used in this library is very well tested, and performs in line with incoherent FSK demodulator theory. The RTTY decoder is approximately [2dB better](http://www.rowetel.com/?p=5906) than dl-fldigi, and the Horus Binary v1 modem approximately 7 dB better again. Once finished, the Horus Binary v2 modes should provide more flexibility over the v1 mode, and provide further performance improvements.
 | 
			
		||||
This project serves as a graphical front-end to [horusdemodlib](https://github.com/projecthorus/horusdemodlib) a Python/C library of telemetry demodulators based off the [codec2](https://github.com/drowe67/codec2) FSK modem. The core modem used in this library is very well tested, and performs in line with incoherent FSK demodulator theory. The RTTY decoder is approximately [2dB better](http://www.rowetel.com/?p=5906) than dl-fldigi, and the Horus Binary modem approximately 7 dB better again. The Horus Binary v2 mode provides some additional flexibility over the v1 mode, allowing the addition of custom telemetry fields.
 | 
			
		||||
 | 
			
		||||
### Important Performance Notes
 | 
			
		||||
The FSK demodulator at the core of this application expects the transmitter to behave like a modem. That is, it should:
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,6 @@ Written by:
 | 
			
		|||
* Python Library - Mark Jessop <vk5qi@rfhead.net>
 | 
			
		||||
* FSK Modem - [David Rowe](http://rowetel.com)
 | 
			
		||||
* FSK Modem Python Wrapper - [XSSFox](https://twitter.com/xssfox)
 | 
			
		||||
* LDPC Codes - [Bill Cowley](http://lowsnr.org/)
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
__version__ = "0.1.17"
 | 
			
		||||
__version__ = "0.2.1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ from ruamel.yaml import YAML
 | 
			
		|||
from . import __version__
 | 
			
		||||
from .modem import populate_modem_settings
 | 
			
		||||
from .audio import populate_sample_rates
 | 
			
		||||
from horusdemodlib.payloads import download_latest_payload_id_list, download_latest_custom_field_list
 | 
			
		||||
from horusdemodlib.payloads import download_latest_payload_id_list, download_latest_custom_field_list, read_payload_list, read_custom_field_list
 | 
			
		||||
import horusdemodlib.payloads
 | 
			
		||||
 | 
			
		||||
default_config = {
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ def read_config(widgets):
 | 
			
		|||
    """ Read in configuration settings from Qt """
 | 
			
		||||
    global qt_settings, default_config
 | 
			
		||||
 | 
			
		||||
    OK_VERSIONS = [__version__, "0.1.15", "0.1.14"]
 | 
			
		||||
    OK_VERSIONS = [__version__]
 | 
			
		||||
    
 | 
			
		||||
    # Try and read in the version parameter from QSettings
 | 
			
		||||
    if qt_settings.value("version") not in OK_VERSIONS:
 | 
			
		||||
| 
						 | 
				
			
			@ -153,19 +153,24 @@ def save_config(widgets):
 | 
			
		|||
        write_config()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def init_payloads():
 | 
			
		||||
def init_payloads(payload_id_list=None, custom_field_list=None):
 | 
			
		||||
    """ Attempt to download the latest payload / config data, and update local configs """
 | 
			
		||||
    global default_config
 | 
			
		||||
 | 
			
		||||
    # Attempt to grab the payload list.
 | 
			
		||||
    _payload_list = download_latest_payload_id_list(timeout=3)
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    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:
 | 
			
		||||
            logging.critical("Could not read downloaded payload list!")
 | 
			
		||||
            logging.critical("Could not read payload list!")
 | 
			
		||||
    else:
 | 
			
		||||
        if 'payload_list' in default_config:
 | 
			
		||||
            # Maybe we have a stored config we can use.
 | 
			
		||||
| 
						 | 
				
			
			@ -183,20 +188,25 @@ def init_payloads():
 | 
			
		|||
 | 
			
		||||
    logging.info(f"Payload List contains {len(list(horusdemodlib.payloads.HORUS_PAYLOAD_LIST.keys()))} entries.")
 | 
			
		||||
 | 
			
		||||
    _custom_fields = download_latest_custom_field_list(timeout=3)
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    if _custom_fields:
 | 
			
		||||
        # Sanity Check
 | 
			
		||||
        if 'HORUSTEST' in _custom_fields:
 | 
			
		||||
        if '4FSKTEST-V2' in _custom_fields:
 | 
			
		||||
            horusdemodlib.payloads.HORUS_CUSTOM_FIELDS = _custom_fields
 | 
			
		||||
            logging.info(f"Updated Custom Field List Successfuly!")
 | 
			
		||||
        else:
 | 
			
		||||
            logging.critical("Could not read downloaded custom field list!")
 | 
			
		||||
            logging.critical("Could not read custom field list!")
 | 
			
		||||
    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'])
 | 
			
		||||
                if 'HORUSTEST' in _custom_fields:
 | 
			
		||||
                if '4FSKTEST-V2' in _custom_fields:
 | 
			
		||||
                    horusdemodlib.payloads.HORUS_CUSTOM_FIELDS = _custom_fields
 | 
			
		||||
                    logging.warning("Loaded Custom Fields List from local cache, may be out of date!")
 | 
			
		||||
                else:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ if sys.version_info < (3, 0):
 | 
			
		|||
    print("This script requires Python 3!")
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
import argparse
 | 
			
		||||
import datetime
 | 
			
		||||
import glob
 | 
			
		||||
import logging
 | 
			
		||||
| 
						 | 
				
			
			@ -39,8 +40,6 @@ from horusdemodlib.payloads import *
 | 
			
		|||
from horusdemodlib.horusudp import send_payload_summary, send_ozimux_message
 | 
			
		||||
from . import __version__
 | 
			
		||||
 | 
			
		||||
# Setup Logging
 | 
			
		||||
logging.basicConfig(format="%(asctime)s %(levelname)s: %(message)s", level=logging.INFO)
 | 
			
		||||
 | 
			
		||||
# A few hardcoded defaults
 | 
			
		||||
DEFAULT_ESTIMATOR_MIN = 100
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +68,23 @@ decoder_init = False
 | 
			
		|||
# Global running indicator
 | 
			
		||||
running = False
 | 
			
		||||
 | 
			
		||||
# Read command-line arguments
 | 
			
		||||
parser = argparse.ArgumentParser(description="Project Horus GUI", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
 | 
			
		||||
parser.add_argument("--payload-id-list", type=str, default=None, help="Use supplied Payload ID List instead of downloading a new one.")
 | 
			
		||||
parser.add_argument("--custom-field-list", type=str, default=None, help="Use supplied Custom Field List instead of downloading a new one.")
 | 
			
		||||
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Verbose output (set logging level to DEBUG)")
 | 
			
		||||
args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
if args.verbose:
 | 
			
		||||
    _log_level = logging.DEBUG
 | 
			
		||||
else:
 | 
			
		||||
    _log_level = logging.INFO
 | 
			
		||||
 | 
			
		||||
# Setup Logging
 | 
			
		||||
logging.basicConfig(
 | 
			
		||||
    format="%(asctime)s %(levelname)s: %(message)s", level=_log_level
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#   GUI Creation - The Bad way.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -914,7 +930,7 @@ def handle_log_update(log_update):
 | 
			
		|||
# GUI Update Loop
 | 
			
		||||
def processQueues():
 | 
			
		||||
    """ Read in data from the queues, this decouples the GUI and async inputs somewhat. """
 | 
			
		||||
    global fft_update_queue, status_update_queue, decoder_init, widgets
 | 
			
		||||
    global fft_update_queue, status_update_queue, decoder_init, widgets, args
 | 
			
		||||
 | 
			
		||||
    while fft_update_queue.qsize() > 0:
 | 
			
		||||
        _data = fft_update_queue.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -936,7 +952,7 @@ def processQueues():
 | 
			
		|||
 | 
			
		||||
    if not decoder_init:
 | 
			
		||||
        # Initialise decoders, and other libraries here.
 | 
			
		||||
        init_payloads()
 | 
			
		||||
        init_payloads(payload_id_list = args.payload_id_list, custom_field_list = args.custom_field_list)
 | 
			
		||||
        decoder_init = True
 | 
			
		||||
        # Once initialised, enable the start button
 | 
			
		||||
        widgets["startDecodeButton"].setEnabled(True)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
[tool.poetry]
 | 
			
		||||
name = "horusgui"
 | 
			
		||||
version = "0.1.17"
 | 
			
		||||
version = "0.2.1"
 | 
			
		||||
description = ""
 | 
			
		||||
authors = ["Mark Jessop <vk5qi@rfhead.net>"]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ PyQt5 = "^5.13.0"
 | 
			
		|||
pyqtgraph = "^0.11.0"
 | 
			
		||||
pyaudio = "^0.2.11"
 | 
			
		||||
"ruamel.yaml" = "^0.16.10"
 | 
			
		||||
horusdemodlib = "^0.1.21"
 | 
			
		||||
horusdemodlib = "^0.2.2"
 | 
			
		||||
 | 
			
		||||
[tool.poetry.dev-dependencies]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,4 +5,4 @@ PyQt5
 | 
			
		|||
pyqtgraph
 | 
			
		||||
ruamel.yaml
 | 
			
		||||
requests
 | 
			
		||||
horusdemodlib>=0.1.21
 | 
			
		||||
horusdemodlib>=0.2.2
 | 
			
		||||
		Ładowanie…
	
		Reference in New Issue