Commit f4adb40c authored by Manolis Surligas's avatar Manolis Surligas 🚀

Add support for different framing schemes

Signed-off-by: Manolis Surligas's avatarManolis Surligas <[email protected]>
parent dfdff47d
class Flowgraph():
"""
Specify configuration parameters of a SatNOGS flowgraph
:param script_name: The executable script name of the flowgraph
:type script_name: str
:param has_baudrate: Indicates if the flowgraph supports a baudrate option
:type has_baudrate: bool, optional
:param has_framing: Indicates if the flowgraph supports a framing option
:type has_framing: bool, optional
:param framing: A gr-satnogs compatible string specifying the framing to use
:type framing: str, optional
"""
def __init__(self, script_name, has_baudrate=False, has_framing=False, framing="ax25"):
self._script_name = script_name
self._has_baudrate = has_baudrate
self._has_framing = has_framing
self._framing = framing
def script_name(self):
return self._script_name
def has_baudrate(self):
return self._has_baudrate
def has_framing(self):
return self._has_framing
def framing(self):
if not self._has_framing:
print('Flowgraph does not support any framing scheme')
raise ValueError()
return self._framing
......@@ -43,19 +43,19 @@ class Observer(object):
self.timestamp = None
self.observation_end = None
self.frequency = None
self.mode = None
self.baud = None
self.observation_raw_file = None
self.observation_ogg_file = None
self.observation_waterfall_file = None
self.observation_waterfall_png = None
self.observation_receiving_decoded_data = None # pylint: disable=C0103
self.observation_decoded_data = None
self.baud = None
self.observation_done_decoded_data = None
self.tracker_freq = None
self.tracker_rot = None
self.script_name = None
def setup(self, observation_id, tle, observation_end, frequency, baud, script_name):
def setup(self, observation_id, tle, observation_end, frequency, mode, baud):
"""
Sets up required internal variables.
* returns True if setup is ok
......@@ -64,11 +64,11 @@ class Observer(object):
# Set attributes
self.observation_id = observation_id
self.script_name = script_name
self.tle = tle
self.observation_end = observation_end
self.frequency = frequency
self.baud = baud
self.mode = mode
not_completed_prefix = 'receiving_satnogs'
completed_prefix = 'satnogs'
......@@ -121,7 +121,7 @@ class Observer(object):
("{{TIMESTAMP}}", self.timestamp),
("{{ID}}", str(self.observation_id)),
("{{BAUD}}", str(self.baud)),
("{{SCRIPT_NAME}}", self.script_name),
("{{SCRIPT_NAME}}", gnuradio_handler.get_flowgraph_script_name(self.mode)),
]
pre_script = []
for arg in shlex.split(settings.SATNOGS_PRE_OBSERVATION_SCRIPT):
......@@ -132,7 +132,7 @@ class Observer(object):
# if it is APT we want to save with a prefix until the observation
# is complete, then rename.
if settings.GNURADIO_APT_SCRIPT_FILENAME in self.script_name:
if self.mode == "APT":
self.observation_decoded_data =\
self.observation_receiving_decoded_data
......@@ -146,18 +146,16 @@ class Observer(object):
LOGGER.info('Start gnuradio thread.')
self._gnu_proc = gnuradio_handler.exec_gnuradio(self.observation_raw_file,
self.observation_waterfall_file,
self.frequency, self.baud,
self.script_name,
self.frequency, self.mode, self.baud,
self.observation_decoded_data)
# Polling gnuradio process status
self.poll_gnu_proc_status()
if "satnogs_generic_iq_receiver.py" not in settings.GNURADIO_SCRIPT_FILENAME:
LOGGER.info('Rename encoded files for uploading.')
self.rename_ogg_file()
self.rename_data_file()
LOGGER.info('Creating waterfall plot.')
self.plot_waterfall()
# Rename files and create waterfall
self.rename_ogg_file()
self.rename_data_file()
LOGGER.info('Creating waterfall plot.')
self.plot_waterfall()
# PUT client version and metadata
base_url = urljoin(settings.SATNOGS_NETWORK_API_URL, 'observations/')
......@@ -233,7 +231,7 @@ class Observer(object):
("{{TIMESTAMP}}", self.timestamp),
("{{ID}}", str(self.observation_id)),
("{{BAUD}}", str(self.baud)),
("{{SCRIPT_NAME}}", self.script_name),
("{{SCRIPT_NAME}}", gnuradio_handler.get_flowgraph_script_name(self.mode)),
]
post_script = []
for arg in shlex.split(settings.SATNOGS_POST_OBSERVATION_SCRIPT):
......@@ -243,25 +241,30 @@ class Observer(object):
subprocess.call(post_script)
def rename_ogg_file(self):
if os.path.isfile(self.observation_raw_file):
try:
os.rename(self.observation_raw_file, self.observation_ogg_file)
LOGGER.info('Rename encoded file for uploading finished')
LOGGER.info('Rename encoded file for uploading finished')
except FileNotFoundError:
LOGGER.error('Failed to rename encoded file')
def rename_data_file(self):
if os.path.isfile(self.observation_receiving_decoded_data):
try:
os.rename(self.observation_receiving_decoded_data, self.observation_done_decoded_data)
LOGGER.info('Rename data file for uploading finished')
LOGGER.info('Rename data file for uploading finished')
except FileNotFoundError:
LOGGER.error('Failed to rename data file')
def plot_waterfall(self):
if os.path.isfile(self.observation_waterfall_file):
try:
plot_waterfall(waterfall_file=self.observation_waterfall_file,
waterfall_png=self.observation_waterfall_png)
if os.path.isfile(self.observation_waterfall_png) and \
settings.SATNOGS_REMOVE_RAW_FILES:
if settings.SATNOGS_REMOVE_RAW_FILES:
self.remove_waterfall_file()
else:
except FileNotFoundError:
LOGGER.error('No waterfall data file found')
def remove_waterfall_file(self):
if os.path.isfile(self.observation_waterfall_file):
try:
os.remove(self.observation_waterfall_file)
except FileNotFoundError:
LOGGER.error('Failed to remove waterfall file')
......@@ -32,46 +32,19 @@ def spawn_observer(**kwargs):
'lat': settings.SATNOGS_STATION_LAT,
'elev': settings.SATNOGS_STATION_ELEV
}
frequency = 100e6
# Get the baudrate. In case of CW baudrate equals the WPM
baud = 0
if 'baud' in obj:
baud = obj['baud']
frequency = obj['frequency']
script_name = settings.GNURADIO_SCRIPT_FILENAME
if 'mode' in obj and obj['mode']:
if obj['mode'] == "CW":
script_name = settings.GNURADIO_CW_SCRIPT_FILENAME
elif obj['mode'] == "APT":
script_name = settings.GNURADIO_APT_SCRIPT_FILENAME
elif obj['mode'].endswith('BPSK PMT-A3'):
script_name = settings.GNURADIO_ARGOS_BPSK_PMT_A3
elif obj['mode'].startswith('BPSK'):
script_name = settings.GNURADIO_BPSK_SCRIPT_FILENAME
elif obj['mode'] == 'GFSK Rktr':
script_name = settings.GNURADIO_GFSK_RKTR_SCRIPT_FILENAME
# FSK and MSK share the same flowgraph
elif (obj['mode'].startswith('FSK') or obj['mode'].startswith('GFSK')
or obj['mode'].startswith('MSK') or obj['mode'].startswith('GMSK')):
script_name = settings.GNURADIO_FSK_SCRIPT_FILENAME
elif obj['mode'].endswith('AFSK S-Net'):
script_name = settings.GNURADIO_AFSK_SNET_SCRIPT_FILENAME
elif obj['mode'].endswith('AFSK SALSAT'):
script_name = settings.GNURADIO_AFSK_SALSAT_SCRIPT_FILENAME
elif obj['mode'].endswith('AFSK1k2'):
script_name = settings.GNURADIO_AFSK1K2_SCRIPT_FILENAME
elif obj['mode'].endswith('DUV'):
script_name = settings.GNURADIO_AMSAT_DUV_SCRIPT_FILENAME
elif obj['mode'].endswith('SSTV'):
script_name = settings.GNURADIO_SSTV_SCRIPT_FILENAME
setup_kwargs = {
'observation_id': obj['id'],
'tle': tle,
'observation_end': end,
'frequency': frequency,
'baud': baud,
'script_name': script_name
'frequency': obj['frequency'],
'mode': obj['mode'],
'baud': baud
}
LOGGER.debug('Observer args: %s', setup_kwargs)
......
......@@ -63,19 +63,104 @@ SATNOGS_NETWORK_API_TIMEOUT = 1800 # In seconds
GNURADIO_UDP_PORT = 16886
GNURADIO_IP = '127.0.0.1'
GNURADIO_SCRIPT_PATH = ['/usr/bin', '/usr/local/bin']
GNURADIO_SCRIPT_FILENAME = 'satnogs_fsk_ax25.py'
GNURADIO_DEFAULT_SCRIPT_FILENAME = 'satnogs_fsk.py'
GNURADIO_CW_SCRIPT_FILENAME = 'satnogs_cw_decoder.py'
GNURADIO_APT_SCRIPT_FILENAME = 'satnogs_noaa_apt_decoder.py'
GNURADIO_BPSK_SCRIPT_FILENAME = 'satnogs_bpsk_ax25.py'
GNURADIO_BPSK_SCRIPT_FILENAME = 'satnogs_bpsk.py'
GNURADIO_GFSK_RKTR_SCRIPT_FILENAME = 'satnogs_reaktor_hello_world_fsk9600_decoder.py'
GNURADIO_FSK_SCRIPT_FILENAME = 'satnogs_fsk_ax25.py'
GNURADIO_FSK_SCRIPT_FILENAME = 'satnogs_fsk.py'
GNURADIO_AFSK1K2_SCRIPT_FILENAME = 'satnogs_afsk1200_ax25.py'
GNURADIO_AFSK_SALSAT_SCRIPT_FILENAME = 'satnogs_afsk_salsat.py'
GNURADIO_AFSK_SNET_SCRIPT_FILENAME = 'satnogs_afsk_snet.py'
GNURADIO_AMSAT_DUV_SCRIPT_FILENAME = 'satnogs_amsat_fox_duv_decoder.py'
GNURADIO_SSTV_SCRIPT_FILENAME = 'satnogs_sstv_pd120_demod.py'
GNURADIO_ARGOS_BPSK_PMT_A3 = 'satnogs_argos_bpsk_ldr.py'
# Dictionary with the modes from the SatNOGS network as keys
SATNOGS_FLOWGRAPHS = {
"AFSK": {
'script_name': GNURADIO_AFSK1K2_SCRIPT_FILENAME,
'has_baudrate': False,
'has_framing': False
},
"APT": {
'script_name': GNURADIO_APT_SCRIPT_FILENAME,
'has_baudrate': False,
'has_framing': False,
},
"BPSK PMT-A3": {
'script_name': GNURADIO_ARGOS_BPSK_PMT_A3,
'has_baudrate': True,
'has_framing': False
},
"CW": {
'script_name': GNURADIO_CW_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': False
},
"DUV": {
'script_name': GNURADIO_AMSAT_DUV_SCRIPT_FILENAME,
'has_baudrate': False,
'has_framing': False
},
"FSK": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax25'
},
"FSK AX.100 Mode 5": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax100_mode5'
},
"FSK AX.100 Mode 6": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax100_mode6'
},
"GFSK": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax25'
},
"GFSK Rktr": {
'script_name': GNURADIO_GFSK_RKTR_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': False
},
"GMSK": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax25'
},
"MSK": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax25'
},
"MSK AX.100 Mode 5": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax100_mode5'
},
"MSK AX.100 Mode 6": {
'script_name': GNURADIO_FSK_SCRIPT_FILENAME,
'has_baudrate': True,
'has_framing': True,
'framing': 'ax100_mode6'
},
"SSTV": {
'script_name': GNURADIO_SSTV_SCRIPT_FILENAME,
'has_baudrate': False,
'has_framing': False
},
}
SATNOGS_ROT_MODEL = environ.get('SATNOGS_ROT_MODEL', 'ROT_MODEL_DUMMY')
SATNOGS_ROT_BAUD = int(environ.get('SATNOGS_ROT_BAUD', 19200))
SATNOGS_ROT_PORT = environ.get('SATNOGS_ROT_PORT', '/dev/ttyUSB0')
......
......@@ -47,29 +47,41 @@ def get_gnuradio_info():
return client_metadata
def exec_gnuradio(observation_file, waterfall_file, freq, baud, script_name, decoded_data):
if not script_name:
script_name = client_settings.GNURADIO_SCRIPT_FILENAME
device = client_settings.SATNOGS_SOAPY_RX_DEVICE
samp_rate = client_settings.SATNOGS_RX_SAMP_RATE
def get_flowgraph_script_name(mode=''):
"""
Returns the GNU Radio flowgraph script name that will be executed based on the
given mode, or the default one if no mode is specified
"""
if mode not in client_settings.SATNOGS_FLOWGRAPHS:
return client_settings.GNURADIO_DEFAULT_SCRIPT_FILENAME
return client_settings.SATNOGS_FLOWGRAPHS[mode]['script_name']
def exec_gnuradio(observation_file, waterfall_file, freq, mode, baud, decoded_data):
args = [
script_name, '--soapy-rx-device=' + device, '--samp-rate-rx=' + str(samp_rate),
'--rx-freq=' + str(freq), '--file-path=' + observation_file
get_flowgraph_script_name(mode),
'--soapy-rx-device=' + client_settings.SATNOGS_SOAPY_RX_DEVICE,
'--samp-rate-rx=' + str(client_settings.SATNOGS_RX_SAMP_RATE), '--rx-freq=' + str(freq),
'--file-path=' + observation_file
]
if waterfall_file != "":
args += ['--waterfall-file-path=' + waterfall_file]
# If this is a CW observation pass the WPM parameter
if script_name == client_settings.GNURADIO_CW_SCRIPT_FILENAME and baud:
args += ['--wpm=' + str(int(baud))]
# If this is a BPSK/FSK/MSK observation pass the baudrate parameter
if script_name in [
client_settings.GNURADIO_BPSK_SCRIPT_FILENAME,
client_settings.GNURADIO_GFSK_RKTR_SCRIPT_FILENAME,
client_settings.GNURADIO_FSK_SCRIPT_FILENAME,
client_settings.GNURADIO_ARGOS_BPSK_PMT_A3,
] and baud:
args += ['--baudrate=' + str(int(baud))]
# Apply baudrate on the supported flowgraphs
if mode in client_settings.SATNOGS_FLOWGRAPHS:
if baud and client_settings.SATNOGS_FLOWGRAPHS[mode]['has_baudrate']:
# If this is a CW observation pass the WPM parameter
if mode == "CW":
args += ['--wpm=' + str(int(baud))]
else:
args += ['--baudrate=' + str(int(baud))]
# Apply framing mode
if mode in client_settings.SATNOGS_FLOWGRAPHS:
if client_settings.SATNOGS_FLOWGRAPHS[mode]['has_framing']:
args += ['--framing=' + client_settings.SATNOGS_FLOWGRAPHS[mode]['framing']]
if client_settings.SATNOGS_DOPPLER_CORR_PER_SEC:
args += ['--doppler-correction-per-sec=' + client_settings.SATNOGS_DOPPLER_CORR_PER_SEC]
if client_settings.SATNOGS_LO_OFFSET:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment