Major update
- Working client server interactions - Can create radio config - Needs radio testing
This commit is contained in:
1
Client/.env
Normal file
1
Client/.env
Normal file
@@ -0,0 +1 @@
|
||||
DEBUG="client:*";
|
||||
@@ -7,6 +7,7 @@ var logger = require('morgan');
|
||||
var indexRouter = require('./routes/index');
|
||||
var botRouter = require('./routes/bot');
|
||||
var clientRouter = require('./routes/client');
|
||||
var radioRouter = require('./routes/radio');
|
||||
|
||||
var app = express();
|
||||
|
||||
@@ -28,6 +29,9 @@ app.use('/bot', botRouter);
|
||||
// Local client control route
|
||||
app.use("/client", clientRouter);
|
||||
|
||||
// Local radio controller route
|
||||
app.use("/radio", radioRouter);
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
app.use(function(req, res, next) {
|
||||
next(createError(404));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Core config settings for the node, these are the settings that are checked with the server
|
||||
const path = require("path");
|
||||
exports.clientConfig = {
|
||||
"id": 13,
|
||||
"name": "boilin balls in the hall",
|
||||
@@ -14,4 +15,9 @@ exports.serverConfig = {
|
||||
"ip": "127.0.0.1",
|
||||
"hostname": "localhost",
|
||||
"port": 3000
|
||||
}
|
||||
|
||||
// Configuration of the local OP25 application
|
||||
exports.radioAppConfig = {
|
||||
"bin": "H:/Logan/Projects/Discord-Radio-Bot-CnC/Client/.idea/testOP25Dir/multi_rx.py"
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"Westchester Cty. Simulcast":{"frequencies":[470575000,470375000,470525000,470575000,470550000],"mode":"p25","trunkFile":"trunk.tsv"}}
|
||||
{"Westchester Cty. Simulcast":{"frequencies":[470575000,470375000,470525000,470575000,470550000],"mode":"p25","trunkFile":"trunk.tsv"},"coppies":{"frequencies":[154875000],"mode":"nbfm","trunkFile":"none"}}
|
||||
@@ -6,7 +6,7 @@ const path = require('path');
|
||||
const fork = require('child_process').fork;
|
||||
const discordBotPath = path.resolve('discord-bot/app.js');
|
||||
|
||||
let botChildProcess, radioChildProcess, tempRes;
|
||||
let botChildProcess, tempRes;
|
||||
|
||||
/**
|
||||
* Bot Process Object Builder
|
||||
@@ -67,6 +67,7 @@ exports.joinServer = (req, res) => {
|
||||
tempRes.sendStatus(202);
|
||||
tempRes = undefined;
|
||||
botChildProcess.kill();
|
||||
botChildProcess = undefined;
|
||||
return;
|
||||
case "ChgPreSet":
|
||||
tempRes.sendStatus(200);
|
||||
|
||||
147
Client/controllers/radioController.js
Normal file
147
Client/controllers/radioController.js
Normal file
@@ -0,0 +1,147 @@
|
||||
// Debug
|
||||
const { DebugBuilder } = require("../utilities/debugBuilder.js");
|
||||
const log = new DebugBuilder("client", "radioController");
|
||||
// Modules
|
||||
const { resolve, dirname } = require('path');
|
||||
const fs = require('fs');
|
||||
const radioConfig = require('../config/clientConfig').radioAppConfig;
|
||||
const radioConfigHelper = require("../utilities/radioConfigHelper");
|
||||
const presetWrappers = require("../utilities/updatePresets");
|
||||
const spawn = require('child_process').spawn;
|
||||
const converter = require("convert-units");
|
||||
|
||||
let radioChildProcess, tempRes, radioConfigPath;
|
||||
|
||||
/**
|
||||
* Closes the radio executable if it's in one
|
||||
*/
|
||||
exports.closeRadioSession = (req, res) => {
|
||||
if (!radioChildProcess) return res.sendStatus(200)
|
||||
tempRes = res;
|
||||
radioChildProcess.kill();
|
||||
radioChildProcess = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current 'cfg.json' file to the preset specified
|
||||
* @param {string} presetName
|
||||
*/
|
||||
exports.changeCurrentConfig = (req, res) => {
|
||||
// Check if the given config is saved
|
||||
log.DEBUG("[/radio/changeCurrentConfig] - Checking if provided preset is in the config");
|
||||
if (!checkIfPresetExists(req.body.presetName)) return res.status(500).JSON("No preset with given name found in config"); // No preset with the given name is in the config
|
||||
|
||||
// Check if the current config is the same as the preset given
|
||||
const currentConfig = readOP25Config();
|
||||
if (currentConfig.channels && currentConfig.channels.name === req.body.presetName) {
|
||||
log.DEBUG("[/radio/changeCurrentConfig] - Current config is the same as the preset given");
|
||||
return res.sendStatus(202);
|
||||
}
|
||||
|
||||
// Convert radioPreset to OP25 'cfg.json. file
|
||||
log.DEBUG("[/radio/changeCurrentConfig] - Converting radioPreset to OP25 config");
|
||||
const updatedConfigObject = convertRadioPresetsToOP25Config(req.body.presetName);
|
||||
|
||||
// Replace current JSON file with the updated file
|
||||
writeOP25Config(updatedConfigObject, () => {
|
||||
res.sendStatus(200);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new OP25 process tuned to the specified system
|
||||
*/
|
||||
exports.openRadioSession = () => {
|
||||
if (radioChildProcess) closeRadioSession();
|
||||
radioChildProcess = spawn(getRadioBinPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of the 'multi_rx.py' binary from the config
|
||||
*/
|
||||
function getRadioBinPath(){
|
||||
return resolve(radioConfig.bin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given config to the JSON file in OP25 the bin dir
|
||||
* @param config The full config to be written to the file
|
||||
* @param {function} callback The function to be called when this wrapper completes
|
||||
*/
|
||||
function writeOP25Config(config, callback = undefined) {
|
||||
log.DEBUG("Updating OP25 config with: ", config);
|
||||
fs.writeFile(getRadioConfigPath(), JSON.stringify(config), (err) => {
|
||||
// Error checking
|
||||
if (err) {
|
||||
log.ERROR(err);
|
||||
throw err;
|
||||
}
|
||||
log.DEBUG("Write Complete");
|
||||
if (callback) callback()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current config file in use by OP25
|
||||
* @returns {object|*} The parsed config object currently set in OP25
|
||||
*/
|
||||
function readOP25Config() {
|
||||
const configPath = getRadioConfigPath();
|
||||
log.DEBUG(`Reading from config path: '${configPath}'`);
|
||||
return JSON.parse(fs.readFileSync(configPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the config for the radio app (OP25) and set the global variable
|
||||
*/
|
||||
function getRadioConfigPath(){
|
||||
let radioConfigDirPath = dirname(getRadioBinPath());
|
||||
return resolve(`${radioConfigDirPath}/cfg.json`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the preset name exists in the config
|
||||
* @param {string} presetName The system name as saved in the preset
|
||||
* @returns {true||false}
|
||||
*/
|
||||
function checkIfPresetExists(presetName) {
|
||||
const savedPresets = presetWrappers.getPresets();
|
||||
if (!Object.keys(savedPresets).includes(presetName)) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a radioPreset to OP25's cfg.json file
|
||||
*/
|
||||
function convertRadioPresetsToOP25Config(presetName){
|
||||
const savedPresets = presetWrappers.getPresets();
|
||||
let frequencyString = "";
|
||||
for (const frequency of savedPresets[presetName].frequencies){
|
||||
frequencyString += `${converter(frequency).from("Hz").to("MHz")},`
|
||||
}
|
||||
frequencyString = frequencyString.slice(0, -1);
|
||||
|
||||
let updatedOP25Config;
|
||||
switch (savedPresets[presetName].mode){
|
||||
case "p25":
|
||||
updatedOP25Config = new radioConfigHelper.P25({
|
||||
"systemName": presetName,
|
||||
"controlChannelsString": frequencyString,
|
||||
"tagsFile": savedPresets[presetName].trunkFile
|
||||
});
|
||||
break;
|
||||
case "nbfm":
|
||||
//code for nbfm here
|
||||
updatedOP25Config = new radioConfigHelper.NBFM({
|
||||
"frequency": frequencyString,
|
||||
"systemName": presetName
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error("Radio mode of selected preset not recognized");
|
||||
}
|
||||
|
||||
log.DEBUG(updatedOP25Config);
|
||||
return updatedOP25Config;
|
||||
}
|
||||
|
||||
327
Client/package-lock.json
generated
327
Client/package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"name": "client",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"convert-units": "^2.3.4",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"debug": "~2.6.9",
|
||||
"ejs": "~2.6.1",
|
||||
@@ -174,6 +175,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-units": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/convert-units/-/convert-units-2.3.4.tgz",
|
||||
"integrity": "sha512-ERHfdA0UhHJp1IpwE6PnFJx8LqG7B1ZjJ20UvVCmopEnVCfER68Tbe3kvN63dLbYXDA2xFWRE6zd4Wsf0w7POg==",
|
||||
"dependencies": {
|
||||
"lodash.foreach": "2.3.x",
|
||||
"lodash.keys": "2.3.x"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
@@ -443,6 +453,160 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._basebind": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz",
|
||||
"integrity": "sha512-SHqM7YCuJ+BeGTs7lqpWnmdHEeF4MWxS3dksJctHFNxR81FXPOzA4bS5Vs5CpcGTkBpM8FCl+YEbQEblRw8ABg==",
|
||||
"dependencies": {
|
||||
"lodash._basecreate": "~2.3.0",
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._basecreate": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz",
|
||||
"integrity": "sha512-vwZaWldZwS2y9b99D8i9+WtgiZXbHKsBsMrpxJEqTsNW20NhJo5W8PBQkeQO9CmxuqEYn8UkMnfEM2MMT4cVrw==",
|
||||
"dependencies": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0",
|
||||
"lodash.noop": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._basecreatecallback": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz",
|
||||
"integrity": "sha512-Ev+pDzzfVfgbiucpXijconLGRBar7/+KNCf05kSnk4CmdDVhAy1RdbU9efCJ/o9GXI08JdUGwZ+5QJ3QX3kj0g==",
|
||||
"dependencies": {
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash.bind": "~2.3.0",
|
||||
"lodash.identity": "~2.3.0",
|
||||
"lodash.support": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._basecreatewrapper": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz",
|
||||
"integrity": "sha512-YLycQ7k8AB9Wc1EOvLNxuRWcqipDkMXq2GCgnLWQR6qtgTb3gY3LELzEpnFshrEO4LOLs+R2EpcY+uCOZaLQ8Q==",
|
||||
"dependencies": {
|
||||
"lodash._basecreate": "~2.3.0",
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash._slice": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._createwrapper": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz",
|
||||
"integrity": "sha512-XjaI/rzg9W+WO4WJDQ+PRlHD5sAMJ1RhJLuT65cBxLCb1kIYs4U20jqvTDGAWyVT3c34GYiLd9AreHYuB/8yJA==",
|
||||
"dependencies": {
|
||||
"lodash._basebind": "~2.3.0",
|
||||
"lodash._basecreatewrapper": "~2.3.0",
|
||||
"lodash.isfunction": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._objecttypes": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz",
|
||||
"integrity": "sha512-jbA6QyHt9cw3BzvbWzIcnU3Z12jSneT6xBgz3Y782CJsN1tV5aTBKrFo2B4AkeHBNaxSrbPYZZpi1Lwj3xjdtg=="
|
||||
},
|
||||
"node_modules/lodash._renative": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz",
|
||||
"integrity": "sha512-v44MRirqYqZGK/h5UKoVqXWF2L+LUiLTU+Ogu5rHRVWJUA1uWIlHaMpG8f/OA8j++BzPMQij9+erXHtgFcbuwg=="
|
||||
},
|
||||
"node_modules/lodash._setbinddata": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz",
|
||||
"integrity": "sha512-xMFfbF7dL+sFtrdE49uHFmfpBAEwlFtfgMp86nQRlAF6aizYL+3MTbnYMKJSkP1W501PhsgiBED5kBbZd8kR2g==",
|
||||
"dependencies": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash.noop": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._shimkeys": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz",
|
||||
"integrity": "sha512-9Iuyi7TiWMGa/9+2rqEE+Zwye4b/U2w7Saw6UX1h6Xs88mEER+uz9FZcEBPKMVKsad9Pw5GNAcIBRnW2jNpneQ==",
|
||||
"dependencies": {
|
||||
"lodash._objecttypes": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash._slice": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz",
|
||||
"integrity": "sha512-7C61GhzRUv36gTafr+RIb+AomCAYsSATEoK4OP0VkNBcwvsM022Z22AVgqjjzikeNO1U29LzsJZDvLbiNPUYvA=="
|
||||
},
|
||||
"node_modules/lodash.bind": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz",
|
||||
"integrity": "sha512-goakyOo+FMN8lttMPnZ0UNlr5RlzX4IrUXyTJPT2A0tGCMXySupond9wzvDqTvVmYTcQjIKGrj8naJDS2xWAlQ==",
|
||||
"dependencies": {
|
||||
"lodash._createwrapper": "~2.3.0",
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash._slice": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.foreach": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz",
|
||||
"integrity": "sha512-yLnyptVRJd0//AbGp480grgQG9iaDIV5uOgSbpurRy1dYybPbjNTLQ3FyLEQ84buVLPG7jyaiyvpzgfOutRB3Q==",
|
||||
"dependencies": {
|
||||
"lodash._basecreatecallback": "~2.3.0",
|
||||
"lodash.forown": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.forown": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz",
|
||||
"integrity": "sha512-dUnCsuQTtq3Y7bxPNoEEqjJjPL2ftLtcz2PTeRKvhbpdM514AvnqCjewHGsm/W+dwspIwa14KoWEZeizJ7smxA==",
|
||||
"dependencies": {
|
||||
"lodash._basecreatecallback": "~2.3.0",
|
||||
"lodash._objecttypes": "~2.3.0",
|
||||
"lodash.keys": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.identity": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz",
|
||||
"integrity": "sha512-NYJ2r2cwy3tkx/saqbIZEX6oQUzjWTnGRu7d/zmBjMCZos3eHBxCpbvWFWSetv8jFVrptsp6EbWjzNgBKhUoOA=="
|
||||
},
|
||||
"node_modules/lodash.isfunction": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz",
|
||||
"integrity": "sha512-X5lteBYlCrVO7Qc00fxP8W90fzRp6Ax9XcHANmU3OsZHdSyIVZ9ZlX5QTTpRq8aGY+9I5Rmd0UTzTIIyWPugEQ=="
|
||||
},
|
||||
"node_modules/lodash.isobject": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz",
|
||||
"integrity": "sha512-jo1pfV61C4TE8BfEzqaHj6EIKiSkFANJrB6yscwuCJMSRw5tbqjk4Gv7nJzk4Z6nFKobZjGZ8Qd41vmnwgeQqQ==",
|
||||
"dependencies": {
|
||||
"lodash._objecttypes": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.keys": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz",
|
||||
"integrity": "sha512-c0UW0ffqMxSCtoVbmVt2lERJLkEqgoOn2ejPsWXzr0ZrqRbl3uruGgwHzhtqXxi6K/ei3Ey7zimOqSwXgzazPg==",
|
||||
"dependencies": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash._shimkeys": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.noop": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz",
|
||||
"integrity": "sha512-NpSm8HRm1WkBBWHUveDukLF4Kfb5P5E3fjHc9Qre9A11nNubozLWD2wH3UBTZbu+KSuX8aSUvy9b+PUyEceJ8g=="
|
||||
},
|
||||
"node_modules/lodash.support": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz",
|
||||
"integrity": "sha512-etc7VWbB0U3Iya8ixj2xy4sDBN3jvPX7ODi8iXtn4KkkjNpdngrdc7Vlt5jub/Vgqx6/dWtp7Ml9awhCQPYKGQ==",
|
||||
"dependencies": {
|
||||
"lodash._renative": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
@@ -949,6 +1113,15 @@
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"convert-units": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/convert-units/-/convert-units-2.3.4.tgz",
|
||||
"integrity": "sha512-ERHfdA0UhHJp1IpwE6PnFJx8LqG7B1ZjJ20UvVCmopEnVCfER68Tbe3kvN63dLbYXDA2xFWRE6zd4Wsf0w7POg==",
|
||||
"requires": {
|
||||
"lodash.foreach": "2.3.x",
|
||||
"lodash.keys": "2.3.x"
|
||||
}
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
@@ -1160,6 +1333,160 @@
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"lodash._basebind": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz",
|
||||
"integrity": "sha512-SHqM7YCuJ+BeGTs7lqpWnmdHEeF4MWxS3dksJctHFNxR81FXPOzA4bS5Vs5CpcGTkBpM8FCl+YEbQEblRw8ABg==",
|
||||
"requires": {
|
||||
"lodash._basecreate": "~2.3.0",
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._basecreate": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz",
|
||||
"integrity": "sha512-vwZaWldZwS2y9b99D8i9+WtgiZXbHKsBsMrpxJEqTsNW20NhJo5W8PBQkeQO9CmxuqEYn8UkMnfEM2MMT4cVrw==",
|
||||
"requires": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0",
|
||||
"lodash.noop": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._basecreatecallback": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz",
|
||||
"integrity": "sha512-Ev+pDzzfVfgbiucpXijconLGRBar7/+KNCf05kSnk4CmdDVhAy1RdbU9efCJ/o9GXI08JdUGwZ+5QJ3QX3kj0g==",
|
||||
"requires": {
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash.bind": "~2.3.0",
|
||||
"lodash.identity": "~2.3.0",
|
||||
"lodash.support": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._basecreatewrapper": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz",
|
||||
"integrity": "sha512-YLycQ7k8AB9Wc1EOvLNxuRWcqipDkMXq2GCgnLWQR6qtgTb3gY3LELzEpnFshrEO4LOLs+R2EpcY+uCOZaLQ8Q==",
|
||||
"requires": {
|
||||
"lodash._basecreate": "~2.3.0",
|
||||
"lodash._setbinddata": "~2.3.0",
|
||||
"lodash._slice": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._createwrapper": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz",
|
||||
"integrity": "sha512-XjaI/rzg9W+WO4WJDQ+PRlHD5sAMJ1RhJLuT65cBxLCb1kIYs4U20jqvTDGAWyVT3c34GYiLd9AreHYuB/8yJA==",
|
||||
"requires": {
|
||||
"lodash._basebind": "~2.3.0",
|
||||
"lodash._basecreatewrapper": "~2.3.0",
|
||||
"lodash.isfunction": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._objecttypes": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz",
|
||||
"integrity": "sha512-jbA6QyHt9cw3BzvbWzIcnU3Z12jSneT6xBgz3Y782CJsN1tV5aTBKrFo2B4AkeHBNaxSrbPYZZpi1Lwj3xjdtg=="
|
||||
},
|
||||
"lodash._renative": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz",
|
||||
"integrity": "sha512-v44MRirqYqZGK/h5UKoVqXWF2L+LUiLTU+Ogu5rHRVWJUA1uWIlHaMpG8f/OA8j++BzPMQij9+erXHtgFcbuwg=="
|
||||
},
|
||||
"lodash._setbinddata": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz",
|
||||
"integrity": "sha512-xMFfbF7dL+sFtrdE49uHFmfpBAEwlFtfgMp86nQRlAF6aizYL+3MTbnYMKJSkP1W501PhsgiBED5kBbZd8kR2g==",
|
||||
"requires": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash.noop": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._shimkeys": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz",
|
||||
"integrity": "sha512-9Iuyi7TiWMGa/9+2rqEE+Zwye4b/U2w7Saw6UX1h6Xs88mEER+uz9FZcEBPKMVKsad9Pw5GNAcIBRnW2jNpneQ==",
|
||||
"requires": {
|
||||
"lodash._objecttypes": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash._slice": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz",
|
||||
"integrity": "sha512-7C61GhzRUv36gTafr+RIb+AomCAYsSATEoK4OP0VkNBcwvsM022Z22AVgqjjzikeNO1U29LzsJZDvLbiNPUYvA=="
|
||||
},
|
||||
"lodash.bind": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz",
|
||||
"integrity": "sha512-goakyOo+FMN8lttMPnZ0UNlr5RlzX4IrUXyTJPT2A0tGCMXySupond9wzvDqTvVmYTcQjIKGrj8naJDS2xWAlQ==",
|
||||
"requires": {
|
||||
"lodash._createwrapper": "~2.3.0",
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash._slice": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash.foreach": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz",
|
||||
"integrity": "sha512-yLnyptVRJd0//AbGp480grgQG9iaDIV5uOgSbpurRy1dYybPbjNTLQ3FyLEQ84buVLPG7jyaiyvpzgfOutRB3Q==",
|
||||
"requires": {
|
||||
"lodash._basecreatecallback": "~2.3.0",
|
||||
"lodash.forown": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash.forown": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz",
|
||||
"integrity": "sha512-dUnCsuQTtq3Y7bxPNoEEqjJjPL2ftLtcz2PTeRKvhbpdM514AvnqCjewHGsm/W+dwspIwa14KoWEZeizJ7smxA==",
|
||||
"requires": {
|
||||
"lodash._basecreatecallback": "~2.3.0",
|
||||
"lodash._objecttypes": "~2.3.0",
|
||||
"lodash.keys": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash.identity": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz",
|
||||
"integrity": "sha512-NYJ2r2cwy3tkx/saqbIZEX6oQUzjWTnGRu7d/zmBjMCZos3eHBxCpbvWFWSetv8jFVrptsp6EbWjzNgBKhUoOA=="
|
||||
},
|
||||
"lodash.isfunction": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz",
|
||||
"integrity": "sha512-X5lteBYlCrVO7Qc00fxP8W90fzRp6Ax9XcHANmU3OsZHdSyIVZ9ZlX5QTTpRq8aGY+9I5Rmd0UTzTIIyWPugEQ=="
|
||||
},
|
||||
"lodash.isobject": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz",
|
||||
"integrity": "sha512-jo1pfV61C4TE8BfEzqaHj6EIKiSkFANJrB6yscwuCJMSRw5tbqjk4Gv7nJzk4Z6nFKobZjGZ8Qd41vmnwgeQqQ==",
|
||||
"requires": {
|
||||
"lodash._objecttypes": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash.keys": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz",
|
||||
"integrity": "sha512-c0UW0ffqMxSCtoVbmVt2lERJLkEqgoOn2ejPsWXzr0ZrqRbl3uruGgwHzhtqXxi6K/ei3Ey7zimOqSwXgzazPg==",
|
||||
"requires": {
|
||||
"lodash._renative": "~2.3.0",
|
||||
"lodash._shimkeys": "~2.3.0",
|
||||
"lodash.isobject": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"lodash.noop": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz",
|
||||
"integrity": "sha512-NpSm8HRm1WkBBWHUveDukLF4Kfb5P5E3fjHc9Qre9A11nNubozLWD2wH3UBTZbu+KSuX8aSUvy9b+PUyEceJ8g=="
|
||||
},
|
||||
"lodash.support": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz",
|
||||
"integrity": "sha512-etc7VWbB0U3Iya8ixj2xy4sDBN3jvPX7ODi8iXtn4KkkjNpdngrdc7Vlt5jub/Vgqx6/dWtp7Ml9awhCQPYKGQ==",
|
||||
"requires": {
|
||||
"lodash._renative": "~2.3.0"
|
||||
}
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"start": "node ./bin/www"
|
||||
},
|
||||
"dependencies": {
|
||||
"convert-units": "^2.3.4",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"debug": "~2.6.9",
|
||||
"ejs": "~2.6.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var express = require('express');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const botController = require("../controllers/botController");
|
||||
var router = express.Router();
|
||||
|
||||
/** GET bot status
|
||||
* Check to see if the bot is online and if so, if it is currently connected to anything
|
||||
@@ -27,11 +27,4 @@ router.post('/join', botController.joinServer);
|
||||
*/
|
||||
router.post('/leave', botController.leaveServer);
|
||||
|
||||
/** POST change bot preset
|
||||
* This will change the bot to the preset specified (if different from what is currently playing)
|
||||
*
|
||||
* The status of the bot: 200 = no change, 202 = changed successfully, 500 + JSON = encountered error
|
||||
* @returns status
|
||||
*/
|
||||
|
||||
module.exports = router;
|
||||
|
||||
30
Client/routes/radio.js
Normal file
30
Client/routes/radio.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// Controllers
|
||||
const radioController = require("../controllers/radioController");
|
||||
// Debug
|
||||
const { DebugBuilder } = require("../utilities/debugBuilder.js");
|
||||
const log = new DebugBuilder("client", "clientController");
|
||||
// Modules
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* POST Open a new radio session
|
||||
* This will open OP25 to the current specified radio settings
|
||||
*/
|
||||
router.post('/start', radioController.openRadioSession);
|
||||
|
||||
/**
|
||||
* POST Close the current radio session
|
||||
*/
|
||||
router.post('/stop', radioController.closeRadioSession);
|
||||
|
||||
/** POST change current radio preset
|
||||
* This will change the bot to the preset specified (if different from what is currently playing)
|
||||
* @param req The request sent from the master
|
||||
* @param {string} req.body.presetName The name of the system to be updated
|
||||
* The status of the bot: 200 = no change, 202 = changed successfully, 500 + JSON = encountered error
|
||||
* @returns status
|
||||
*/
|
||||
router.post('/changeConfig', radioController.changeCurrentConfig);
|
||||
|
||||
module.exports = router;
|
||||
161
Client/utilities/radioConfigHelper.js
Normal file
161
Client/utilities/radioConfigHelper.js
Normal file
@@ -0,0 +1,161 @@
|
||||
exports.P25 = class P25ConfigGenerator {
|
||||
constructor({systemName, controlChannelsString, tagsFile}) {
|
||||
this.channels = new channelConfig({
|
||||
"systemName": systemName,
|
||||
"enableAnalog": "off",
|
||||
"demodType": "cqpsk",
|
||||
"cqpskTracking": true,
|
||||
"filterType": "rc"
|
||||
});
|
||||
this.devices = new deviceConfig({
|
||||
"gain": "LNA:36"
|
||||
});
|
||||
this.trunking = new trunkingConfig({
|
||||
"module": "tk_p25.py",
|
||||
"systemName": systemName,
|
||||
"controlChannelsString": controlChannelsString,
|
||||
"tagsFile": tagsFile
|
||||
});
|
||||
this.audio = new audioConfig({});
|
||||
this.terminal = new terminalConfig({});
|
||||
}
|
||||
}
|
||||
|
||||
exports.NBFM = class NBFMConfigGenerator {
|
||||
constructor({systemName, frequency, nbfmSquelch = -70}) {
|
||||
this.channels = new channelConfig({
|
||||
"channelName": systemName,
|
||||
"enableAnalog": "on",
|
||||
"nbfmSquelch": nbfmSquelch,
|
||||
"frequency": frequency,
|
||||
"demodType": "fsk4",
|
||||
"filterType": "widepulse"
|
||||
});
|
||||
this.devices = new deviceConfig({
|
||||
"gain": "LNA:32"
|
||||
});
|
||||
this.audio = new audioConfig({});
|
||||
this.terminal = new terminalConfig({});
|
||||
}
|
||||
}
|
||||
|
||||
class channelConfig {
|
||||
constructor({
|
||||
channelName = "Voice_ch1",
|
||||
device = "sdr0",
|
||||
systemName,
|
||||
metaStreamName,
|
||||
demodType, // cqpsk: P25; fsk4: everything else
|
||||
cqpskTracking,
|
||||
trackingThreshold = 120,
|
||||
trackingFeedback = 0.75,
|
||||
destination = "udp://127.0.0.1:23456",
|
||||
excess_bw = 0.2,
|
||||
filterType = "rc", // rc: P25; widepulse: analog
|
||||
ifRate = 24000,
|
||||
plot = "",
|
||||
symbolRate = 4800,
|
||||
enableAnalog, //[on, off, auto]
|
||||
nbfmDeviation = 4000, // only needed if analog is enabled
|
||||
nbfmSquelch = -50, // only needed if analog is enabled
|
||||
frequency, // only needed if analog is enabled
|
||||
blacklist,
|
||||
whitelist,
|
||||
cryptKeys
|
||||
}){
|
||||
// Core Configs
|
||||
this.name = channelName;
|
||||
this.device = device;
|
||||
this.demod_type = demodType;
|
||||
this.destination = destination;
|
||||
this.excess_bw = excess_bw;
|
||||
this.filter_type = filterType;
|
||||
this.if_rate = ifRate;
|
||||
this.plot = plot;
|
||||
this.symbol_rate = symbolRate;
|
||||
this.enable_analog = enableAnalog;
|
||||
|
||||
// P25 config
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName) this.trunking_sysname = systemName;
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName && metaStreamName) this.meta_stream_name = metaStreamName ?? "";
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName) this.cqpsk_tracking = cqpskTracking;
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName) this.tracking_threshold = trackingThreshold;
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName) this.tracking_feedback = trackingFeedback;
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName && blacklist) this.blacklist = blacklist ?? "";
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName && whitelist) this.whitelist = whitelist ?? "";
|
||||
if (!enableAnalog || enableAnalog === "off" || systemName && cryptKeys) this.crypt_keys = cryptKeys ?? "";
|
||||
|
||||
// Analog config
|
||||
if (enableAnalog === "on" || enableAnalog === "auto") this.nbfm_deviation = nbfmDeviation;
|
||||
if (enableAnalog === "on" || enableAnalog === "auto") this.nbfm_squelch = nbfmSquelch;
|
||||
if (enableAnalog === "on" || enableAnalog === "auto") this.frequency = frequency;
|
||||
}
|
||||
}
|
||||
|
||||
class deviceConfig {
|
||||
constructor({args = "rtl", gain = "LNA:32", gainMode = false, name = "sdr0", offset = 0, ppm = 0.0, sampleRate = 1920000, tunable=true}) {
|
||||
this.args = args
|
||||
this.gains = gain
|
||||
this.gain_mode = gainMode
|
||||
this.name = name
|
||||
this.offset = offset
|
||||
this.ppm = ppm
|
||||
this.rate = sampleRate
|
||||
this.usable_bw_pct = 0.85
|
||||
this.tunable = tunable
|
||||
}
|
||||
}
|
||||
|
||||
class trunkingConfig {
|
||||
/**
|
||||
*
|
||||
* @param {object} *
|
||||
*/
|
||||
constructor({module, systemName, controlChannelsString, tagsFile = "", nac = "0x0", wacn = "0x0", cryptBehavior = 2, whitelist = "", blacklist = ""}) {
|
||||
this.module = module;
|
||||
this.chans = [{
|
||||
"nac": nac,
|
||||
"wacn": wacn,
|
||||
"sysname": systemName,
|
||||
"control_channel_list": controlChannelsString,
|
||||
"whitelist": whitelist,
|
||||
"blacklist": blacklist,
|
||||
"tgid_tags_file": tagsFile,
|
||||
"tdma_cc": false,
|
||||
"crypt_behavior": cryptBehavior
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
class audioConfig {
|
||||
constructor({module = "sockaudio.py", port = 23456, deviceName = "default"}) {
|
||||
this.module = module;
|
||||
this.instances = [{
|
||||
"instance_name": "audio0",
|
||||
"device_name": deviceName,
|
||||
"udp_port": port,
|
||||
"audio_gain": 1.0,
|
||||
"number_channels": 1
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
class metadataStreamConfig {
|
||||
constructor({}) {
|
||||
this.module = "";
|
||||
this.streams = [];
|
||||
}
|
||||
}
|
||||
|
||||
class terminalConfig {
|
||||
constructor({module = "terminal.py", terminalType = "http:0.0.0.0:8080"}) {
|
||||
this.module = module;
|
||||
this.terminal_type = terminalType;
|
||||
this.curses_plot_interval= 0.1;
|
||||
this.http_plot_interval= 1.0;
|
||||
this.http_plot_directory = "../www/images";
|
||||
this.tuning_step_large= 1200;
|
||||
this.tuning_step_small = 100;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ const { DebugBuilder } = require("../utilities/debugBuilder.js");
|
||||
const log = new DebugBuilder("client", "updatePresets");
|
||||
// Modules
|
||||
const fs = require('fs');
|
||||
const path = require("path");
|
||||
const converter = require("convert-units");
|
||||
|
||||
/**
|
||||
* Write the given presets to the JSON file
|
||||
@@ -10,7 +12,8 @@ const fs = require('fs');
|
||||
* @param {function} callback The function to be called when this wrapper completes
|
||||
*/
|
||||
function writePresets(presets, callback = undefined) {
|
||||
fs.writeFile("../config/radioPresets.json", JSON.stringify(presets), (err) => {
|
||||
log.DEBUG(`${__dirname}`);
|
||||
fs.writeFile("./config/radioPresets.json", JSON.stringify(presets), (err) => {
|
||||
// Error checking
|
||||
if (err) throw err;
|
||||
log.DEBUG("Write Complete");
|
||||
@@ -37,7 +40,7 @@ function sanitizeFrequencies(frequenciesArray) {
|
||||
/**
|
||||
* Function to convert a string or a float into the integer type needed to be saved
|
||||
* @param frequency Could be a string, number or float,
|
||||
* @returns {number|number|*} Return the value to be saved in Hz format ("154875000" = 154.875MHz)
|
||||
* @returns {number|number|*} Return the value to be saved in Hz format ("154.875"MHz format = "154875000")
|
||||
*/
|
||||
function convertFrequencyToHertz(frequency){
|
||||
// check if the passed value is a number
|
||||
@@ -50,18 +53,7 @@ function convertFrequencyToHertz(frequency){
|
||||
else {
|
||||
log.DEBUG(`${frequency} is a float value.`);
|
||||
// Convert to a string to remove the decimal in place and then correct the length
|
||||
frequency = frequency.toString();
|
||||
// One extra digit checked for the '.' included in the string
|
||||
if (frequency.length >= 8 && frequency.length <= 10) return parseInt(frequency.replace(".", ""));
|
||||
else if (frequency.length <= 7) {
|
||||
// Check to see if the frequency is 1s, 10s or 100s of MHz
|
||||
let zerosToBeRemoved = 3 - frequency.split(".")[0].length;
|
||||
// Need to add more 0s since it was in MHz format
|
||||
let neededZeros = (9 - frequency.length) - zerosToBeRemoved;
|
||||
frequency = frequency.replace(".", "") + '0'.repeat(neededZeros)
|
||||
|
||||
return parseInt(frequency);
|
||||
}
|
||||
return converter(frequency).from("MHz").to("Hz");
|
||||
}
|
||||
} else {
|
||||
log.DEBUG(`${frequency} is not a number`);
|
||||
@@ -76,7 +68,8 @@ function convertFrequencyToHertz(frequency){
|
||||
* @returns {any} The object containing the different systems the bot is near
|
||||
*/
|
||||
exports.getPresets = function getPresets() {
|
||||
return JSON.parse(fs.readFileSync("../config/radioPresets.json"));
|
||||
log.DEBUG(`Getting presets from directory: '${__dirname}'`);
|
||||
return JSON.parse(fs.readFileSync( "./config/radioPresets.json"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user