From fb8c0753d32ba4bd8ea81e9978fe24b2ac703fde Mon Sep 17 00:00:00 2001 From: NoobishSVK Date: Wed, 17 Jan 2024 22:46:34 +0100 Subject: [PATCH] remote control support --- README.md | 2 +- datahandler.js | 6 ++--- index.js | 68 ++++++++++++++++++++++++++++++++++++++++++-------- userconfig.js | 10 ++++++++ web/index.html | 14 +++++++---- web/main.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++ web/styles.css | 15 +++++++++++ 7 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 userconfig.js diff --git a/README.md b/README.md index b5047a3..f874c83 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ FM-DX Webserver is a cross-platform web server designed for FM DXers who want to - 🌐 **Web-Based Control:** Access and control your TEF6686 / F1HD receiver from any device with a web browser. - 📻 **FM DXing:** Enhance your FM DXing experience with a user-friendly web interface. +- **Cross-Platform:** You can run this on both Windows and Linux servers along with xdrd. ## Features to be added - **Tuner control:** Currently the tuner info is read only, however in the near future you will also be able to control via password authentication. -- **Cross-Platform:** Our main priority, as we use librdsparser, we are patiently waiting for a Windows version. - **Low-latency streaming**: Currently planned as a feature similar to WebSDRs to provide a zero-delay audio using your browser. - **Pre-compiled app version**: Currently planned right after finishing the low-latency streaming feature. diff --git a/datahandler.js b/datahandler.js index d76ec04..9630738 100644 --- a/datahandler.js +++ b/datahandler.js @@ -20,7 +20,7 @@ koffi.proto('void callback_ptyn(void *rds, void *user_data)'); const rdsparser = { new: lib.func('void* rdsparser_new()'), - clear: lib.func('void* rdsparser_clear()'), + clear: lib.func('void rdsparser_clear(void *rds)'), free: lib.func('void rdsparser_free(void *rds)'), parse_string: lib.func('bool rdsparser_parse_string(void *rds, const char *input)'), get_pi: lib.func('int32_t rdsparser_get_pi(void *rds)'), @@ -107,8 +107,8 @@ const callbacks = { }, 'callback_rt *'), ptyn: koffi.register((rds, flag) => ( - value = decode_unicode(rdsparser.get_ptyn(rds)), - console.log('PTYN: ' + value) + value = decode_unicode(rdsparser.get_ptyn(rds)) + /*console.log('PTYN: ' + value)*/ ), 'callback_ptyn *') }; diff --git a/index.js b/index.js index 30923a3..0d87132 100644 --- a/index.js +++ b/index.js @@ -6,29 +6,37 @@ const path = require('path'); const net = require('net'); const cors = require('cors'); const axios = require('axios'); +const crypto = require('crypto'); +let receivedSalt = ''; +let receivedPassword = false; // Other JS files const dataHandler = require('./datahandler'); +const config = require('./userconfig'); /* Server settings */ -const webServerHost = '192.168.1.14'; // IP of the web server -const webServerPort = 8080; // web server port +const webServerHost = config.webServerHost; // IP of the web server +const webServerPort = config.webServerPort; // web server port -const xdrdServerHost = '192.168.1.15'; // xdrd server iP -const xdrdServerPort = 7373; // xdrd server port +const xdrdServerHost = config.xdrdServerHost; // xdrd server iP +const xdrdServerPort = config.xdrdServerPort; // xdrd server port +const xdrdPassword = config.xdrdPassword; const wss = new WebSocket.Server({ noServer: true }); const app = express(); const httpServer = http.createServer(app); - +/* connection to xdrd */ +const client = new net.Socket(); /* webSocket handlers */ wss.on('connection', (ws) => { console.log('WebSocket client connected'); ws.on('message', (message) => { - console.log('Received message from client:', message); + console.log('Received message from client:', message.toString()); + newFreq = message.toString() * 1000; + client.write("T" + newFreq + '\n'); }); }); @@ -36,15 +44,56 @@ wss.on('connection', (ws) => { // Serve static files from the "web" folder app.use(express.static(path.join(__dirname, 'web'))); -/* connection to xdrd */ -const client = new net.Socket(); +// Function to authenticate with the xdrd server +function authenticateWithXdrd(client, salt, password) { + const sha1 = crypto.createHash('sha1'); + // Convert salt and password to buffers + const saltBuffer = Buffer.from(salt, 'utf-8'); + const passwordBuffer = Buffer.from(password, 'utf-8'); + + // Update the hash context with salt and password + sha1.update(saltBuffer); + sha1.update(passwordBuffer); + + // Finalize the hash and get the hashed password + const hashedPassword = sha1.digest('hex'); + client.write(hashedPassword + '\n'); + client.write('x\n'); +} + +// WebSocket client connection client.connect(xdrdServerPort, xdrdServerHost, () => { console.log('Connected to xdrd'); + + client.once('data', (data) => { + const receivedData = data.toString(); + const lines = receivedData.split('\n'); + + // Assuming that the first message contains the salt + if (lines.length > 0 && !receivedPassword) { + receivedSalt = lines[0].trim(); + authenticateWithXdrd(client, receivedSalt, xdrdPassword); + receivedPassword = true; + } + }); }); client.on('data', (data) => { const receivedData = data.toString(); + + const lines = receivedData.split('\n'); + + // If there's at least one line, set it as the received salt + /*if (lines.length > 0 && receivedPassword === false) { + receivedSalt = lines[0].trim(); // Trim any leading or trailing whitespace + console.log('Received Salt:', receivedSalt); + + // Authentication logic + authenticateWithXdrd(client, receivedSalt, xdrdPassword); + receivedPassword = true; + }*/ + wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { dataHandler.handleData(client, receivedData); @@ -52,12 +101,11 @@ client.on('data', (data) => { }); }); + client.on('close', () => { console.log('Disconnected from xdrd'); }); -client.write('x'); - /* HTTP Server */ httpServer.on('upgrade', (request, socket, head) => { diff --git a/userconfig.js b/userconfig.js new file mode 100644 index 0000000..eeb99d5 --- /dev/null +++ b/userconfig.js @@ -0,0 +1,10 @@ +const webServerHost = '192.168.1.14'; // IP of the web server +const webServerPort = 8080; // web server port + +const xdrdServerHost = '192.168.1.15'; // xdrd server iP +const xdrdServerPort = 7373; // xdrd server port +const xdrdPassword = ''; // xdrd password (optional) + +module.exports = { + webServerHost, webServerPort, xdrdServerHost, xdrdServerPort, xdrdPassword + }; \ No newline at end of file diff --git a/web/index.html b/web/index.html index f2717fa..f2fe47f 100644 --- a/web/index.html +++ b/web/index.html @@ -51,8 +51,9 @@ -
- +
+ +
@@ -73,8 +74,11 @@
- -
+ +
+

AF

+
+
@@ -92,7 +96,7 @@ -

FM-DX WebServer uses librds by Konrad Kosmatka.

+

FM-DX WebServer uses librdsparser by Konrad Kosmatka.

diff --git a/web/main.js b/web/main.js index 2531a55..aa51ee3 100644 --- a/web/main.js +++ b/web/main.js @@ -166,3 +166,68 @@ signalToggle.addEventListener("change", function() { signalText.textContent = 'dBf'; } }); + +const textInput = document.getElementById('commandinput'); + +textInput.addEventListener('keyup', function (event) { + // Get the current input value + let inputValue = textInput.value; + + // Remove non-digit characters + inputValue = inputValue.replace(/[^0-9]/g, ''); + + console.log("InputValue contains dot: ", inputValue.toLowerCase().includes(".")); + + // Determine where to add the dot based on the frequency range + if (inputValue.includes(".") === false) { + if (inputValue.startsWith('10') && inputValue.length > 2) { + // For frequencies starting with '10', add the dot after the third digit + inputValue = inputValue.slice(0, 3) + '.' + inputValue.slice(3); + textInput.value = inputValue; + } else if (inputValue.length > 2) { + // For other frequencies, add the dot after the second digit + inputValue = inputValue.slice(0, 2) + '.' + inputValue.slice(2); + textInput.value = inputValue; + } + } + + // Update the input value + + // Check if the pressed key is 'Enter' (key code 13) + if (event.key === 'Enter') { + // Retrieve the input value + const inputValue = textInput.value; + + // Send the input value to the WebSocket + if (socket.readyState === WebSocket.OPEN) { + socket.send(inputValue); + } + + // Clear the input field if needed + textInput.value = ''; + } +}); + +document.onkeydown = checkKey; + +function checkKey(e) { + e = e || window.event; + currentFreq = document.getElementById("data-frequency").textContent; + currentFreq = parseFloat(currentFreq).toFixed(3); + currentFreq = parseFloat(currentFreq); + + if (socket.readyState === WebSocket.OPEN) { + if (e.keyCode == '38') { + socket.send((currentFreq + 0.01).toFixed(3)); + } + else if (e.keyCode == '40') { + socket.send((currentFreq - 0.01).toFixed(3)); + } + else if (e.keyCode == '37') { + socket.send((currentFreq - 0.10).toFixed(3)); + } + else if (e.keyCode == '39') { + socket.send((currentFreq + 0.10).toFixed(3)); + } + } +} \ No newline at end of file diff --git a/web/styles.css b/web/styles.css index 632a1b2..d8d2ca7 100644 --- a/web/styles.css +++ b/web/styles.css @@ -130,7 +130,22 @@ h2 { background: #100d1f; } +input[type="text"] { + width: 100%; + height: 100%; + min-height: 46px; + border-radius: 30px; + padding-left: 20px; + box-sizing: border-box; + border: 0; + color: white; + background-color: var(--color-1); + font-family: 'Titillium Web', sans-serif; +} +input[type="text"]:focus { + outline: 2px solid var(--color-main-bright); +} @media only screen and (max-width: 768px) { .flex-container {