diff --git a/client/modules/serviceHandler.mjs b/client/modules/serviceHandler.mjs new file mode 100644 index 0000000..5a714e7 --- /dev/null +++ b/client/modules/serviceHandler.mjs @@ -0,0 +1,52 @@ +import { exec } from 'child_process'; + +/** + * Starts the given service from the command line. + * @param {string} serviceName The service name to be started. Ex: ... start "{serviceName}.service" + * @returns {Promise} + */ +export const startService = async (serviceName) => { + return new Promise((resolve, reject) => { + exec(`sudo systemctl start ${serviceName}.service`, (error, stdout, stderr) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); +}; + +/** + * Restarts the given service from the command line. + * @param {string} serviceName The service name to be restarted. Ex: ... restart "{serviceName}.service" + * @returns {Promise} + */ +export const restartService = async (serviceName) => { + return new Promise((resolve, reject) => { + exec(`sudo systemctl restart ${serviceName}.service`, (error, stdout, stderr) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); +}; + +/** + * Stops the given service from the command line. + * @param {string} serviceName The service name to be stopped. Ex: ... stop "{serviceName}.service" + * @returns {Promise} + */ +export const stopService = async (serviceName) => { + return new Promise((resolve, reject) => { + exec(`sudo systemctl stop ${serviceName}.service`, (error, stdout, stderr) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); +}; \ No newline at end of file diff --git a/client/op25Handler/modules/op25ConfigGenerators.mjs b/client/op25Handler/modules/op25ConfigGenerators.mjs index 8ae0740..6fdb9e4 100644 --- a/client/op25Handler/modules/op25ConfigGenerators.mjs +++ b/client/op25Handler/modules/op25ConfigGenerators.mjs @@ -17,18 +17,19 @@ class OP25ConfigObject { export class P25ConfigGenerator extends OP25ConfigObject { constructor({ systemName, controlChannels, tagsFile, whitelistFile = undefined }) { super(); + console.log("Generating P25 Config for:", systemName); const controlChannelsString = controlChannels.join(','); - this.channels = new channelConfig({ + this.channels = [new channelConfig({ "channelName": systemName, "systemName": systemName, "enableAnalog": "off", "demodType": "cqpsk", "cqpskTracking": true, "filterType": "rc" - }); - this.devices = new deviceConfig({ + })]; + this.devices = [new deviceConfig({ "gain": "LNA:36" - }); + })]; this.trunking = new trunkingConfig({ "module": "tk_p25.py", "systemName": systemName, @@ -149,7 +150,7 @@ class trunkingConfig { } class audioConfig { - constructor({ module = "sockaudio.py", port = 23456, deviceName = "default" }) { + constructor({ module = "sockaudio.py", port = 23457, deviceName = "default" }) { this.module = module; this.instances = [{ "instance_name": "audio0", @@ -169,7 +170,7 @@ class metadataStreamConfig { } class terminalConfig { - constructor({ module = "terminal.py", terminalType = "http:0.0.0.0:8080" }) { + constructor({ module = "terminal.py", terminalType = "http:0.0.0.0:8081" }) { this.module = module; this.terminal_type = terminalType; this.curses_plot_interval = 0.1; diff --git a/client/op25Handler/op25Handler.mjs b/client/op25Handler/op25Handler.mjs index 5064552..07f51d9 100644 --- a/client/op25Handler/op25Handler.mjs +++ b/client/op25Handler/op25Handler.mjs @@ -1,14 +1,84 @@ +import { P25ConfigGenerator, NBFMConfigGenerator } from './modules/op25ConfigGenerators.mjs'; +import { getAllPresets } from '../modules/radioPresetHandler.mjs'; +import { startService, stopService } from '../modules/serviceHandler.mjs'; + +import dotenv from 'dotenv'; +dotenv.config() + let currentSystem = undefined; +/** + * Creates configuration based on the preset and restarts the OP25 service. + * @param {Object} preset The preset object containing system configuration. + * @returns {Promise} + */ +const createConfigAndRestartService = async (systemName, preset) => { + const { mode, frequencies, trunkFile, whitelistFile } = preset; + let generator; + if (mode === 'p25') { + console.log("Using P25 Config Generator based on preset mode", systemName, mode); + generator = new P25ConfigGenerator({ + systemName, + controlChannels: frequencies, + tagsFile: trunkFile, + whitelistFile: whitelistFile !== 'none' ? whitelistFile : undefined + }); + } else if (mode === 'nbfm') { + console.log("Using NBFM Config Generator based on preset mode", systemName, mode); + generator = new NBFMConfigGenerator({ + systemName, + frequencies, + tagsFile: trunkFile + }); + } else { + throw new Error(`Unsupported mode: ${mode}`); + } + + const op25FilePath = process.env.OP25_FULL_PATH || './'; // Default to current directory if OP25_FULL_PATH is not set + const op25ConfigPath = `${op25FilePath}${op25FilePath.endsWith('/') ? 'active.cfg.json' : '/active.cfg.json'}`; + await generator.exportToFile(op25ConfigPath); + + // Restart the service + await stopService('op25'); + await startService('op25'); +}; + +/** + * Opens the OP25 service for the specified system. + * @param {string} systemName The name of the system to open. + * @returns {Promise} + */ export const openOP25 = async (systemName) => { currentSystem = systemName; -} + // Retrieve preset for the specified system name + const presets = await getAllPresets(); + const preset = presets[systemName]; + + console.log("Found preset:", preset); + + if (!preset) { + throw new Error(`Preset for system "${systemName}" not found.`); + } + + await createConfigAndRestartService(systemName, preset); +}; + + +/** + * Closes the OP25 service. + * @returns {Promise} + */ export const closeOP25 = async () => { currentSystem = undefined; -} + await stopService('op25'); +}; +/** + * Gets the current system. + * @returns {Promise} The name of the current system. + */ export const getCurrentSystem = async () => { return currentSystem; -} \ No newline at end of file +}; \ No newline at end of file