From a120355ee58b013c572ba42eecb7e6dfe8d882c7 Mon Sep 17 00:00:00 2001 From: NoobishSVK Date: Sun, 10 Mar 2024 22:42:43 +0100 Subject: [PATCH] serial port support, bugfixes, UI adjustments --- index.js | 180 +++++++++++++++------- package-lock.json | 320 +++++++++++++++++++++++++++++++++++++++- package.json | 3 +- server_config.js | 2 + tx_search.js | 1 - web/css/breadcrumbs.css | 5 +- web/css/buttons.css | 1 + web/index.ejs | 2 +- web/js/confighandler.js | 24 ++- web/js/main.js | 70 ++++----- web/js/settings.js | 4 +- web/js/setup.js | 9 ++ web/setup.ejs | 69 ++++++--- web/wizard.ejs | 58 ++++++-- 14 files changed, 618 insertions(+), 130 deletions(-) diff --git a/index.js b/index.js index 7ad3e91..f3fcd25 100644 --- a/index.js +++ b/index.js @@ -24,6 +24,7 @@ const client = new net.Socket(); // Other files and libraries const crypto = require('crypto'); const fs = require('fs'); +const { SerialPort } = require('serialport') const commandExists = require('command-exists-promise'); const dataHandler = require('./datahandler'); const fmdxList = require('./fmdx_list'); @@ -57,6 +58,7 @@ let currentUsers = 0; let connectedUsers = []; let streamEnabled = false; let incompleteDataBuffer = ''; +let serialport; app.use(bodyParser.urlencoded({ extended: true })); const sessionMiddleware = session({ @@ -96,10 +98,40 @@ function authenticateWithXdrd(client, salt, password) { } connectToXdrd(); +connectToSerial(); + +// Serial Connection +function connectToSerial() { + if (serverConfig.xdrd.wirelessConnection === false) { + + serialport = new SerialPort({path: serverConfig.xdrd.comPort, baudRate: 115200 }); + + serialport.on('open', () => { + logInfo('Using COM device: ' + serverConfig.xdrd.comPort); + serialport.write('x\n'); + if(serverConfig.defaultFreq) { + serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n'); + } else { + serialport.write('T87500\n'); + } + serialport.write('G00\n'); + + serialport.on('data', (data) => { + resolveDataBuffer(data); + }); + }); + + serialport.on('error', (error) => { + logError(error.message); + }); + + return serialport; + } +} // xdrd connection function connectToXdrd() { - if (serverConfig.xdrd.xdrdPassword.length > 1) { + if (serverConfig.xdrd.wirelessConnection === true) { client.connect(serverConfig.xdrd.xdrdPort, serverConfig.xdrd.xdrdIp, () => { logInfo('Connection to xdrd established successfully.'); @@ -157,12 +189,16 @@ function connectToXdrd() { dataHandler.dataToSend.ims = 0; break; } + } else if (line.startsWith('Z')) { + let modifiedLine = line.slice(1); + dataHandler.initialData.ant = modifiedLine; + dataHandler.dataToSend.ant = modifiedLine; } if (authFlags.authMsg && authFlags.firstClient) { client.write('x\n'); if(serverConfig.defaultFreq) { - client.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n') + client.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n'); } else { client.write('T87500\n'); } @@ -176,29 +212,7 @@ function connectToXdrd() { }; client.on('data', (data) => { - var receivedData = incompleteDataBuffer + data.toString(); - const isIncomplete = (receivedData.slice(-1) != '\n'); - - if (isIncomplete) { - const position = receivedData.lastIndexOf('\n'); - if (position < 0) { - incompleteDataBuffer = receivedData; - receivedData = ''; - } else { - incompleteDataBuffer = receivedData.slice(position + 1); - receivedData = receivedData.slice(0, position + 1); - } - } else { - incompleteDataBuffer = ''; - } - - if (receivedData.length) { - wss.clients.forEach((client) => { - if (client.readyState === WebSocket.OPEN) { - dataHandler.handleData(client, receivedData); - } - }); - } + resolveDataBuffer(data); }); client.on('data', authDataHandler); @@ -293,6 +307,32 @@ const authenticate = (req, res, next) => { app.set('view engine', 'ejs'); // Set EJS as the template engine app.set('views', path.join(__dirname, '/web')) +function resolveDataBuffer(data) { + var receivedData = incompleteDataBuffer + data.toString(); + const isIncomplete = (receivedData.slice(-1) != '\n'); + + if (isIncomplete) { + const position = receivedData.lastIndexOf('\n'); + if (position < 0) { + incompleteDataBuffer = receivedData; + receivedData = ''; + } else { + incompleteDataBuffer = receivedData.slice(position + 1); + receivedData = receivedData.slice(0, position + 1); + } + } else { + incompleteDataBuffer = ''; + } + + if (receivedData.length) { + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + dataHandler.handleData(client, receivedData); + } + }); + } +} + function parseMarkdown(parsed) { parsed = parsed.replace(/<\/?[^>]+(>|$)/g, ''); @@ -333,12 +373,24 @@ function removeMarkdown(parsed) { app.get('/', (req, res) => { if (!fs.existsSync(configName + '.json')) { - parseAudioDevice((result) => { - res.render('wizard', { - isAdminAuthenticated: true, - videoDevices: result.audioDevices, - audioDevices: result.videoDevices }); + let serialPorts; + + SerialPort.list() + .then((deviceList) => { + serialPorts = deviceList.map(port => ({ + path: port.path, + friendlyName: port.friendlyName, + })); + + parseAudioDevice((result) => { + res.render('wizard', { + isAdminAuthenticated: req.session.isAdminAuthenticated, + videoDevices: result.audioDevices, + audioDevices: result.videoDevices, + serialPorts: serialPorts + }); }); + }) } else { res.render('index', { isAdminAuthenticated: req.session.isAdminAuthenticated, @@ -359,30 +411,54 @@ app.get('/', (req, res) => { }); app.get('/wizard', (req, res) => { + let serialPorts; + + SerialPort.list() + .then((deviceList) => { + serialPorts = deviceList.map(port => ({ + path: port.path, + friendlyName: port.friendlyName, + })); + parseAudioDevice((result) => { - res.render('wizard', { + res.render('wizard', { isAdminAuthenticated: req.session.isAdminAuthenticated, videoDevices: result.audioDevices, - audioDevices: result.videoDevices }); + audioDevices: result.videoDevices, + serialPorts: serialPorts }); + }); + }) }) app.get('/setup', (req, res) => { - parseAudioDevice((result) => { - const processUptimeInSeconds = Math.floor(process.uptime()); - const formattedProcessUptime = formatUptime(processUptimeInSeconds); + let serialPorts; + + SerialPort.list() + .then((deviceList) => { + serialPorts = deviceList.map(port => ({ + path: port.path, + friendlyName: port.friendlyName, + })); + + parseAudioDevice((result) => { + const processUptimeInSeconds = Math.floor(process.uptime()); + const formattedProcessUptime = formatUptime(processUptimeInSeconds); + + res.render('setup', { + isAdminAuthenticated: req.session.isAdminAuthenticated, + videoDevices: result.audioDevices, + audioDevices: result.videoDevices, + serialPorts: serialPorts, + memoryUsage: (process.memoryUsage.rss() / 1024 / 1024).toFixed(1) + ' MB', + processUptime: formattedProcessUptime, + consoleOutput: consoleCmd.logs, + onlineUsers: dataHandler.dataToSend.users, + connectedUsers: connectedUsers + }); + }); + }) - res.render('setup', { - isAdminAuthenticated: req.session.isAdminAuthenticated, - videoDevices: result.audioDevices, - audioDevices: result.videoDevices, - memoryUsage: (process.memoryUsage.rss() / 1024 / 1024).toFixed(1) + ' MB', - processUptime: formattedProcessUptime, - consoleOutput: consoleCmd.logs, - onlineUsers: dataHandler.dataToSend.users, - connectedUsers: connectedUsers - }); - }); }); app.get('/api', (req, res) => { @@ -491,7 +567,7 @@ wss.on('connection', (ws, request) => { currentUsers++; dataHandler.showOnlineUsers(currentUsers); if(currentUsers === 1 && serverConfig.autoShutdown === true) { - connectToXdrd(); + serverConfig.xdrd.wirelessConnection === true ? connectToXdrd() : serialport.write('x\n'); } // Use ipinfo.io API to get geolocation information @@ -549,12 +625,12 @@ wss.on('connection', (ws, request) => { if(serverConfig.lockToAdmin === true) { if(request.session && request.session.isAdminAuthenticated === true) { - client.write(command + "\n"); + serverConfig.xdrd.wirelessConnection === true ? client.write(command + "\n") : serialport.write(command + "\n"); } else { return; } } else { - client.write(command + "\n"); + serverConfig.xdrd.wirelessConnection === true ? client.write(command + "\n") : serialport.write(command + "\n"); } } }); @@ -569,17 +645,17 @@ wss.on('connection', (ws, request) => { connectedUsers.splice(index, 1); // Remove the user's data from connectedUsers array } - if (currentUsers === 0 && serverConfig.defaultFreq && serverConfig.enableDefaultFreq && serverConfig.enableDefaultFreq === true) { + if (currentUsers === 0 && serverConfig.enableDefaultFreq === true && serverConfig.autoShutdown !== true && serverConfig.xdrd.wirelessConnection === true) { setTimeout(function() { if(currentUsers === 0) { client.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n'); - //dataHandler.resetToDefault(); + dataHandler.resetToDefault(dataHandler.dataToSend); dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3); } }, 10000) } - if (currentUsers === 0 && serverConfig.autoShutdown === true) { + if (currentUsers === 0 && serverConfig.autoShutdown === true && serverConfig.xdrd.wirelessConnection === true) { client.write('X\n'); } diff --git a/package-lock.json b/package-lock.json index 76f025d..c422591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "fm-dx-webserver", - "version": "1.0.8", + "version": "1.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fm-dx-webserver", - "version": "1.0.8", + "version": "1.1.3", "license": "ISC", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.11", @@ -20,6 +20,7 @@ "https": "1.0.0", "koffi": "2.7.2", "net": "1.0.2", + "serialport": "^12.0.0", "websocket": "1.0.34", "wrtc": "^0.4.7", "ws": "^8.14.2" @@ -44,6 +45,268 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@serialport/binding-mock": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz", + "integrity": "sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==", + "dependencies": { + "@serialport/bindings-interface": "^1.2.1", + "debug": "^4.3.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@serialport/binding-mock/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@serialport/binding-mock/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@serialport/bindings-cpp": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@serialport/bindings-cpp/-/bindings-cpp-12.0.1.tgz", + "integrity": "sha512-r2XOwY2dDvbW7dKqSPIk2gzsr6M6Qpe9+/Ngs94fNaNlcTRCV02PfaoDmRgcubpNVVcLATlxSxPTIDw12dbKOg==", + "hasInstallScript": true, + "dependencies": { + "@serialport/bindings-interface": "1.2.2", + "@serialport/parser-readline": "11.0.0", + "debug": "4.3.4", + "node-addon-api": "7.0.0", + "node-gyp-build": "4.6.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-11.0.0.tgz", + "integrity": "sha512-aZLJhlRTjSmEwllLG7S4J8s8ctRAS0cbvCpO87smLvl3e4BgzbVgF6Z6zaJd3Aji2uSiYgfedCdNc4L6W+1E2g==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-11.0.0.tgz", + "integrity": "sha512-rRAivhRkT3YO28WjmmG4FQX6L+KMb5/ikhyylRfzWPw0nSXy97+u07peS9CbHqaNvJkMhH1locp2H36aGMOEIA==", + "dependencies": { + "@serialport/parser-delimiter": "11.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@serialport/bindings-cpp/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@serialport/bindings-cpp/node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/@serialport/bindings-interface": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@serialport/bindings-interface/-/bindings-interface-1.2.2.tgz", + "integrity": "sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==", + "engines": { + "node": "^12.22 || ^14.13 || >=16" + } + }, + "node_modules/@serialport/parser-byte-length": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-12.0.0.tgz", + "integrity": "sha512-0ei0txFAj+s6FTiCJFBJ1T2hpKkX8Md0Pu6dqMrYoirjPskDLJRgZGLqoy3/lnU1bkvHpnJO+9oJ3PB9v8rNlg==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-cctalk": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-12.0.0.tgz", + "integrity": "sha512-0PfLzO9t2X5ufKuBO34DQKLXrCCqS9xz2D0pfuaLNeTkyGUBv426zxoMf3rsMRodDOZNbFblu3Ae84MOQXjnZw==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-delimiter": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-12.0.0.tgz", + "integrity": "sha512-gu26tVt5lQoybhorLTPsH2j2LnX3AOP2x/34+DUSTNaUTzu2fBXw+isVjQJpUBFWu6aeQRZw5bJol5X9Gxjblw==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-inter-byte-timeout": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-12.0.0.tgz", + "integrity": "sha512-GnCh8K0NAESfhCuXAt+FfBRz1Cf9CzIgXfp7SdMgXwrtuUnCC/yuRTUFWRvuzhYKoAo1TL0hhUo77SFHUH1T/w==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-packet-length": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-packet-length/-/parser-packet-length-12.0.0.tgz", + "integrity": "sha512-p1hiCRqvGHHLCN/8ZiPUY/G0zrxd7gtZs251n+cfNTn+87rwcdUeu9Dps3Aadx30/sOGGFL6brIRGK4l/t7MuQ==", + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@serialport/parser-readline": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-12.0.0.tgz", + "integrity": "sha512-O7cywCWC8PiOMvo/gglEBfAkLjp/SENEML46BXDykfKP5mTPM46XMaX1L0waWU6DXJpBgjaL7+yX6VriVPbN4w==", + "dependencies": { + "@serialport/parser-delimiter": "12.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-ready": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-12.0.0.tgz", + "integrity": "sha512-ygDwj3O4SDpZlbrRUraoXIoIqb8sM7aMKryGjYTIF0JRnKeB1ys8+wIp0RFMdFbO62YriUDextHB5Um5cKFSWg==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-regex": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-12.0.0.tgz", + "integrity": "sha512-dCAVh4P/pZrLcPv9NJ2mvPRBg64L5jXuiRxIlyxxdZGH4WubwXVXY/kBTihQmiAMPxbT3yshSX8f2+feqWsxqA==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-slip-encoder": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-slip-encoder/-/parser-slip-encoder-12.0.0.tgz", + "integrity": "sha512-0APxDGR9YvJXTRfY+uRGhzOhTpU5akSH183RUcwzN7QXh8/1jwFsFLCu0grmAUfi+fItCkR+Xr1TcNJLR13VNA==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/parser-spacepacket": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/parser-spacepacket/-/parser-spacepacket-12.0.0.tgz", + "integrity": "sha512-dozONxhPC/78pntuxpz/NOtVps8qIc/UZzdc/LuPvVsqCoJXiRxOg6ZtCP/W58iibJDKPZPAWPGYeZt9DJxI+Q==", + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/stream": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@serialport/stream/-/stream-12.0.0.tgz", + "integrity": "sha512-9On64rhzuqKdOQyiYLYv2lQOh3TZU/D3+IWCR5gk0alPel2nwpp4YwDEGiUBfrQZEdQ6xww0PWkzqth4wqwX3Q==", + "dependencies": { + "@serialport/bindings-interface": "1.2.2", + "debug": "4.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/@serialport/stream/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@serialport/stream/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1118,6 +1381,11 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, + "node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -1390,6 +1658,54 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/serialport": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-12.0.0.tgz", + "integrity": "sha512-AmH3D9hHPFmnF/oq/rvigfiAouAKyK/TjnrkwZRYSFZxNggJxwvbAbfYrLeuvq7ktUdhuHdVdSjj852Z55R+uA==", + "dependencies": { + "@serialport/binding-mock": "10.2.2", + "@serialport/bindings-cpp": "12.0.1", + "@serialport/parser-byte-length": "12.0.0", + "@serialport/parser-cctalk": "12.0.0", + "@serialport/parser-delimiter": "12.0.0", + "@serialport/parser-inter-byte-timeout": "12.0.0", + "@serialport/parser-packet-length": "12.0.0", + "@serialport/parser-readline": "12.0.0", + "@serialport/parser-ready": "12.0.0", + "@serialport/parser-regex": "12.0.0", + "@serialport/parser-slip-encoder": "12.0.0", + "@serialport/parser-spacepacket": "12.0.0", + "@serialport/stream": "12.0.0", + "debug": "4.3.4" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/serialport/donate" + } + }, + "node_modules/serialport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/serialport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", diff --git a/package.json b/package.json index 59de4b2..41e24cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fm-dx-webserver", - "version": "1.1.2", + "version": "1.1.3", "description": "", "main": "index.js", "scripts": { @@ -23,6 +23,7 @@ "https": "1.0.0", "koffi": "2.7.2", "net": "1.0.2", + "serialport": "^12.0.0", "websocket": "1.0.34", "wrtc": "^0.4.7", "ws": "^8.14.2" diff --git a/server_config.js b/server_config.js index 6b8772f..a98360b 100644 --- a/server_config.js +++ b/server_config.js @@ -18,6 +18,8 @@ let serverConfig = { chatEnabled: true }, xdrd: { + wirelessConnection: "", + comPort: "", xdrdIp: "127.0.0.1", xdrdPort: 7373, xdrdPassword: "" diff --git a/tx_search.js b/tx_search.js index b3c0d25..b9800ea 100644 --- a/tx_search.js +++ b/tx_search.js @@ -1,5 +1,4 @@ const fetch = require('node-fetch'); -var fs = require('fs'); const { serverConfig } = require('./server_config') let cachedData = {}; diff --git a/web/css/breadcrumbs.css b/web/css/breadcrumbs.css index 062f26c..a1ff0b6 100644 --- a/web/css/breadcrumbs.css +++ b/web/css/breadcrumbs.css @@ -212,6 +212,9 @@ label { text-transform: uppercase; } + #tuner-wireless { + display: none; + } @media (max-width: 768px) { canvas, #flags-container { display: none; @@ -340,6 +343,6 @@ label { height: 225px !important; } .chatbutton { - height: 86px !important; + height: 88px !important; } } \ No newline at end of file diff --git a/web/css/buttons.css b/web/css/buttons.css index fe37328..abbdacc 100644 --- a/web/css/buttons.css +++ b/web/css/buttons.css @@ -190,6 +190,7 @@ input[type="range"]::-moz-range-thumb { width: 100%; border-radius: 25px; font-weight: bold; + background-color: var(--color-2); } .toggleSwitch * { -webkit-box-sizing: border-box; diff --git a/web/index.ejs b/web/index.ejs index 815c409..64da018 100644 --- a/web/index.ejs +++ b/web/index.ejs @@ -119,7 +119,7 @@
- +
<% if (antennaSwitch) { %> diff --git a/web/js/confighandler.js b/web/js/confighandler.js index f3b56fa..1865283 100644 --- a/web/js/confighandler.js +++ b/web/js/confighandler.js @@ -8,7 +8,6 @@ function submitData() { var themeSelectedValue = $("#selected-theme").val(); var themeDataValue = $(".option:contains('" + themeSelectedValue + "')").attr('data-value') || 'theme1'; - const defaultTheme = themeDataValue; let presets = []; @@ -25,6 +24,11 @@ function submitData() { validateAndAdd(banlist); } + + var comDevicesValue = $("#com-devices").val(); + var comDevicesDataValue = $(".option:contains('" + comDevicesValue + "')").attr('data-value') || ''; + const comPort = comDevicesDataValue; + const wirelessConnection = $('#connection-type-toggle').is(":checked") || false; const xdrdIp = $('#xdrd-ip').val() || '127.0.0.1'; const xdrdPort = $('#xdrd-port').val() || '7373'; const xdrdPassword = $('#xdrd-password').val() || 'password'; @@ -66,6 +70,8 @@ function submitData() { banlist }, xdrd: { + comPort, + wirelessConnection, xdrdIp, xdrdPort, xdrdPassword @@ -108,7 +114,6 @@ function submitData() { data: JSON.stringify(data), success: function (message) { alert(message); - console.log(data); }, error: function (error) { console.error(error); @@ -155,13 +160,28 @@ function submitData() { $('#ip-addresses').val(data.webserver.banlist?.join('\n') || ""); + $('#connection-type-toggle').prop("checked", data.xdrd.wirelessConnection || false); + $('#xdrd-ip').val(data.xdrd.xdrdIp); $('#xdrd-port').val(data.xdrd.xdrdPort); $('#xdrd-password').val(data.xdrd.xdrdPassword); + $('#com-devices').val(data.xdrd.comPort); + var selectedDevice = $(".option[data-value='" + data.xdrd.comPort + "']"); + if (selectedDevice.length > 0) { + $("#com-devices").val(selectedDevice.text()); + } $('#audio-devices').val(data.audio.audioDevice); $('#audio-channels').val(data.audio.audioChannels); + var selectedChannels = $(".option[data-value='" + data.audio.audioChannels + "']"); + if (selectedChannels.length > 0) { + $("#audio-channels").val(selectedChannels.text()); + } $('#audio-quality').val(data.audio.audioBitrate); + var selectedQuality = $(".option[data-value='" + data.audio.audioBitrate + "']"); + if (selectedQuality.length > 0) { + $("#audio-quality").val(selectedQuality.text()); + } $('#webserver-name').val(data.identification.tunerName); $('#webserver-desc').val(data.identification.tunerDesc); diff --git a/web/js/main.js b/web/js/main.js index 16c5197..9c84ac9 100644 --- a/web/js/main.js +++ b/web/js/main.js @@ -530,16 +530,16 @@ function copyToClipboard(textToCopy) { } function findOnMaps() { - var frequency = $('#data-frequency').text(); + var frequency = parseFloat($('#data-frequency').text()).toFixed(1); var pi = $('#data-pi').text(); var latitude = localStorage.getItem('qthLongitude'); var longitude = localStorage.getItem('qthLatitude'); - frequency = parseFloat(frequency).toFixed(1); - var url = "https://maps.fmdx.pl/#qth=" + longitude + "," + latitude + "&freq=" + frequency + "&pi=" + pi; + var url = `https://maps.fmdx.pl/#qth=${longitude},${latitude}&freq=${frequency}&findPi=${pi}`; window.open(url, "_blank"); } + function updateSignalUnits(parsedData, averageSignal) { const signalUnit = localStorage.getItem('signalUnit'); let currentSignal; @@ -577,35 +577,37 @@ function updateSignalUnits(parsedData, averageSignal) { } function updateDataElements(parsedData) { - $('#data-frequency').text(parsedData.freq); - $("#commandinput").attr("aria-label", "Current frequency: " + parsedData.freq); - $('#data-pi').html(parsedData.pi === '?' ? "?" : parsedData.pi); + const $dataFrequency = $('#data-frequency'); + const $commandInput = $("#commandinput"); + const $dataPi = $('#data-pi'); + const $dataPs = $('#data-ps'); + const $dataSt = $('.data-st'); + const $dataRt0 = $('#data-rt0'); + const $dataRt1 = $('#data-rt1'); + const $dataAntInput = $('#data-ant input'); + const $dataStationContainer = $('#data-station-container'); + const $dataTp = $('.data-tp'); + const $dataTa = $('.data-ta'); + const $dataMs = $('.data-ms'); + const $dataPty = $('.data-pty'); + + $dataFrequency.text(parsedData.freq); + $commandInput.attr("aria-label", "Current frequency: " + parsedData.freq); + $dataPi.html(parsedData.pi === '?' ? "?" : parsedData.pi); + if (localStorage.getItem('psUnderscores') === 'true') { parsedData.ps = parsedData.ps.replace(/\s/g, '_'); } - $('#data-ps').html(parsedData.ps === '?' ? "?" : processString(parsedData.ps, parsedData.ps_errors)); - $('.data-pty').html(europe_programmes[parsedData.pty]); + $dataPs.html(parsedData.ps === '?' ? "?" : processString(parsedData.ps, parsedData.ps_errors)); + $dataSt.html(`${parsedData.st_forced ? 'MO' : 'ST'}`); + $dataRt0.html(processString(parsedData.rt0, parsedData.rt0_errors)); + $dataRt1.html(processString(parsedData.rt1, parsedData.rt1_errors)); + $dataPty.html(europe_programmes[parsedData.pty]); - - if(parsedData.st === true) { - if (parsedData.st_forced == true) { - $('.data-st').html("MO"); - } else { - $('.data-st').html("ST"); - } - } else { - if (parsedData.st_forced == true) { - $('.data-st').html("MO"); - } else { - $('.data-st').html("ST"); - } - } - - $('#data-rt0').html(processString(parsedData.rt0, parsedData.rt0_errors)); - $('#data-rt1').html(processString(parsedData.rt1, parsedData.rt1_errors)); $('.data-flag').html(``); $('.data-flag-big').html(``); - $('#data-ant input').val($('#data-ant li[data-value="' + parsedData.ant + '"]').text()); + + $dataAntInput.val($('#data-ant li[data-value="' + parsedData.ant + '"]').text()); if (parsedData.txInfo.station.length > 1) { $('#data-station-name').text(parsedData.txInfo.station.replace(/%/g, '%25')); @@ -615,16 +617,16 @@ function updateDataElements(parsedData) { $('#data-station-pol').text(parsedData.txInfo.pol); $('#data-station-distance').text(parsedData.txInfo.distance); $('#data-station-azimuth').text(parsedData.txInfo.azimuth); - $('#data-station-container').css('display', 'block'); + $dataStationContainer.css('display', 'block'); } else { - $('#data-station-container').removeAttr('style'); + $dataStationContainer.removeAttr('style'); } updateCounter++; if(updateCounter % 8 === 0) { - $('.data-tp').html(parsedData.tp === 0 ? "TP" : "TP"); - $('.data-ta').html(parsedData.ta === 0 ? "TA" : "TA"); - $('.data-ms').html(parsedData.ms === 0 + $dataTp.html(parsedData.tp === 0 ? "TP" : "TP"); + $dataTa.html(parsedData.ta === 0 ? "TA" : "TA"); + $dataMs.html(parsedData.ms === 0 ? "MS" : (parsedData.ms === -1 ? "MS" @@ -634,9 +636,9 @@ function updateDataElements(parsedData) { } if (updateCounter % 30 === 0) { - $('#data-ps').attr('aria-label', parsedData.ps); - $('#data-rt0').attr('aria-label', parsedData.rt0); - $('#data-rt1').attr('aria-label', parsedData.rt1); + $dataPs.attr('aria-label', parsedData.ps); + $dataRt0.attr('aria-label', parsedData.rt0); + $dataRt1.attr('aria-label', parsedData.rt1); } } diff --git a/web/js/settings.js b/web/js/settings.js index d9aa3b3..0fce5be 100644 --- a/web/js/settings.js +++ b/web/js/settings.js @@ -1,9 +1,9 @@ -var currentDate = new Date('March 4, 2024 22:00:00'); +var currentDate = new Date('March 10, 2024 22:00:00'); var day = currentDate.getDate(); var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1 var year = currentDate.getFullYear(); var formattedDate = day + '/' + month + '/' + year; -var currentVersion = 'v1.1.2a [' + formattedDate + ']'; +var currentVersion = 'v1.1.3 [' + formattedDate + ']'; /** diff --git a/web/js/setup.js b/web/js/setup.js index e1678e8..d5cc920 100644 --- a/web/js/setup.js +++ b/web/js/setup.js @@ -50,6 +50,15 @@ $(document).ready(function() { } }); + $('#connection-type-toggle').change(function(){ + if($(this).is(":checked")) { + $('#tuner-usb').hide(); + $('#tuner-wireless').show(); + } else { + $('#tuner-wireless').hide(); + $('#tuner-usb').show(); + } +}); $('#login-form').submit(function (event) { event.preventDefault(); diff --git a/web/setup.ejs b/web/setup.ejs index 1639f34..34885f8 100644 --- a/web/setup.ejs +++ b/web/setup.ejs @@ -125,20 +125,50 @@

Connection settings

You can set up your connection settings here. Changing these settings requires a server restart.

Tuner connection:

-

If you are connecting your tuner wirelessly, enter the tuner IP.
If you use xdrd, use 127.0.0.1 as your IP.

-
- - -
-
- - -
-
- - -
-
+ +
+ +
+ +
+
+ + +
+
+ +
+

If you are connecting your tuner wirelessly, enter the tuner IP.
If you use xdrd, use 127.0.0.1 as your IP.

+
+ + +
+
+ + +
+
+ + +
+
+ +
+

Webserver connection:

Leave the IP at 0.0.0.0 unless you explicitly know you have to change it.
Don't enter your public IP here.

@@ -177,9 +207,9 @@

Audio channel count.
- 1: Mono • 2: Stereo + Choose between Mono / Stereo.

- +