diff --git a/gui/daemon.js b/gui/daemon.js index 1dd0694f..f380114a 100644 --- a/gui/daemon.js +++ b/gui/daemon.js @@ -221,7 +221,7 @@ exports.getDaemonState = function() { // START TNC // ` `== multi line string -exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq, rx_buffer_size, enable_explorer) { +exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, devicename, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq, rx_buffer_size, enable_explorer, explorer_stats, auto_tune) { var json_command = JSON.stringify({ type: 'set', command: 'start_tnc', @@ -250,7 +250,9 @@ exports.startTNC = function(mycall, mygrid, rx_audio, tx_audio, radiocontrol, de tx_audio_level : tx_audio_level, respond_to_cq : respond_to_cq, rx_buffer_size : rx_buffer_size, - enable_explorer : enable_explorer + enable_explorer : enable_explorer, + enable_stats: explorer_stats, + enable_auto_tune: auto_tune }] }) diff --git a/gui/main.js b/gui/main.js index 808a45d8..c251f169 100644 --- a/gui/main.js +++ b/gui/main.js @@ -96,7 +96,9 @@ const configDefaultSettings = '{\ "rx_buffer_size" : "16", \ "enable_explorer" : "False", \ "wftheme": 2, \ - "high_graphics" : "True"\ + "high_graphics" : "True",\ + "explorer_stats" : "False", \ + "auto_tune" : "False" \ }'; if (!fs.existsSync(configPath)) { @@ -467,6 +469,10 @@ ipcMain.on('request-update-transmission-status', (event, arg) => { win.webContents.send('action-update-transmission-status',arg); }); +ipcMain.on('request-update-reception-status', (event, arg) => { + win.webContents.send('action-update-reception-status',arg); +}); + ipcMain.on('request-open-tnc-log', () => { logViewer.show(); }); @@ -503,7 +509,8 @@ console.log(filepath.filePaths[0]) try { //fs.readFile(filepath.filePaths[0], 'utf8', function (err, data) { - fs.readFile(filepath.filePaths[0], 'binary', function (err, data) { + //Has to be binary + fs.readFile(filepath.filePaths[0],'binary', function (err, data) { console.log(data.length) @@ -537,15 +544,10 @@ ipcMain.on('save-file-to-folder',(event,data)=>{ console.log(data.file) try { - - let buffer = Buffer.from(data.file); - let arraybuffer = Uint8Array.from(buffer); + let arraybuffer = Buffer.from(data.file,"base64").toString('utf-8'); console.log(arraybuffer) - fs.writeFile(filepath.filePath, data.file, 'binary', function (err, data) { - //fs.writeFile(filepath.filePath, arraybuffer, function (err, data) { - //fs.writeFile(filepath.filePath, arraybuffer, 'binary', function(err) { - //fs.writeFile(filepath.filePath, new Uint8Array(Buffer.from(data.file)), function (err, data) { - //fs.writeFile(filepath.filePath, Buffer.from(data.file), function (err, data) { + //Has to be binary + fs.writeFile(filepath.filePath, arraybuffer, 'binary', function (err, data) { }) } catch (err) { console.log(err); diff --git a/gui/preload-chat.js b/gui/preload-chat.js index 73e31a63..de9f517d 100644 --- a/gui/preload-chat.js +++ b/gui/preload-chat.js @@ -5,8 +5,6 @@ const { const { v4: uuidv4 } = require('uuid'); -const utf8 = require('utf8'); -const blobUtil = require('blob-util') // https://stackoverflow.com/a/26227660 var appDataFolder = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME + "/.config") var configFolder = path.join(appDataFolder, "FreeDATA"); @@ -163,11 +161,10 @@ window.addEventListener('DOMContentLoaded', () => { document.querySelector('emoji-picker').addEventListener("emoji-click", (event) => { var msg = document.getElementById('chatModuleMessage'); - var picker = document.getElementById("emojipickercontainer"); - msg.setRangeText(event.detail.emoji.unicode) - console.log(event.detail); - picker.style.display="none"; - msg.focus(); + //Convert to utf-8--so we can just use utf-8 everywhere + msg.setRangeText(event.detail.emoji.unicode.toString('utf-8')); + //console.log(event.detail); + //msg.focus(); }) document.getElementById("emojipickerbutton").addEventListener("click", () => { var element = document.getElementById("emojipickercontainer") @@ -310,7 +307,8 @@ db.post({ var dxcallsign = selected_callsign.toUpperCase(); var textarea = document.getElementById('chatModuleMessage') var chatmessage = textarea.value; - + //Remove non-printable chars from begining and end of string--should save us a byte here and there + chatmessage = chatmessage.toString().trim(); // reset textarea size var message_container_height_offset = 150; var message_container_height = `calc(100% - ${message_container_height_offset}px)`; @@ -357,7 +355,8 @@ db.post({ _attachments: { [filename]: { content_type: filetype, - data: btoa(file) + //data: btoa(file) + data: btoa_FD(file) } } }).then(function(response) { @@ -367,7 +366,6 @@ db.post({ }).catch(function(err) { console.log(err); }); - update_chat_obj_by_uuid(uuid); // clear input @@ -475,7 +473,9 @@ ipcRenderer.on('action-new-msg-received', (event, arg) => { // handle ARQ transmission } else if (item.arq == 'transmission' && item.status == 'received') { - var encoded_data = atob(item.data); + //var encoded_data = atob(item.data); + //var encoded_data = Buffer.from(item.data,'base64').toString('utf-8'); + var encoded_data = atob_FD(item.data); var splitted_data = encoded_data.split(split_char); console.log(splitted_data) @@ -486,14 +486,16 @@ ipcRenderer.on('action-new-msg-received', (event, arg) => { obj.command = splitted_data[1]; obj.checksum = splitted_data[2]; // convert message to unicode from utf8 because of emojis - obj.uuid = utf8.decode(splitted_data[3]); - obj.msg = utf8.decode(splitted_data[5]); + //No, don't convert; we're already UTF-8!!!!! + obj.uuid = splitted_data[3]; + obj.msg = splitted_data[5]; obj.status = 'null'; obj.snr = 'null'; obj.type = 'received'; - obj.filename = utf8.decode(splitted_data[6]); - obj.filetype = utf8.decode(splitted_data[7]); - obj.file = btoa(splitted_data[8]); + obj.filename = splitted_data[6]; + obj.filetype = splitted_data[7]; + //obj.file = btoa(splitted_data[8]); + obj.file = btoa_FD(splitted_data[8]); add_obj_to_database(obj); update_chat_obj_by_uuid(obj.uuid); @@ -535,7 +537,8 @@ update_chat = function(obj) { // get filesize of new submitted data // not that nice.... // we really should avoid converting back from base64 for performance reasons... - var filesize = Math.ceil(atob(obj._attachments[filename]["data"]).length) + "Bytes"; + //var filesize = Math.ceil(atob(obj._attachments[filename]["data"]).length) + "Bytes"; + var filesize = Math.ceil(atob_FD(obj._attachments[filename]["data"]).length) + " Bytes"; } // check if image, then display it @@ -853,7 +856,7 @@ update_chat = function(obj) { var filename = Object.keys(obj._attachments)[0] var filetype = filename.content_type - + console.log(filename) console.log(filetype) var file = obj._attachments[filename].data @@ -863,6 +866,24 @@ update_chat = function(obj) { //var file = atob(obj._attachments[filename]["data"]) db.getAttachment(obj._id, filename).then(function(data) { console.log(data) + //Rewrote this part to use buffers to ensure encoding is corect -- n1qm + var binaryString = atob_FD(data); + + console.log(binaryString); + var data_with_attachment = doc.timestamp + split_char + doc.msg + split_char + filename + split_char + filetype + split_char + binaryString; + let Data = { + command: "send_message", + dxcallsign: doc.dxcallsign, + mode: 255, + frames: 1, + data: data_with_attachment, + checksum: doc.checksum, + uuid: doc.uuid + }; + console.log(Data) + ipcRenderer.send('run-tnc-command', Data); + }); + /* // convert blob data to binary string blobUtil.blobToBinaryString(data).then(function (binaryString) { console.log(binaryString) @@ -891,6 +912,7 @@ update_chat = function(obj) { }); }); + */ }).catch(function(err) { console.log(err); }); @@ -1038,4 +1060,22 @@ var crc32 = function(str) { } return (crc ^ (-1)) >>> 0; -}; \ No newline at end of file +}; +/** + * Binary to ASCII replacement + * @param {string} data in normal/usual utf-8 format + * @returns base64 encoded string + */ +function btoa_FD(data) +{ + return Buffer.from(data,'utf-8').toString('base64'); +} +/** + * ASCII to Binary replacement + * @param {string} data in base64 encoding + * @returns utf-8 normal/usual string + */ +function atob_FD(data) +{ + return Buffer.from(data,'base64').toString('utf-8'); +} \ No newline at end of file diff --git a/gui/preload-main.js b/gui/preload-main.js index b9ec859b..a44e459f 100644 --- a/gui/preload-main.js +++ b/gui/preload-main.js @@ -261,13 +261,27 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', () if(config.enable_explorer == 'True'){ document.getElementById("ExplorerSwitch").checked = true; + document.getElementById("ExplorerStatsSwitch").disabled=false; + if (config.explorer_stats.toLowerCase() == 'true') { + document.getElementById("ExplorerStatsSwitch").checked=true; + } else { + document.getElementById("ExplorerStatsSwitch").checked=false; + } + + } else { document.getElementById("ExplorerSwitch").checked = false; + document.getElementById("ExplorerStatsSwitch").disabled=true; + document.getElementById("ExplorerStatsSwitch").checked=false; + } + if(config.auto_tune == 'True'){ + document.getElementById("autoTuneSwitch").checked = true; + } else { + document.getElementById("autoTuneSwitch").checked = false; } // theme selector if(config.theme != 'default'){ - var theme_path = "../node_modules/bootswatch/dist/"+ config.theme +"/bootstrap.min.css"; document.getElementById("theme_selector").value = config.theme; document.getElementById("bootstrap_theme").href = escape(theme_path); @@ -1086,8 +1100,31 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => { document.getElementById("ExplorerSwitch").addEventListener("click", () => { if(document.getElementById("ExplorerSwitch").checked == true){ config.enable_explorer = "True"; + document.getElementById("ExplorerStatsSwitch").disabled=false; } else { config.enable_explorer = "False"; + config.explorer_stats = "False"; + document.getElementById("ExplorerStatsSwitch").disabled=true; + document.getElementById("ExplorerStatsSwitch").checked=false; + document.getElementById("ExplorerSwitch").checked = false; + } + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + }); + // enable explorer stats Switch clicked + document.getElementById("ExplorerStatsSwitch").addEventListener("click", () => { + if(document.getElementById("ExplorerStatsSwitch").checked == true){ + config.explorer_stats = "True"; + } else { + config.explorer_stats = "False"; + } + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + }); + // enable explorer stats Switch clicked + document.getElementById("autoTuneSwitch").addEventListener("click", () => { + if(document.getElementById("autoTuneSwitch").checked == true){ + config.auto_tune = "True"; + } else { + config.auto_tune = "False"; } fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); }); @@ -1253,7 +1290,16 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => { } else { var enable_explorer = "False"; } - + if (document.getElementById("ExplorerStatsSwitch").checked == true){ + var explorer_stats = "True"; + } else { + var explorer_stats = "False"; + } + if (document.getElementById("autoTuneSwitch").checked == true){ + var auto_tune = "True"; + } else { + var auto_tune = "False"; + } // loop through audio device list and select for(i = 0; i < document.getElementById("audio_input_selectbox").length; i++) { device = document.getElementById("audio_input_selectbox")[i]; @@ -1313,6 +1359,8 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => { config.respond_to_cq = respond_to_cq; config.rx_buffer_size = rx_buffer_size; config.enable_explorer = enable_explorer; + config.explorer_stats = explorer_stats; + config.auto_tune = auto_tune; fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); @@ -1331,7 +1379,7 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => { */ - daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq, rx_buffer_size, enable_explorer); + daemon.startTNC(callsign_ssid, mygrid, rx_audio, tx_audio, radiocontrol, deviceid, deviceport, pttprotocol, pttport, serialspeed, data_bits, stop_bits, handshake, rigctld_ip, rigctld_port, enable_fft, enable_scatter, low_bandwidth_mode, tuning_range_fmin, tuning_range_fmax, enable_fsk, tx_audio_level, respond_to_cq, rx_buffer_size, enable_explorer,explorer_stats,auto_tune); }) @@ -1484,33 +1532,52 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => { }; ipcRenderer.send('request-show-chat-window', Data); }) - - - - - - - - }) -//Listen for events caused by tnc 'tnc-message's -ipcRenderer.on('action-update-transmission-status', (event, arg) => { +function connectedStation(data) +{ + if ((typeof(data.dxcallsign) == 'undefined')) { + return; + } + if (!(typeof(data.arq) == 'undefined') && data.arq.toLowerCase() == 'session') { + var prefix = "w/ "; + } else { + switch (data.irs){ + case 'True': + //We are receiving station + var prefix = "de "; + break; + case 'False': + //We are sending station + var prefix = "to "; + break; + default: + //Shouldn't happen + console.trace('No data.irs data in tnc-message'); + var prefix = ""; + break; + } + + } + document.getElementById("txtConnectedWith").textContent=prefix + data.dxcallsign; +} + +//Listen for events caused by tnc 'tnc-message' rx +ipcRenderer.on('action-update-reception-status', (event, arg) => { var data =arg["data"][0]; var txprog = document.getElementById("transmission_progress") ipcRenderer.send('request-show-electron-progressbar',data.percent); txprog.setAttribute("aria-valuenow", data.percent); txprog.setAttribute("style", "width:" + data.percent + "%;"); - - // SET TIME LEFT UNTIL FINIHED - if (typeof(data.finished) == 'undefined') { - var time_left = 0; + + // SET TIME LEFT UNTIL FINIHED + if (typeof(data.finished) == 'undefined') { + var time_left = "time left: estimating"; } else { var arq_seconds_until_finish = data.finished var hours = Math.floor(arq_seconds_until_finish / 3600); var minutes = Math.floor((arq_seconds_until_finish % 3600) / 60 ); var seconds = arq_seconds_until_finish % 60; - if(hours < 0) { hours = 0; } @@ -1520,9 +1587,14 @@ ipcRenderer.on('action-update-transmission-status', (event, arg) => { if(seconds < 0) { seconds = 0; } - var time_left = "time left: ~ "+ minutes + "min" + " " + seconds + "s"; + if (hours > 0) + { + time_left = "time left: ~"+ hours.toString().padStart(2,'0') + ":" + minutes.toString().padStart(2,'0') + "." + seconds.toString().padStart(2,'0'); + } else { + time_left = "time left: ~"+ minutes.toString().padStart(2,'0') + "." + seconds.toString().padStart(2,'0'); + } } - document.getElementById("transmission_timeleft").textContent = time_left; + var time_left = "" + time_left +" || Speed/min: "; // SET BYTES PER MINUTE if (typeof(data.bytesperminute) == 'undefined') { @@ -1530,7 +1602,6 @@ ipcRenderer.on('action-update-transmission-status', (event, arg) => { } else { var arq_bytes_per_minute = data.bytesperminute; } - document.getElementById("bytes_per_min").textContent = arq_bytes_per_minute; // SET BYTES PER MINUTE COMPRESSED var compress = data.compression; @@ -1538,10 +1609,70 @@ ipcRenderer.on('action-update-transmission-status', (event, arg) => { compress = 1; } var arq_bytes_per_minute_compressed = Math.round(arq_bytes_per_minute * compress); - document.getElementById("bytes_per_min_compressed").textContent = arq_bytes_per_minute_compressed; + time_left += formatBytes(arq_bytes_per_minute,1) + " (comp: " + formatBytes(arq_bytes_per_minute_compressed,1) + ")"; + + + document.getElementById("transmission_timeleft").innerHTML = time_left; + connectedStation(data); }); +//Listen for events caused by tnc 'tnc-message's tx +ipcRenderer.on('action-update-transmission-status', (event, arg) => { + var data =arg["data"][0]; + var txprog = document.getElementById("transmission_progress") + ipcRenderer.send('request-show-electron-progressbar',data.percent); + txprog.setAttribute("aria-valuenow", data.percent); + txprog.setAttribute("style", "width:" + data.percent + "%;"); + + // SET TIME LEFT UNTIL FINIHED + if (typeof(data.finished) == 'undefined') { + var time_left = "time left: estimating"; + } else { + var arq_seconds_until_finish = data.finished + var hours = Math.floor(arq_seconds_until_finish / 3600); + var minutes = Math.floor((arq_seconds_until_finish % 3600) / 60 ); + var seconds = arq_seconds_until_finish % 60; + if(hours < 0) { + hours = 0; + } + if(minutes < 0) { + minutes = 0; + } + if(seconds < 0) { + seconds = 0; + } + if (hours > 0) + { + time_left = "time left: ~"+ hours.toString().padStart(2,'0') + ":" + minutes.toString().padStart(2,'0') + "." + seconds.toString().padStart(2,'0'); + } else { + time_left = "time left: ~"+ minutes.toString().padStart(2,'0') + "." + seconds.toString().padStart(2,'0'); + } + } + var time_left = "" + time_left +" || Speed/min: "; + + // SET BYTES PER MINUTE + if (typeof(data.bytesperminute) == 'undefined') { + var arq_bytes_per_minute = 0; + } else { + var arq_bytes_per_minute = data.bytesperminute; + } + + // SET BYTES PER MINUTE COMPRESSED + var compress = data.compression; + if (isNaN(compress)) { + compress = 1; + } + var arq_bytes_per_minute_compressed = Math.round(arq_bytes_per_minute * compress); + + time_left += formatBytes(arq_bytes_per_minute,1) + " (comp: " + formatBytes(arq_bytes_per_minute_compressed,1) + ")"; + + connectedStation(data); + +}); + + + var slowRollTable=4; ipcRenderer.on('action-update-tnc-state', (event, arg) => { @@ -1563,9 +1694,7 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { // DATA STATE global.rxBufferLengthTnc = arg.rx_buffer_length - // START OF SCATTER CHART - const scatterConfig = { plugins: { legend: { @@ -1574,7 +1703,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { tooltip: { enabled: false }, - annotation: { annotations: { line1: { @@ -1593,9 +1721,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { } } }, - - - }, animations: false, scales: { @@ -1610,7 +1735,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { } }, y: { - display: true, min: -80, max: 80, @@ -1654,7 +1778,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { // END OF SCATTER CHART // START OF SPEED CHART - var speedDataTime = [] if (typeof(arg.speed_list) == 'undefined') { @@ -1683,7 +1806,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { speedDataSnr.push(arg.speed_list[i].snr) } - var speedChartConfig = { type: 'line', }; @@ -1710,7 +1832,6 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => { yAxisID: 'SPEED', } ], - }; var speedChartOptions = { @@ -1748,19 +1869,9 @@ var speedChartOptions = { global.speedChart.update(); } } - // END OF SPEED CHART // PTT STATE - /* - if (arg.ptt_state == 'True') { - document.getElementById("ptt_state").className = "btn btn-sm btn-danger"; - } else if (arg.ptt_state == 'False') { - document.getElementById("ptt_state").className = "btn btn-sm btn-success"; - } else { - document.getElementById("ptt_state").className = "btn btn-sm btn-secondary"; - } - */ switch (arg.ptt_state){ case 'True': document.getElementById("ptt_state").className = "btn btn-sm btn-danger"; @@ -1771,33 +1882,16 @@ var speedChartOptions = { default: document.getElementById("ptt_state").className = "btn btn-sm btn-secondary"; break; - } + // AUDIO RECORDING if (arg.audio_recording == 'True') { - document.getElementById("startStopRecording").className = "btn btn-sm btn-danger"; document.getElementById("startStopRecording").textContent = "Stop Rec" - } else if (arg.ptt_state == 'False') { - document.getElementById("startStopRecording").className = "btn btn-sm btn-danger"; - document.getElementById("startStopRecording").textContent = "Start Rec" } else { - document.getElementById("startStopRecording").className = "btn btn-sm btn-danger"; document.getElementById("startStopRecording").textContent = "Start Rec" } // CHANNEL BUSY STATE - /* - if (arg.channel_busy == 'True') { - document.getElementById("channel_busy").className = "btn btn-sm btn-danger"; - - } else if (arg.channel_busy == 'False') { - document.getElementById("channel_busy").className = "btn btn-sm btn-success"; - - } else { - document.getElementById("channel_busy").className = "btn btn-sm btn-secondary"; - - } - */ switch (arg.channel_busy){ case 'True': document.getElementById("channel_busy").className = "btn btn-sm btn-danger"; @@ -1811,19 +1905,6 @@ var speedChartOptions = { } // BUSY STATE - /* - if (arg.busy_state == 'BUSY') { - document.getElementById("busy_state").className = "btn btn-sm btn-danger"; - document.getElementById("startTransmission").disabled = true; - //document.getElementById("stopTransmission").disabled = false; - } else if (arg.busy_state == 'IDLE') { - document.getElementById("busy_state").className = "btn btn-sm btn-success"; - } else { - document.getElementById("busy_state").className = "btn btn-sm btn-secondary"; - document.getElementById("startTransmission").disabled = true; - //document.getElementById("stopTransmission").disabled = false; - } - */ switch(arg.busy_state){ case 'BUSY': document.getElementById("busy_state").className = "btn btn-sm btn-danger"; @@ -1839,61 +1920,32 @@ var speedChartOptions = { } // ARQ STATE - /* - if (arg.arq_state == 'True') { - document.getElementById("arq_state").className = "btn btn-sm btn-warning"; - //document.getElementById("startTransmission").disabled = true; - document.getElementById("startTransmission").disabled = false; - //document.getElementById("stopTransmission").disabled = false; - } else if (arg.arq_state == 'False') { - document.getElementById("arq_state").className = "btn btn-sm btn-secondary"; - document.getElementById("startTransmission").disabled = false; - //document.getElementById("stopTransmission").disabled = true; - } else { - document.getElementById("arq_state").className = "btn btn-sm btn-secondary"; - //document.getElementById("startTransmission").disabled = true; - document.getElementById("startTransmission").disabled = false; - //document.getElementById("stopTransmission").disabled = false; - } - */ switch (arg.arq_state){ case 'True': document.getElementById("arq_state").className = "btn btn-sm btn-warning"; document.getElementById("startTransmission").disabled = false; break; - case 'False': - document.getElementById("arq_state").className = "btn btn-sm btn-secondary"; - document.getElementById("startTransmission").disabled = false; - break; default: document.getElementById("arq_state").className = "btn btn-sm btn-secondary"; document.getElementById("startTransmission").disabled = false; break; } - // ARQ SESSION - /* - if (arg.arq_session == 'True') { - document.getElementById("arq_session").className = "btn btn-sm btn-warning"; - } else if (arg.arq_session == 'False') { - document.getElementById("arq_session").className = "btn btn-sm btn-secondary"; + // ARQ SESSION + switch (arg.arq_session){ + case 'True': + document.getElementById("arq_session").className = "btn btn-sm btn-warning"; + break; + default: + document.getElementById("arq_session").className = "btn btn-sm btn-secondary"; + break; + } - } else { - document.getElementById("arq_session").className = "btn btn-sm btn-secondary"; - - } - */ - switch (arg.arq_session){ - case 'True': - document.getElementById("arq_session").className = "btn btn-sm btn-warning"; - break; - case 'False': - document.getElementById("arq_session").className = "btn btn-sm btn-secondary"; - break; - default: - document.getElementById("arq_session").className = "btn btn-sm btn-secondary"; - break; - } + if (arg.arq_state == 'True' || arg.arq_session == 'True') { + toggleClass("spnConnectedWith","text-success",true); + } else { + toggleClass("spnConnectedWith","text-success",false); + } // HAMLIB STATUS if (arg.hamlib_status == 'connected') { @@ -1902,45 +1954,28 @@ var speedChartOptions = { document.getElementById("rigctld_state").className = "btn btn-secondary btn-sm"; } + // BEACON + let bcn = document.getElementById("startBeacon"); - - // BEACON STATE - /* - if (arg.beacon_state == 'True') { - document.getElementById("startBeacon").className = "btn btn-sm btn-success spinner-grow"; - document.getElementById("startBeacon").disabled = true; - document.getElementById("beaconInterval").disabled = true; - document.getElementById("stopBeacon").disabled = false; - } else if (arg.beacon_state == 'False') { - document.getElementById("startBeacon").className = "btn btn-sm btn-success"; - document.getElementById("startBeacon").disabled = false; - document.getElementById("beaconInterval").disabled = false; - document.getElementById("stopBeacon").disabled = true; - } else { - document.getElementById("startBeacon").className = "btn btn-sm btn-success"; - document.getElementById("startBeacon").disabled = false; - document.getElementById("stopBeacon").disabled = true; - document.getElementById("beaconInterval").disabled = false; - } - */ switch (arg.beacon_state){ case 'True': - document.getElementById("startBeacon").className = "btn btn-sm btn-success spinner-grow"; - document.getElementById("startBeacon").disabled = true; + bcn.disabled = true; + if (config.high_graphics.toUpperCase() == "TRUE") { + bcn.className = "btn btn-sm btn-success spinner-grow force-gpu"; + document.getElementById("txtBeacon").setAttribute("class","input-group-text p-1"); + } else { + bcn.className = "btn btn-sm btn-success"; + document.getElementById("txtBeacon").setAttribute("class","input-group-text p-1 text-success text-uppercase"); + } document.getElementById("beaconInterval").disabled = true; document.getElementById("stopBeacon").disabled = false; break; - case 'False': - document.getElementById("startBeacon").className = "btn btn-sm btn-success"; - document.getElementById("startBeacon").disabled = false; - document.getElementById("beaconInterval").disabled = false; - document.getElementById("stopBeacon").disabled = true; - break; default: - document.getElementById("startBeacon").className = "btn btn-sm btn-success"; - document.getElementById("startBeacon").disabled = false; - document.getElementById("stopBeacon").disabled = true; + document.getElementById("txtBeacon").setAttribute("class","input-group-text p-1"); + bcn.className = "btn btn-sm btn-success"; document.getElementById("beaconInterval").disabled = false; + document.getElementById("stopBeacon").disabled = true; + bcn.disabled = false; break; } // dbfs @@ -1968,23 +2003,6 @@ var speedChartOptions = { document.getElementById("bandwidth").textContent = arg.bandwidth; // SET SPEED LEVEL - /* - if(arg.speed_level >= 0) { - document.getElementById("speed_level").className = "bi bi-reception-1"; - } - if(arg.speed_level >= 1) { - document.getElementById("speed_level").className = "bi bi-reception-2"; - } - if(arg.speed_level >= 2) { - document.getElementById("speed_level").className = "bi bi-reception-3"; - } - if(arg.speed_level >= 3) { - document.getElementById("speed_level").className = "bi bi-reception-4"; - } - if(arg.speed_level >= 4) { - document.getElementById("speed_level").className = "bi bi-reception-4"; - } - */ switch (arg.speed_level){ case '0': document.getElementById("speed_level").className = "bi bi-reception-1"; @@ -2000,8 +2018,6 @@ var speedChartOptions = { break; } - - // SET TOTAL BYTES if (typeof(arg.total_bytes) == 'undefined') { var total_bytes = 0; @@ -2040,13 +2056,10 @@ var speedChartOptions = { var myGrid = document.getElementById("myGrid").value; try { var dist = parseInt(distance(myGrid, dxGrid)) + ' km'; - //document.getElementById("pingDistance").innerHTML = dist; document.getElementById("dataModalPingDistance").textContent = dist; } catch { - //document.getElementById("pingDistance").innerHTML = '---'; document.getElementById("dataModalPingDistance").textContent = '---'; } - //document.getElementById("pingDB").innerHTML = arg.stations[i]['snr']; document.getElementById("dataModalPingDB").textContent = arg.stations[i]['snr']; } @@ -2090,7 +2103,11 @@ var speedChartOptions = { var gridDistanceText = document.createElement('span'); try { - gridDistanceText.innerText = parseInt(distance(document.getElementById("myGrid").value, arg.stations[i]['dxgrid'])) + ' km'; + if (arg.stations[i]['dxgrid'].toString() != "------") { + gridDistanceText.innerText = parseInt(distance(document.getElementById("myGrid").value, arg.stations[i]['dxgrid'])) + ' km'; + } else { + gridDistanceText.innerText = '---'; + } } catch { gridDistanceText.innerText = '---'; } @@ -2100,17 +2117,7 @@ var speedChartOptions = { var dataTypeText = document.createElement('span'); dataTypeText.innerText = arg.stations[i]['datatype']; dataType.appendChild(dataTypeText); - /* - if(arg.stations[i]['datatype'] == 'DATA-CHANNEL'){ - dataTypeText.innerText = 'DATA-C'; - dataType.appendChild(dataTypeText); - } - - if(arg.stations[i]['datatype'] == 'SESSION-HB'){ - dataTypeText.innerHTML = ''; - dataType.appendChild(dataTypeText); - } - */ + switch (arg.stations[i]['datatype']){ case 'DATA-CHANNEL': dataTypeText.innerText = 'DATA-C'; @@ -2121,28 +2128,7 @@ var speedChartOptions = { dataType.appendChild(dataTypeText); break; } - /* - if (dataTypeText.innerText == 'CQ CQ CQ') { - row.classList.add("table-success"); - } - if (dataTypeText.innerText == 'DATA-C') { - dataTypeText.innerHTML = ''; - row.classList.add("table-warning"); - } - - if (dataTypeText.innerText == 'BEACON') { - row.classList.add("table-light"); - } - - if (dataTypeText.innerText == 'PING') { - row.classList.add("table-info"); - } - - if (dataTypeText.innerText == 'PING-ACK') { - row.classList.add("table-primary"); - } - */ switch (dataTypeText.innerText){ case 'CQ CQ CQ': row.classList.add("table-success"); @@ -2512,7 +2498,6 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => { console.log(err); }); } - }); ipcRenderer.on('run-tnc-command', (event, arg) => { @@ -2954,12 +2939,26 @@ function set_CPU_mode() { toggleClass("transmission_progress","progress-bar-striped",true); } } -//Teomporarily disable a button with timeout +//Temporarily disable a button with timeout function pauseButton(btn, timems) { btn.disabled = true; var curText = btn.innerHTML; - btn.innerHTML = ""; + if (config.high_graphics.toUpperCase() == "TRUE") { + btn.innerHTML = ""; + } setTimeout(()=>{ btn.innerHTML=curText; btn.disabled = false;}, timems) +} +//https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript +function formatBytes(bytes, decimals = 1) { + if (!+bytes) return '0 Bytes' + + const k = 1024 + const dm = decimals < 0 ? 0 : decimals + const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` } \ No newline at end of file diff --git a/gui/sock.js b/gui/sock.js index 545ae9f6..f9c916f1 100644 --- a/gui/sock.js +++ b/gui/sock.js @@ -236,6 +236,8 @@ client.on('data', function(socketdata) { }; ipcRenderer.send('request-update-tnc-state', Data); + //continue to next for loop iteration, nothing else needs to be done here + continue; } @@ -346,6 +348,9 @@ client.on('data', function(socketdata) { } else if (data['status'] == 'waiting') { ipcRenderer.send('request-show-arq-toast-datachannel-waiting', {data: [data]}); + // ARQ RECEIVING + } else if (data['status'] == 'receiving') { + ipcRenderer.send('request-update-reception-status', {data: [data]}); // ARQ TRANSMISSION FAILED } else if (data['status'] == 'failed') { @@ -367,7 +372,8 @@ client.on('data', function(socketdata) { socketLog.info(data) // we need to encode here to do a deep check for checking if file or message - var encoded_data = atob(data['data']) + //var encoded_data = atob(data['data']) + var encoded_data = atob_FD(data['data']); var splitted_data = encoded_data.split(split_char) if(splitted_data[0] == 'f'){ @@ -420,7 +426,8 @@ client.on('data', function(socketdata) { for (i = 0; i < data['data-array'].length; i++) { try{ // we need to encode here to do a deep check for checking if file or message - var encoded_data = atob(data['data-array'][i]['data']) + //var encoded_data = atob(data['data-array'][i]['data']) + var encoded_data = atob_FD(data['data-array'][i]['data']); var splitted_data = encoded_data.split(split_char) @@ -516,8 +523,11 @@ exports.sendFile = function(dxcallsign, mode, frames, filename, filetype, data, data = datatype + split_char + filename + split_char + filetype + split_char + checksum + split_char + data socketLog.info(data) - socketLog.info(btoa(data)) - data = btoa(data) + //socketLog.info(btoa(data)) + //Btoa / atob will not work with charsets > 8 bits (i.e. the emojis); should probably move away from using it + //TODO: Will need to update anyother occurences and throughly test + //data = btoa(data) + data = btoa_FD(data); command = '{"type" : "arq", "command" : "send_raw", "parameter" : [{"dxcallsign" : "' + dxcallsign + '", "mode" : "' + mode + '", "n_frames" : "' + frames + '", "data" : "' + data + '"}]}' writeTncCommand(command) @@ -541,8 +551,8 @@ exports.sendMessage = function(dxcallsign, mode, frames, data, checksum, uuid, c console.log("CHECKSUM" + checksum) //socketLog.info(btoa(data)) - data = btoa(data) - + //data = btoa(data) + data = btoa_FD(data); //command = '{"type" : "arq", "command" : "send_message", "parameter" : [{ "dxcallsign" : "' + dxcallsign + '", "mode" : "' + mode + '", "n_frames" : "' + frames + '", "data" : "' + data + '" , "checksum" : "' + checksum + '"}]}' command = '{"type" : "arq", "command" : "send_raw", "uuid" : "'+ uuid +'", "parameter" : [{"dxcallsign" : "' + dxcallsign + '", "mode" : "' + mode + '", "n_frames" : "' + frames + '", "data" : "' + data + '", "attempts": "15"}]}' @@ -636,7 +646,23 @@ ipcRenderer.on('action-update-tnc-ip', (event, arg) => { }); - +/** +* String to base64 +* @param {string} data in normal/usual utf-8 format +* @returns base64 encoded string +*/ +function btoa_FD(data) { + return Buffer.from(data,'utf-8').toString('base64'); +} +/** +* base64 to string +* @param {string} data in base64 encoding +* @returns utf-8 normal/usual string +*/ +function atob_FD(data) +{ + return Buffer.from(data,'base64').toString('utf-8'); +} // https://stackoverflow.com/a/50579690 // crc32 calculation diff --git a/gui/src/index.html b/gui/src/index.html index 3b41caa6..fe81e7f5 100644 --- a/gui/src/index.html +++ b/gui/src/index.html @@ -21,32 +21,62 @@
@@ -71,196 +104,252 @@
-