diff --git a/gui/src/components/settings_hamlib.vue b/gui/src/components/settings_hamlib.vue
index dc83a29b..da8ae52e 100644
--- a/gui/src/components/settings_hamlib.vue
+++ b/gui/src/components/settings_hamlib.vue
@@ -357,7 +357,7 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
@change="onChange"
v-model.number="settings.remote.RADIO.serial_speed"
>
-
+
@@ -380,7 +380,7 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
@change="onChange"
v-model.number="settings.remote.RADIO.data_bits"
>
-
+
@@ -395,7 +395,7 @@ import { serialDeviceOptions } from "../js/deviceFormHelper";
@change="onChange"
v-model.number="settings.remote.RADIO.stop_bits"
>
-
+
diff --git a/modem/helpers.py b/modem/helpers.py
index bfdb28f8..8ee0cc8f 100644
--- a/modem/helpers.py
+++ b/modem/helpers.py
@@ -15,7 +15,9 @@ import hmac
import os
import sys
from pathlib import Path
-
+import platform
+import subprocess
+import psutil
log = structlog.get_logger("helpers")
@@ -701,9 +703,54 @@ def set_flag(byte, flag_name, value, flag_dict):
position = flag_dict[flag_name]
return set_bit(byte, position, value)
+
def get_flag(byte, flag_name, flag_dict):
"""Get the value of the flag from the byte according to the flag dictionary."""
if flag_name not in flag_dict:
raise ValueError(f"Unknown flag name: {flag_name}")
position = flag_dict[flag_name]
return get_bit(byte, position)
+
+
+def find_binary_path(binary_name="rigctld"):
+ """
+ Search for a binary within the current working directory and its subdirectories,
+ adjusting the binary name for the operating system.
+
+ :param binary_name: The base name of the binary to search for, without extension.
+ :return: The full path to the binary if found, otherwise None.
+ """
+ # Adjust binary name for Windows
+ if platform.system() == 'Windows':
+ binary_name += ".exe"
+
+ root_path = os.getcwd() # Get the current working directory
+ for dirpath, dirnames, filenames in os.walk(root_path):
+ if binary_name in filenames:
+ return os.path.join(dirpath, binary_name)
+ return None
+
+
+def kill_and_execute(binary_path, additional_args=None):
+ """
+ Kills any running instances of the binary across Linux, macOS, and Windows, then starts a new one non-blocking.
+
+ :param binary_path: The full path to the binary to execute.
+ :param additional_args: A list of additional arguments to pass to the binary.
+ :return: subprocess.Popen object of the started process
+ """
+ # Kill any existing instances of the binary
+ for proc in psutil.process_iter(attrs=['pid', 'name', 'cmdline']):
+ try:
+ cmdline = proc.info['cmdline']
+ # Ensure cmdline is iterable and not None
+ if cmdline and binary_path in ' '.join(cmdline):
+ proc.kill()
+ print(f"Killed running instance with PID: {proc.info['pid']}")
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
+ pass # Process no longer exists or no permission to kill
+
+ # Execute the binary with additional arguments non-blocking
+ command = [binary_path] + (additional_args if additional_args else [])
+ process = subprocess.Popen(command)
+ return process
\ No newline at end of file
diff --git a/modem/radio_manager.py b/modem/radio_manager.py
index 5f0c214a..eabdf291 100644
--- a/modem/radio_manager.py
+++ b/modem/radio_manager.py
@@ -21,7 +21,7 @@ class RadioManager:
def _init_rig_control(self):
# Check how we want to control the radio
if self.radiocontrol == "rigctld":
- self.radio = rigctld.radio(self.state_manager, hostname=self.rigctld_ip,port=self.rigctld_port)
+ self.radio = rigctld.radio(self.config, self.state_manager, hostname=self.rigctld_ip,port=self.rigctld_port)
elif self.radiocontrol == "tci":
raise NotImplementedError
# self.radio = self.tci_module
diff --git a/modem/rigctld.py b/modem/rigctld.py
index 4e3a9110..2fa82d0b 100644
--- a/modem/rigctld.py
+++ b/modem/rigctld.py
@@ -1,6 +1,6 @@
import socket
import structlog
-import time
+import helpers
import threading
class radio:
@@ -8,11 +8,12 @@ class radio:
log = structlog.get_logger("radio (rigctld)")
- def __init__(self, states, hostname="localhost", port=4532, timeout=5):
+ def __init__(self, config, states, hostname="localhost", port=4532, timeout=5):
self.hostname = hostname
self.port = port
self.timeout = timeout
self.states = states
+ self.config = config
self.connection = None
self.connected = False
@@ -29,6 +30,9 @@ class radio:
'ptt': False # Initial PTT state is set to False
}
+ # start rigctld...
+ self.start_service()
+
# connect to radio
self.connect()
@@ -201,3 +205,49 @@ class radio:
"""Return the latest fetched parameters."""
return self.parameters
+
+ def start_service(self):
+ binary_name = "rigctld"
+ binary_path = helpers.find_binary_path(binary_name)
+ additional_args = self.format_rigctld_args()
+ if binary_path:
+ self.log.info(f"Rigctld binary found at: {binary_path}")
+ helpers.kill_and_execute(binary_path, additional_args)
+ self.log.info(f"Executed rigctld...")
+ else:
+ self.log.warning("Rigctld binary not found.")
+
+ def format_rigctld_args(self):
+ config = self.config['RADIO'] # Accessing the 'RADIO' section of the INI file
+ args = []
+
+ # Helper function to check if the value should be ignored
+ def should_ignore(value):
+ return value == 'ignore' or value == 0
+
+ # Model ID, Serial Port, and Speed
+ if not should_ignore(config.get('model_id', "0")):
+ args += ['-m', str(config['model_id'])]
+ if not should_ignore(config.get('serial_port', "0")):
+ args += ['-r', config['serial_port']]
+ if not should_ignore(config.get('serial_speed', "0")):
+ args += ['-s', str(config['serial_speed'])]
+
+ # PTT Port and Type
+ if not should_ignore(config.get('ptt_port', "0")):
+ args += ['--ptt-port', config['ptt_port']]
+ if not should_ignore(config.get('ptt_type', "0")):
+ args += ['--ptt-type', config['ptt_type']]
+
+ # Serial DCD and DTR
+ if not should_ignore(config.get('serial_dcd', "0")):
+ args += ['--set-dcd', config['serial_dcd']]
+ if not should_ignore(config.get('serial_dtr', "0")):
+ args += ['--set-dtr', config['serial_dtr']]
+
+ # Handling Stop Bits with the corrected --set-conf syntax
+ if not should_ignore(config.get('stop_bits', "0")):
+ args += ['--set-conf', f'stop_bits={config["stop_bits"]}']
+
+ return args
+