config fixes and adjustments

This commit is contained in:
DJ2LS 2023-11-14 19:26:11 +01:00
parent 131ec6fa63
commit d74dda0bc5
6 changed files with 123 additions and 53 deletions

View file

@ -17,13 +17,12 @@ class CONFIG:
try:
self.config_name = configfile
except Exception:
self.config_name = "config.ini"
self.log.info("[CFG] logfile init", file=self.config_name)
self.log.info("[CFG] config init", file=self.config_name)
# check if log file exists
# check if config file exists
self.config_exists()
def config_exists(self):
@ -36,30 +35,110 @@ class CONFIG:
self.log.error("[CFG] logfile init error", e=configerror)
return False
def write_config(self, section: str, key: str, value):
"""
write values to config
"""
# Validates config data
def validate_network_settings(self, data):
if 'modemport' in data:
if not isinstance(data['modemport'], int):
raise ValueError("'modemport' in 'NETWORK' must be an integer.")
def validate_station_settings(self, data):
for setting in ['mycall', 'mygrid']:
if setting in data and not data[setting]:
raise ValueError(f"'{setting}' in 'STATION' cannot be empty.")
if 'ssid_list' in data and not isinstance(data['ssid_list'], list):
raise ValueError("'ssid_list' in 'STATION' needs to be a list.")
def validate_audio_settings(self, data):
for setting in ['input_device', 'output_device']:
if setting in data and not isinstance(data[setting], str):
raise ValueError(f"'{setting}' in 'AUDIO' must be a string.")
for setting in ['rx_audio_level', 'tx_audio_level']:
if setting in data and not isinstance(data[setting], int):
raise ValueError(f"'{setting}' in 'AUDIO' must be an integer.")
def validate_radio_settings(self, data):
if 'radioport' in data and not (data['radioport'] is None or isinstance(data['radioport'], int)):
raise ValueError("'radioport' in 'RADIO' must be None or an integer.")
def validate_tci_settings(self, data):
if 'tci_ip' in data and not isinstance(data['tci_ip'], str):
raise ValueError("'tci_ip' in 'TCI' must be a string.")
if 'tci_port' in data and not isinstance(data['tci_port'], int):
raise ValueError("'tci_port' in 'TCI' must be an integer.")
def validate_modem_settings(self, data):
for setting in ['enable_fft', 'enable_fsk', 'enable_low_bandwidth_mode', 'respond_to_cq', 'enable_scatter']:
if setting in data and not isinstance(data[setting], bool):
raise ValueError(f"'{setting}' in 'MODEM' must be a boolean.")
for setting in ['tuning_range_fmax', 'tuning_range_fmin', 'rx_buffer_size', 'tx_delay']:
if setting in data and not isinstance(data[setting], int):
raise ValueError(f"'{setting}' in 'MODEM' must be an integer.")
def validate_mesh_settings(self, data):
if 'enable_protocol' in data and not isinstance(data['enable_protocol'], bool):
raise ValueError("'enable_protocol' in 'MESH' must be a boolean.")
def validate(self, data):
for section in data:
for setting in data[section]:
if section == 'NETWORK':
if setting == 'modemport' and int(data[section][setting]) == 0:
raise Exception("'modemport' should be an integer")
if section == 'STATION':
if setting == 'mycall' and len(data[section][setting]) <= 0:
raise Exception("'%s' can't be empty" % setting)
if setting == 'mygrid' and len(data[section][setting]) <= 0:
raise Exception("'%s' can't be empty" % setting)
if setting == 'ssid_list' and not isinstance(data[section][setting], list):
raise Exception("'%s' needs to be a list" % setting)
# TODO finish this for all config settings!
# Handle special setting data type conversion
for section, settings in data.items():
if section == 'NETWORK':
self.validate_network_settings(settings)
elif section == 'STATION':
self.validate_station_settings(settings)
elif section == 'AUDIO':
self.validate_audio_settings(settings)
elif section == 'RADIO':
self.validate_radio_settings(settings)
elif section == 'TCI':
self.validate_tci_settings(settings)
elif section == 'MESH':
self.validate_mesh_settings(settings)
elif section == 'MODEM':
self.validate_modem_settings(settings)
else:
self.log.warning("wrong config", section=section)
# converts values of settings from String to Value.
# For example 'False' (type String) will be converted to False (type Bool)
def convert_types(self, config):
for setting in config:
value = config[setting]
if isinstance(value, dict):
# If the value is a dictionary, apply the function recursively
config[setting] = self.convert_types(value)
elif isinstance(value, list):
# If the value is a list, iterate through the list
new_list = []
for item in value:
# Apply the function to each dictionary item in the list
if isinstance(item, dict):
new_list.append(self.convert_types(item))
else:
new_list.append(item)
config[setting] = new_list
elif isinstance(value, str):
# Attempt to convert string values
if value.lstrip('-').isdigit():
config[setting] = int(value)
else:
try:
# Try converting to a float
float_value = float(value)
# If it's actually an integer (like -50.0), convert it to an integer
config[setting] = int(float_value) if float_value.is_integer() else float_value
except ValueError:
# Convert to boolean if applicable
if value.lower() in ['true', 'false']:
config[setting] = value.lower() == 'true'
return config
# Handle special setting data type conversion
# is_writing means data from a dict being writen to the config file
# if False, it means the opposite direction
# TODO check if we can include this in function "convert_types"
def handle_setting(self, section, setting, value, is_writing = False):
if (section == 'STATION' and setting == 'ssid_list'):
if (is_writing):
@ -71,7 +150,8 @@ class CONFIG:
# Sets and writes config data from a dict containing data settings
def write(self, data):
# convert datatypes
data = self.convert_types(data)
# Validate config data before writing
self.validate(data)
@ -98,35 +178,18 @@ class CONFIG:
"""
read config file
"""
self.log.info("[CFG] reading...")
if not self.config_exists():
return False
# at first just copy the config as read from file
result = {s:dict(self.config.items(s)) for s in self.config.sections()}
result = self.convert_types(result)
# handle the special settings (like 'ssid_list')
for section in result:
for setting in result[section]:
result[section][setting] = self.handle_setting(
section, setting, result[section][setting], False)
section, setting, result[section][setting], False)
return result
def get(self, area, key, default):
"""
read from config and add if not exists
"""
for _ in range(2):
try:
parameter = (
self.config[area][key] in ["True", "true", True]
if default in ["True", "true", True, "False", "false", False]
else self.config[area][key]
)
except KeyError:
self.config[area][key] = str(default)
self.log.info("[CFG] reading...", parameter=parameter, key=key)
return parameter

View file

@ -285,7 +285,6 @@ class DATA:
def worker_transmit(self) -> None:
"""Dispatch incoming UI instructions for transmitting operations"""
while True:
print("ja?")
data = self.data_queue_transmit.get()
print(data)
@ -365,7 +364,7 @@ class DATA:
self.log.error(
"[Modem] worker_transmit: received invalid command:", data=data
)
print("jaaaa")
def worker_receive(self) -> None:
"""Queue received data for processing"""
while True:

View file

@ -63,6 +63,7 @@ class RF:
def __init__(self, config, event_queue, fft_queue, service_queue, states) -> None:
self.config = config
print(config)
self.service_queue = service_queue
self.states = states
@ -79,7 +80,6 @@ class RF:
self.enable_fft = config['MODEM']['enable_fft']
self.enable_scatter = config['MODEM']['enable_scatter']
self.tx_delay = config['MODEM']['tx_delay']
self.tuning_range_fmin = config['MODEM']['tuning_range_fmin']
self.tuning_range_fmax = config['MODEM']['tuning_range_fmax']

View file

@ -40,7 +40,7 @@ set_config()
# start modem
app.state_queue = queue.Queue() # queue which holds latest states
app.modem_events = queue.Queue() # queue which holds latest events
app.modem_fft = queue.Queue() # queue which holds lates fft data
app.modem_fft = queue.Queue() # queue which holds latest fft data
app.modem_service = queue.Queue() # start / stop modem service
# init state manager
@ -204,8 +204,11 @@ def sock_watchdog(sock, client_list, event_queue):
try:
sock.receive(timeout=1)
except Exception as e:
print(e)
client_list.remove(sock)
print(f"client connection lost: {e}")
try:
client_list.remove(sock)
except Exception as err:
print(f"error removing client from list: {e} | {err}")
break
return

View file

@ -14,7 +14,7 @@ class SM:
self.modem = False
self.data_handler = False
self.config = app.config_manager.config
self.config = app.config_manager.read()
self.modem_events = app.modem_events
self.modem_fft = app.modem_fft
self.modem_service = app.modem_service

View file

@ -3,7 +3,7 @@ import ujson as json
class STATES:
def __init__(self, statequeue):
self.statequeue = statequeue
self.newstate = None
self.channel_busy = False
self.channel_busy_slot = [False, False, False, False, False]
self.is_codec2_traffic = False
@ -16,7 +16,12 @@ class STATES:
def set(self, key, value):
setattr(self, key, value)
self.statequeue.put(self.getAsJSON())
# only process data if changed
new_state = self.getAsJSON()
if new_state != self.newstate:
self.statequeue.put(new_state)
self.newstate = new_state
def getAsJSON(self):
return json.dumps({