Merge pull request #334 from DJ2LS/ls-gui

This commit is contained in:
DJ2LS 2023-01-28 09:18:16 +01:00 committed by GitHub
commit d4138da879
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 538 additions and 269 deletions

View file

@ -16,8 +16,10 @@ const mainLog = log.scope('main');
const daemonProcessLog = log.scope('freedata-daemon');
const mime = require('mime');
const net = require('net');
//Useful for debugging event emitter memory leaks
//require('events').EventEmitter.defaultMaxListeners = 10;
//process.traceProcessWarnings=true;
const sysInfo = log.scope('system information');
sysInfo.info("SYSTEM INFORMATION ----------------------------- ");
sysInfo.info("APP VERSION : " + app.getVersion());
@ -93,7 +95,8 @@ const configDefaultSettings = '{\
"respond_to_cq" : "True",\
"rx_buffer_size" : "16", \
"enable_explorer" : "False", \
"wftheme": 2 \
"wftheme": 2, \
"high_graphics" : "True"\
}';
if (!fs.existsSync(configPath)) {
@ -206,7 +209,7 @@ function createWindow() {
})
// hide menu bar
win.setMenuBarVisibility(false)
//open dev tools
/*win.webContents.openDevTools({
mode: 'undocked',
@ -316,111 +319,84 @@ app.whenReady().then(() => {
win.show();
}, 3000);
// start daemon by checking os
mainLog.info('Starting freedata-daemon binary');
if(os.platform()=='darwin'){
daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [],
{
cwd: path.join(process.resourcesPath, 'tnc'),
});
}
/*
process.resourcesPath -->
/tmp/.mount_FreeDAUQYfKb/resources
__dirname -->
/tmp/.mount_FreeDAUQYfKb/resources/app.asar
*/
if(os.platform()=='linux'){
/*
var folder = path.join(process.resourcesPath, 'tnc');
//var folder = path.join(__dirname, 'extraResources', 'tnc');
console.log(folder);
fs.readdir(folder, (err, files) => {
console.log(files);
});
*/
daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon'), [],
{
cwd: path.join(process.resourcesPath, 'tnc'),
});
//Generate daemon binary path
var daemonPath = "";
switch (os.platform().toLowerCase()){
case "darwin":
case "linux":
daemonPath = path.join(process.resourcesPath, 'tnc', 'freedata-daemon')
break;
case "win32":
case "win64":
daemonPath = path.join(process.resourcesPath, 'tnc', 'freedata-daemon.exe')
break;
default:
console.log("Unhandled OS Platform: ", os.platform());
break;
}
if(os.platform()=='win32' || os.platform()=='win64'){
// for windows the relative path via path.join(__dirname) is not needed for some reason
//daemonProcess = exec('\\tnc\\daemon.exe', [])
daemonProcess = spawn(path.join(process.resourcesPath, 'tnc', 'freedata-daemon.exe'), [],
{
cwd: path.join(process.resourcesPath, 'tnc'),
//Start daemon binary if it exists
if (fs.existsSync(daemonPath)){
mainLog.info('Starting freedata-daemon binary');
daemonProcess = spawn(daemonPath,[],
{
cwd: path.join(daemonPath,".."),
});
}
// return process messages
daemonProcess.on('error', (err) => {
daemonProcessLog.error(`error when starting daemon: ${err}`);
});
daemonProcess.on('message', (data) => {
daemonProcessLog.info(`${data}`);
});
daemonProcess.stdout.on('data', (data) => {
daemonProcessLog.info(`${data}`);
});
daemonProcess.stderr.on('data', (data) => {
daemonProcessLog.info(`${data}`);
// return process messages
daemonProcess.on('error', (err) => {
daemonProcessLog.error(`error when starting daemon: ${err}`);
});
daemonProcess.on('message', (data) => {
daemonProcessLog.info(`${data}`);
});
daemonProcess.stdout.on('data', (data) => {
daemonProcessLog.info(`${data}`);
});
daemonProcess.stderr.on('data', (data) => {
daemonProcessLog.info(`${data}`);
let arg = {
entry: `${data}`
};
// send info to log only if log screen available
// it seems an error occurs when updating
if (logViewer !== null && logViewer !== ''){
try{
logViewer.webContents.send('action-update-log', arg);
} catch (e) {
// empty for keeping error stuff silent
// this is important to avoid error messages if we are going to close the app while
// an logging information will be pushed to the logger
entry: `${data}`
};
// send info to log only if log screen available
// it seems an error occurs when updating
if (logViewer !== null && logViewer !== ''){
try{
logViewer.webContents.send('action-update-log', arg);
} catch (e) {
// empty for keeping error stuff silent
// this is important to avoid error messages if we are going to close the app while
// an logging information will be pushed to the logger
}
}
}
});
});
daemonProcess.on('close', (code) => {
daemonProcessLog.warn(`daemonProcess exited with code ${code}`);
});
} else {
daemonProcess=null;
daemonPath=null;
mainLog.info("Daemon binary doesn't exist--normal for dev environments.")
}
win.send("action-set-app-version",app.getVersion());
});
daemonProcess.on('close', (code) => {
daemonProcessLog.warn(`daemonProcess exited with code ${code}`);
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
})
app.on('window-all-closed', () => {
close_all();
})
// IPC HANDLER
//Show/update task bar/button progressbar
ipcMain.on('request-show-electron-progressbar',(event,data)=>{
win.setProgressBar(data/100);
});
ipcMain.on('request-show-chat-window', () => {
chat.show();
@ -488,6 +464,7 @@ ipcMain.on('request-new-msg-received', (event, arg) => {
});
ipcMain.on('request-update-transmission-status', (event, arg) => {
chat.webContents.send('action-update-transmission-status', arg);
win.webContents.send('action-update-transmission-status',arg);
});
ipcMain.on('request-open-tnc-log', () => {
@ -655,6 +632,11 @@ ipcMain.on('request-show-arq-toast-transmission-failed',(event,data)=>{
win.webContents.send('action-show-arq-toast-transmission-failed', data);
});
// ARQ TRANSMISSION FAILED
ipcMain.on('request-show-arq-toast-transmission-failed-ver',(event,data)=>{
win.webContents.send('action-show-arq-toast-transmission-failed-ver', data);
});
// ARQ TRANSMISSION RECEIVING
ipcMain.on('request-show-arq-toast-transmission-receiving',(event,data)=>{
win.webContents.send('action-show-arq-toast-transmission-receiving', data);
@ -782,7 +764,9 @@ function close_sub_processes(){
// closing the tnc binary if not closed when closing application and also our daemon which has been started by the gui
try {
daemonProcess.kill();
if (daemonProcess != null) {
daemonProcess.kill();
}
} catch (e) {
mainLog.error(e)
}
@ -894,6 +878,8 @@ ipcMain.on('request-stop-rigctld',(event,data)=>{
// create new socket so we are not reopening every time a new one
var rigctld_connection = new net.Socket();
var rigctld_connection_state = false;
var rigctld_events_wired = false;
ipcMain.on('request-check-rigctld',(event, data)=>{
try{
@ -904,41 +890,44 @@ ipcMain.on('request-check-rigctld',(event, data)=>{
if(!rigctld_connection_state){
rigctld_connection = new net.Socket();
rigctld_events_wired = false;
rigctld_connection.connect(data.port, data.ip)
}
// check if we have created a new socket object
if (typeof(rigctld_connection) != 'undefined') {
rigctld_connection.on('connect', function() {
rigctld_connection_state = true;
Data["state"] = "connection possible - (" + data.ip + ":" + data.port + ")";
if (win !== null && win !== '' && typeof(win) != 'undefined'){
// try catch for being sure we have a clean app close
try{
win.webContents.send('action-check-rigctld', Data);
} catch(e){
console.log(e)
// Check if we have created a new socket object and attach listeners if not already created
if (typeof(rigctld_connection) != 'undefined' && !rigctld_events_wired) {
rigctld_connection.on('connect', function() {
rigctld_events_wired=true;
mainLog.info("Starting rigctld event listeners");
rigctld_connection_state = true;
Data["state"] = "connection possible - (" + data.ip + ":" + data.port + ")";
if (win !== null && win !== '' && typeof(win) != 'undefined'){
// try catch for being sure we have a clean app close
try{
win.webContents.send('action-check-rigctld', Data);
} catch(e){
console.log(e)
}
}
}
})
rigctld_connection.on('error', function() {
rigctld_connection_state = false;
Data["state"] = "unknown/stopped - (" + data.ip + ":" + data.port + ")";
if (win !== null && win !== '' && typeof(win) != 'undefined'){
// try catch for being sure we have a clean app close
try{
win.webContents.send('action-check-rigctld', Data);
} catch(e){
console.log(e)
})
rigctld_connection.on('error', function() {
rigctld_connection_state = false;
Data["state"] = "unknown/stopped - (" + data.ip + ":" + data.port + ")";
if (win !== null && win !== '' && typeof(win) != 'undefined'){
// try catch for being sure we have a clean app close
try{
win.webContents.send('action-check-rigctld', Data);
} catch(e){
console.log(e)
}
}
}
})
rigctld_connection.on('end', function() {
rigctld_connection_state = false;
})
})
rigctld_connection.on('end', function() {
rigctld_connection_state = false;
})
}
@ -946,4 +935,4 @@ ipcMain.on('request-check-rigctld',(event, data)=>{
console.log(e)
}
});
});

View file

@ -8,8 +8,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"engines": {
"node": ">=14.0.0",
"npm": ">=6.0.0"
"node": ">=16.0.0",
"npm": ">=9.0.0"
},
"repository": {
"type": "git",
@ -32,30 +32,30 @@
"@electron/osx-sign": "^1.0.4",
"@popperjs/core": "^2.11.6",
"blob-util": "^2.0.2",
"bootstrap": "^5.2.1",
"bootstrap-icons": "^1.9.1",
"bootswatch": "^5.2.0",
"chart.js": "^4.0.0",
"bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.3",
"bootswatch": "^5.2.3",
"chart.js": "^4.2.0",
"chartjs-plugin-annotation": "^2.1.2",
"electron-log": "^4.4.8",
"electron-updater": "^5.2.1",
"emoji-picker-element": "^1.12.1",
"electron-updater": "^5.3.0",
"emoji-picker-element": "^1.15.0",
"emoji-picker-element-data": "^1.3.0",
"express-pouchdb": "^4.2.0",
"mime": "^3.0.0",
"pouchdb": "^7.3.0",
"pouchdb-browser": "^7.3.0",
"pouchdb": "^8.0.0",
"pouchdb-browser": "^8.0.0",
"pouchdb-express-router": "^0.0.11",
"pouchdb-find": "^7.3.0",
"pouchdb-find": "^8.0.0",
"pouchdb-replication": "^8.0.0",
"qth-locator": "^2.1.0",
"utf8": "^3.0.0",
"uuid": "^9.0.0"
},
"devDependencies": {
"electron": "^22.0.2",
"electron-builder": "^23.6.0",
"@electron/notarize": "^1.2.3",
"electron": "^20.1.3",
"electron-builder": "^23.3.3",
"electron-builder-notarize": "^1.5.0"
},
"build": {

View file

@ -28,7 +28,8 @@ const config = require(configPath);
// we are going to check if we have unequal values before we start calculating again
var dbfs_level_raw = 0
//Global version variable
var appVer = null;
// START INTERVALL COMMAND EXECUTION FOR STATES
//setInterval(sock.getRxBuffer, 1000);
@ -169,7 +170,8 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
ssid = callsign_and_ssid[1];
document.getElementById("myCall").value = callsign;
document.title = document.title + ' - Call: ' + config.mycall;
//document.title = document.title + ' - Call: ' + config.mycall;
updateTitle();
document.getElementById("myCallSSID").value = ssid;
document.getElementById("myGrid").value = config.mygrid;
@ -238,7 +240,13 @@ document.getElementById('openReceivedFilesFolder').addEventListener('click', ()
} else {
document.getElementById("500HzModeSwitch").checked = false;
}
if(config.high_graphics == 'True'){
document.getElementById("GraphicsSwitch").checked = true;
} else {
document.getElementById("GraphicsSwitch").checked = false;
}
if(config.enable_fsk == 'True'){
document.getElementById("fskModeSwitch").checked = true;
} else {
@ -963,9 +971,9 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
callsign_ssid = callsign.toUpperCase() + '-' + ssid;
config.mycall = callsign_ssid;
// split document title by looking for Call then split and update it
var documentTitle = document.title.split('Call:')
document.title = documentTitle[0] + 'Call: ' + callsign_ssid;
//var documentTitle = document.title.split('Call:')
//document.title = documentTitle[0] + 'Call: ' + callsign_ssid;
updateTitle(callsign_ssid);
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
daemon.saveMyCall(callsign_ssid);
});
@ -982,8 +990,10 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
// startPing button clicked
document.getElementById("sendPing").addEventListener("click", () => {
var dxcallsign = document.getElementById("dxCall").value;
dxcallsign = dxcallsign.toUpperCase();
var dxcallsign = document.getElementById("dxCall").value.toUpperCase();
if (dxcallsign == "" || dxcallsign == null || dxcallsign == undefined)
return;
pauseButton(document.getElementById("sendPing"),2000);
sock.sendPing(dxcallsign);
});
@ -1018,6 +1028,7 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
// sendCQ button clicked
document.getElementById("sendCQ").addEventListener("click", () => {
pauseButton(document.getElementById("sendCQ"),2000);
sock.sendCQ();
});
@ -1080,6 +1091,15 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
}
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
});
document.getElementById("GraphicsSwitch").addEventListener("click", () => {
if(document.getElementById("GraphicsSwitch").checked == true){
config.high_graphics = "True";
} else {
config.high_graphics = "False";
}
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
set_CPU_mode();
});
// enable fsk Switch clicked
document.getElementById("fskModeSwitch").addEventListener("click", () => {
@ -1133,11 +1153,11 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
});
// Update channel selector clicked
document.getElementById("update_channel_selector").addEventListener("click", () => {
// Update channel selector changed
document.getElementById("update_channel_selector").addEventListener("change", () => {
config.update_channel = document.getElementById("update_channel_selector").value;
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
console.log("Autoupdate channel changed to ", config.update_channel);
});
// rx buffer size selector clicked
@ -1312,7 +1332,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);
})
@ -1474,21 +1494,65 @@ document.getElementById('hamlib_rigctld_stop').addEventListener('click', () => {
})
//Listen for events caused by tnc 'tnc-message's
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 = 0;
} 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;
}
var time_left = "time left: ~ "+ minutes + "min" + " " + seconds + "s";
}
document.getElementById("transmission_timeleft").textContent = time_left;
// SET BYTES PER MINUTE
if (typeof(data.bytesperminute) == 'undefined') {
var arq_bytes_per_minute = 0;
} 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;
if (isNaN(compress)) {
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;
});
var slowRollTable=4;
ipcRenderer.on('action-update-tnc-state', (event, arg) => {
// update FFT
if (typeof(arg.fft) !== 'undefined') {
var array = JSON.parse("[" + arg.fft + "]");
spectrum.addData(array[0]);
}
if (typeof(arg.mycallsign) !== 'undefined') {
// split document title by looking for Call then split and update it
var documentTitle = document.title.split('Call:')
document.title = documentTitle[0] + 'Call: ' + arg.mycallsign;
updateTitle(arg.mycallsign);
}
// update mygrid information with data from tnc
@ -1572,7 +1636,7 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
var scatterSize = arg.scatter.length;
}
if (global.scatterData != newScatterData && scatterSize > 0) {
if (scatterSize > 0 && global.scatterData != newScatterData) {
global.scatterData = newScatterData;
if (typeof(global.scatterChart) == 'undefined') {
@ -1688,6 +1752,7 @@ var speedChartOptions = {
// 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') {
@ -1695,24 +1760,33 @@ var speedChartOptions = {
} 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";
break;
case 'False':
document.getElementById("ptt_state").className = "btn btn-sm btn-success";
break;
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").innerHTML = "Stop Rec"
document.getElementById("startStopRecording").textContent = "Stop Rec"
} else if (arg.ptt_state == 'False') {
document.getElementById("startStopRecording").className = "btn btn-sm btn-danger";
document.getElementById("startStopRecording").innerHTML = "Start Rec"
document.getElementById("startStopRecording").textContent = "Start Rec"
} else {
document.getElementById("startStopRecording").className = "btn btn-sm btn-danger";
document.getElementById("startStopRecording").innerHTML = "Start Rec"
document.getElementById("startStopRecording").textContent = "Start Rec"
}
// CHANNEL BUSY STATE
/*
if (arg.channel_busy == 'True') {
document.getElementById("channel_busy").className = "btn btn-sm btn-danger";
@ -1723,24 +1797,49 @@ var speedChartOptions = {
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";
break;
case 'False':
document.getElementById("channel_busy").className = "btn btn-sm btn-success";
break;
default:
document.getElementById("channel_busy").className = "btn btn-sm btn-secondary";
break;
}
// 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";
document.getElementById("startTransmission").disabled = true;
break;
case 'IDLE':
document.getElementById("busy_state").className = "btn btn-sm btn-success";
break;
default:
document.getElementById("busy_state").className = "btn btn-sm btn-secondary";
document.getElementById("startTransmission").disabled = true;
break;
}
// ARQ STATE
/*
if (arg.arq_state == 'True') {
document.getElementById("arq_state").className = "btn btn-sm btn-warning";
//document.getElementById("startTransmission").disabled = true;
@ -1756,8 +1855,23 @@ var speedChartOptions = {
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";
@ -1768,11 +1882,22 @@ var speedChartOptions = {
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;
}
// HAMLIB STATUS
if (arg.hamlib_status == 'connected') {
document.getElementById("rigctld_state").className = "btn btn-success btn-sm";
} else {
document.getElementById("rigctld_state").className = "btn btn-secondary btn-sm";
}
@ -1780,6 +1905,7 @@ var speedChartOptions = {
// BEACON STATE
/*
if (arg.beacon_state == 'True') {
document.getElementById("startBeacon").className = "btn btn-sm btn-success spinner-grow";
document.getElementById("startBeacon").disabled = true;
@ -1796,71 +1922,53 @@ var speedChartOptions = {
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;
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("beaconInterval").disabled = false;
break;
}
// dbfs
// https://www.moellerstudios.org/converting-amplitude-representations/
if (dbfs_level_raw != arg.dbfs_level){
dbfs_level_raw = arg.dbfs_level
dbfs_level = Math.pow(10, arg.dbfs_level / 20) * 100
document.getElementById("dbfs_level_value").innerHTML = Math.round(arg.dbfs_level) + ' dBFS'
document.getElementById("dbfs_level").setAttribute("aria-valuenow", dbfs_level);
document.getElementById("dbfs_level").setAttribute("style", "width:" + dbfs_level + "%;");
document.getElementById("dbfs_level_value").textContent = Math.round(arg.dbfs_level) + ' dBFS'
var dbfscntrl = document.getElementById("dbfs_level");
dbfscntrl.setAttribute("aria-valuenow", dbfs_level);
dbfscntrl.setAttribute("style", "width:" + dbfs_level + "%;");
}
// SET FREQUENCY
// https://stackoverflow.com/a/2901298
var freq = arg.frequency.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
document.getElementById("frequency").innerHTML = freq;
document.getElementById("frequency").textContent = freq;
//document.getElementById("newFrequency").value = arg.frequency;
// SET MODE
document.getElementById("mode").innerHTML = arg.mode;
document.getElementById("mode").textContent = arg.mode;
// SET bandwidth
document.getElementById("bandwidth").innerHTML = arg.bandwidth;
document.getElementById("bandwidth").textContent = arg.bandwidth;
// SET BYTES PER MINUTE
if (typeof(arg.arq_bytes_per_minute) == 'undefined') {
var arq_bytes_per_minute = 0;
} else {
var arq_bytes_per_minute = arg.arq_bytes_per_minute;
}
document.getElementById("bytes_per_min").innerHTML = arq_bytes_per_minute;
// SET BYTES PER MINUTE COMPRESSED
if (typeof(arg.arq_bytes_per_minute) == 'undefined') {
var arq_bytes_per_minute_compressed = 0;
} else {
var arq_bytes_per_minute_compressed = Math.round(arg.arq_bytes_per_minute * arg.arq_compression_factor);
}
document.getElementById("bytes_per_min_compressed").innerHTML = arq_bytes_per_minute_compressed;
// SET TIME LEFT UNTIL FINIHED
if (typeof(arg.arq_seconds_until_finish) == 'undefined') {
var time_left = 0;
} else {
var arq_seconds_until_finish = arg.arq_seconds_until_finish
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;
}
var time_left = "time left: ~ "+ minutes + "min" + " " + seconds + "s";
}
document.getElementById("transmission_timeleft").innerHTML = time_left;
// SET SPEED LEVEL
/*
if(arg.speed_level >= 0) {
document.getElementById("speed_level").className = "bi bi-reception-1";
}
@ -1876,7 +1984,21 @@ var speedChartOptions = {
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";
break;
case '1':
document.getElementById("speed_level").className = "bi bi-reception-2";
break;
case '2':
document.getElementById("speed_level").className = "bi bi-reception-3";
break;
default:
document.getElementById("speed_level").className = "bi bi-reception-4";
break;
}
@ -1886,10 +2008,20 @@ var speedChartOptions = {
} else {
var total_bytes = arg.total_bytes;
}
document.getElementById("total_bytes").innerHTML = total_bytes;
document.getElementById("transmission_progress").setAttribute("aria-valuenow", arg.arq_transmission_percent);
document.getElementById("transmission_progress").setAttribute("style", "width:" + arg.arq_transmission_percent + "%;");
document.getElementById("total_bytes").textContent = total_bytes;
//Ensure heard station table is last so we can return if we don't want to update it
//Only update heard stations every 5 iterations
//Allows for single click event to work more reliabily to populate dxcall textbox
//Should also save some CPU
slowRollTable++;
if (slowRollTable!=5) {
return;
}
slowRollTable=0;
// UPDATE HEARD STATIONS
var tbl = document.getElementById("heardstations");
document.getElementById("heardstations").innerHTML = '';
@ -1903,19 +2035,19 @@ var speedChartOptions = {
for (i = 0; i < heardStationsLength; i++) {
// first we update the PING window
if (arg.stations[i]['dxcallsign'] == document.getElementById("dxCall").value) {
if (arg.stations[i]['dxcallsign'] == document.getElementById("dxCall").value.toUpperCase()) {
var dxGrid = arg.stations[i]['dxgrid'];
var myGrid = document.getElementById("myGrid").value;
try {
var dist = parseInt(distance(myGrid, dxGrid)) + ' km';
document.getElementById("pingDistance").innerHTML = dist;
document.getElementById("dataModalPingDistance").innerHTML = dist;
//document.getElementById("pingDistance").innerHTML = dist;
document.getElementById("dataModalPingDistance").textContent = dist;
} catch {
document.getElementById("pingDistance").innerHTML = '---';
document.getElementById("dataModalPingDistance").innerHTML = '---';
//document.getElementById("pingDistance").innerHTML = '---';
document.getElementById("dataModalPingDistance").textContent = '---';
}
document.getElementById("pingDB").innerHTML = arg.stations[i]['snr'];
document.getElementById("dataModalPingDB").innerHTML = arg.stations[i]['snr'];
//document.getElementById("pingDB").innerHTML = arg.stations[i]['snr'];
document.getElementById("dataModalPingDB").textContent = arg.stations[i]['snr'];
}
// now we update the heard stations list
@ -1940,10 +2072,13 @@ var speedChartOptions = {
frequencyText.innerText = arg.stations[i]['frequency'];
frequency.appendChild(frequencyText);
var dxCall = document.createElement("td");
var dxCallText = document.createElement('span');
dxCallText.innerText = arg.stations[i]['dxcallsign'];
let dxCallTextCall = dxCallText.innerText;
row.addEventListener("click", function() {
document.getElementById("dxCall").value = dxCallTextCall;
});
dxCall.appendChild(dxCallText);
var dxGrid = document.createElement("td");
@ -1965,7 +2100,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);
@ -1975,11 +2110,20 @@ var speedChartOptions = {
dataTypeText.innerHTML = '<i class="bi bi-heart-pulse-fill"></i>';
dataType.appendChild(dataTypeText);
}
*/
switch (arg.stations[i]['datatype']){
case 'DATA-CHANNEL':
dataTypeText.innerText = 'DATA-C';
dataType.appendChild(dataTypeText);
break;
case 'SESSION-HB':
dataTypeText.innerHTML = '<i class="bi bi-heart-pulse-fill"></i>';
dataType.appendChild(dataTypeText);
break;
}
/*
if (dataTypeText.innerText == 'CQ CQ CQ') {
row.classList.add("table-success");
}
if (dataTypeText.innerText == 'DATA-C') {
@ -1998,7 +2142,25 @@ var speedChartOptions = {
if (dataTypeText.innerText == 'PING-ACK') {
row.classList.add("table-primary");
}
*/
switch (dataTypeText.innerText){
case 'CQ CQ CQ':
row.classList.add("table-success");
break;
case 'DATA-C':
dataTypeText.innerHTML = '<i class="bi bi-file-earmark-binary-fill"></i>';
row.classList.add("table-warning");
break;
case 'BEACON':
row.classList.add("table-light");
break;
case 'PING':
row.classList.add("table-info");
break;
case 'PING-ACK':
row.classList.add("table-primary");
break;
}
var snr = document.createElement("td");
var snrText = document.createElement('span');
snrText.innerText = arg.stations[i]['snr'];
@ -2204,7 +2366,11 @@ ipcRenderer.on('action-update-tnc-connection', (event, arg) => {
var collapseThirdRow = new bootstrap.Collapse(document.getElementById('collapseThirdRow'), {toggle: false})
collapseThirdRow.show();
var collapseFourthRow = new bootstrap.Collapse(document.getElementById('collapseFourthRow'), {toggle: false})
collapseFourthRow.show();
collapseFourthRow.show();
//Set tuning for fancy graphics mode (high/low CPU)
set_CPU_mode();
} else {
/*
document.getElementById('hamlib_deviceid').disabled = false;
@ -2249,15 +2415,15 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
for (i = 0; i < arg.data.length; i++) {
// first we update the PING window
if (arg.data[i]['dxcallsign'] == document.getElementById("dxCall").value) {
if (arg.data[i]['dxcallsign'] == document.getElementById("dxCall").value.toUpperCase()) {
/*
// if we are sending data without doing a ping before, we don't have a grid locator available. This could be a future feature for the TNC!
if(arg.data[i]['DXGRID'] != ''){
document.getElementById("pingDistance").innerHTML = arg.stations[i]['DXGRID']
}
*/
document.getElementById("pingDB").innerHTML = arg.stations[i]['snr'];
//document.getElementById("pingDB").innerHTML = arg.stations[i]['snr'];
document.getElementById("dataModalPingDB").innerHTML = arg.stations[i]['snr'];
}
@ -2413,14 +2579,11 @@ ipcRenderer.on('action-updater', (event, arg) => {
}
if (arg.status == "checking-for-update"){
document.title = document.title + ' - v' + arg.version;
//document.title = document.title + ' - v' + arg.version;
updateTitle(config.myCall,config.tnc_host,config.tnc_port, " -v " + arg.version);
document.getElementById("updater_status").innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>'
document.getElementById("updater_status").className = "btn btn-secondary btn-sm";
document.getElementById("update_and_install").style.display = 'none';
}
@ -2562,6 +2725,13 @@ ipcRenderer.on('action-show-arq-toast-transmission-failed', (event, data) => {
toast.show();
});
// ARQ TRANSMISSION FAILED (Version mismatch)
ipcRenderer.on('action-show-arq-toast-transmission-failed-ver', (event, data) => {
document.getElementById("transmission_progress").className = "progress-bar progress-bar-striped bg-danger";
var toast = bootstrap.Toast.getOrCreateInstance(toastARQtransmittingfailedver); // Returns a Bootstrap toast instance
toast.show();
});
// ARQ TRANSMISSION STOPPED
// TODO: RENAME ID -- WRONG
ipcRenderer.on('action-show-arq-toast-transmission-stopped', (event, data) => {
@ -2691,11 +2861,6 @@ ipcRenderer.on('action-show-arq-toast-session-failed', (event, data) => {
});
// enable or disable a setting by given switch and element
function enable_setting(enable_switch, enable_object){
if(document.getElementById(enable_switch).checked){
@ -2724,9 +2889,77 @@ function checkRigctld(){
ip: rigctld_ip,
port: rigctld_port
};
ipcRenderer.send('request-check-rigctld', Data);
//Prevents an error on startup if hamlib settings aren't populated yet
if (rigctld_port.length > 0 && rigctld_ip.length > 0) {
ipcRenderer.send('request-check-rigctld', Data);
}
}
ipcRenderer.on('action-check-rigctld', (event, data) => {
document.getElementById("hamlib_rigctld_status").value = data["state"];
});
ipcRenderer.on('action-set-app-version', (event, data) => {
appVer = data;
});
function updateTitle(mycall = config.mycall , tnc = config.tnc_host, tncport = config.tnc_port, appender = ""){
//Multiple consecutive spaces get converted to a single space
var title ="FreeDATA " + appVer + " - Call: " + mycall + " - TNC: " + tnc + ":" + tncport + appender;
if (title != document.title) {
document.title=title;
}
}
//Set force to true to ensure a class is present on a control, other set to false to ensure it isn't present
function toggleClass(control,classToToggle,force) {
var cntrl = document.getElementById(control);
if (cntrl == undefined) {
//console.log("toggle class: unknown control", control);
return;
}
var activeClasses = cntrl.getAttribute('class');
//var oldactive = activeClasses;
if (force == true && activeClasses.indexOf(classToToggle) >= 0) {
return;
}
if (force == false && activeClasses.indexOf(classToToggle) == -1) {
return;
}
if (force == true) {
activeClasses += " " + classToToggle;
} else {
activeClasses = activeClasses.replace(classToToggle,"");
}
activeClasses = activeClasses.replace(" "," ").trim();
cntrl.setAttribute("class",activeClasses);
//console.log(control," toggleClass; force: ", force, "class: " ,classToToggle, " in: '" ,oldactive, "' out: '",activeClasses,"'");
}
function set_CPU_mode() {
if (config.high_graphics.toUpperCase()=="FALSE")
{
toggleClass("dbfs_level","disable-effects",true);
toggleClass("dbfs_level","progress-bar-striped",false);
toggleClass("waterfall","disable-effects",true);
toggleClass("transmission_progress","disable-effects",true);
toggleClass("transmission_progress","progress-bar-striped",false);
}
else
{
toggleClass("dbfs_level","disable-effects",false);
toggleClass("dbfs_level","progress-bar-striped",true);
toggleClass("waterfall","disable-effects",false);
toggleClass("transmission_progress","disable-effects",false);
toggleClass("transmission_progress","progress-bar-striped",true);
}
}
//Teomporarily disable a button with timeout
function pauseButton(btn, timems) {
btn.disabled = true;
var curText = btn.innerHTML;
btn.innerHTML = "<span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\">";
setTimeout(()=>{
btn.innerHTML=curText;
btn.disabled = false;}, timems)
}

View file

@ -156,8 +156,8 @@ client.on('data', function(socketdata) {
// split data into chunks if we received multiple commands
socketchunk = socketchunk.split("\n");
data = JSON.parse(socketchunk[0])
//don't think this is needed anymore
//data = JSON.parse(socketchunk[0])
// search for empty entries in socketchunk and remove them
for (i = 0; i < socketchunk.length; i++) {
@ -349,7 +349,11 @@ client.on('data', function(socketdata) {
// ARQ TRANSMISSION FAILED
} else if (data['status'] == 'failed') {
ipcRenderer.send('request-show-arq-toast-transmission-failed', {data: [data]});
if (data['reason'] == 'protocol version missmatch') {
ipcRenderer.send('request-show-arq-toast-transmission-failed-ver', {data: [data]});
} else {
ipcRenderer.send('request-show-arq-toast-transmission-failed', {data: [data]});
}
ipcRenderer.send('request-update-transmission-status', {data: [data]});

View file

@ -18,8 +18,8 @@
<!-- bootstrap -->
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<!-- chart.js -->
<script src="../node_modules/chart.js/dist/chart.min.js"></script>
<script src="../node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
<script src="../node_modules/chart.js/dist/chart.umd.js"></script>
<!--<script src="../node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>-->
<!--<script type="module" src="../node_modules/emoji-picker-element/index.js"></script>-->
<script type="module" src="../node_modules/emoji-picker-element/picker.js"></script>
<script type="module" src="../node_modules/emoji-picker-element/database.js"></script>

View file

@ -28,7 +28,7 @@
<label class="btn btn-sm btn-outline-secondary" for="local-remote-switch2"> <i class="bi bi-ethernet" style="font-size: 1rem; color: black;"></i> </label>
</div>
<div class="input-group input-group-sm me-2" id="remote-tnc-field"> <span class="input-group-text" id="basic-addon1">TNC IP</span>
<input type="text" class="form-control" placeholder="ip adress" id="tnc_adress" value="192.168.178.163" maxlength="17" style="width: 8rem" aria-label="Username" aria-describedby="basic-addon1"> <span class="input-group-text" id="basic-addon1">:</span>
<input type="text" class="form-control" placeholder="ip address" id="tnc_adress" value="192.168.178.163" maxlength="17" style="width: 8rem" aria-label="Username" aria-describedby="basic-addon1"> <span class="input-group-text" id="basic-addon1">:</span>
<input type="text" class="form-control" placeholder="port" value="3000" id="tnc_port" maxlength="5" max="65534" min="1025" style="width: 4rem" aria-label="Username" aria-describedby="basic-addon1">
<button class="btn btn-sm btn-danger" id="daemon_connection_state" type="button" disabled> <i class="bi bi-diagram-3" style="font-size: 1rem; color: white;"></i> </button>
</div>
@ -214,6 +214,13 @@
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
<!-- ARQ TRANSMITTING FAILED -->
<div class="toast align-items-center text-white bg-danger border-0" id="toastARQtransmittingfailedver" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">TRANSMITTING FAILED, VERSION MISMATCH!</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
<!-- ARQ TRANSMITTING SUCCESS-->
<div class="toast align-items-center text-white bg-success border-0" id="toastARQtransmittingsuccess" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
@ -774,7 +781,7 @@
</div>
<div class="card-body p-2">
<div class="progress mb-0" style="height: 15px;">
<div class="progress-bar progress-bar-striped bg-primary" id="dbfs_level" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar progress-bar-striped bg-primary force-gpu" id="dbfs_level" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<p class="justify-content-center d-flex position-absolute w-100" id="dbfs_level_value">dBFS</p>
</div>
<div class="progress mb-0" style="height: 5px;">
@ -848,9 +855,9 @@
</div>
<div class="card-body p-1" style="height: 200px">
<!--278px-->
<canvas id="waterfall" style="position: relative; z-index: 2; transform: translateZ(0);"></canvas>
<canvas id="scatter" style="position: relative; z-index: 1; transform: translateZ(0);"></canvas>
<canvas id="chart" style="position: relative; z-index: 1; transform: translateZ(0);"></canvas>
<canvas id="waterfall" style="position: relative; z-index: 2;" class="force-gpu"></canvas>
<canvas id="scatter" style="position: relative; z-index: 1;" class="force-gpu"></canvas>
<canvas id="chart" style="position: relative; z-index: 1;" class="force-gpu"></canvas>
</div>
</div>
</div>
@ -1117,7 +1124,7 @@
</div>
<div class="container-fluid p-0" style="width:15rem">
<div class="progress" style="height: 30px;">
<div class="progress-bar progress-bar-striped bg-primary" id="transmission_progress" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar progress-bar-striped bg-primary force-gpu" id="transmission_progress" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<!--<p class="justify-content-center d-flex position-absolute w-100">PROGRESS</p>-->
<p class="justify-content-center mt-2 d-flex position-absolute w-100" id="transmission_timeleft">---</p>
</div>
@ -1129,7 +1136,6 @@
<!-- chart.js -->
<script src="../node_modules/chart.js/dist/chart.umd.js"></script>
<!--<script src="../node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>-->
<!--<script src="../ui.js"></script>-->
<!-- WATERFALL -->
<script src="waterfall/colormap.js"></script>
<script src="waterfall/spectrum.js"></script>
@ -1162,6 +1168,11 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="alert alert-warning" role="alert">
Most settings need a tnc restart to take effect!
</div>
<div class="input-group input-group-sm mb-1"> <span class="input-group-text w-50" id="basic-addon1">Theme</span>
<select class="form-select form-select-sm w-50" id="theme_selector">
<option value="default">Default</option>
@ -1304,6 +1315,15 @@
</select>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable Fancy GUI</label>
<label class="input-group-text bg-white w-50">
<div class="form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" id="GraphicsSwitch">
<label class="form-check-label" for="GraphicsSwitch">Higher CPU Usage</label>
</div>
</label>
</div>
</div>
</div>
</div>

View file

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="script-src 'self';">
</head>
<body>
<body style="overflow:hidden;">
<img src="img/icon_cube_border.png" width="100%" height="100%">
</body>
</html>

View file

@ -3,6 +3,7 @@ body {
padding-right: 0px !important;
overflow-y: hidden !important;
overflow-x: hidden !important;
}
/*Progress bars with centered text*/
@ -65,4 +66,26 @@ th {
.picker {
border-radius: 10px:
}
}
/* force gpu usage
https://stackoverflow.com/questions/13176746/css-keyframe-animation-cpu-usage-is-high-should-it-be-this-way/13293044#13293044
*/
.force-gpu {
transform: translateZ(0);
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
will-change: transform;
}
/* force disable transition effects
https://stackoverflow.com/a/9622873
*/
.disable-effects {
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
}

View file

@ -1060,6 +1060,12 @@ class DATA:
static.TOTAL_BYTES = len(data_out)
frame_total_size = len(data_out).to_bytes(4, byteorder="big")
# Compress data frame
data_frame_compressed = lzma.compress(data_out)
compression_factor = len(data_out) / len(data_frame_compressed)
static.ARQ_COMPRESSION_FACTOR = np.clip(compression_factor, 0, 255)
compression_factor = bytes([int(static.ARQ_COMPRESSION_FACTOR * 10)])
self.send_data_to_socket_queue(
freedata="tnc-message",
arq="transmission",
@ -1078,12 +1084,6 @@ class DATA:
Bytes=static.TOTAL_BYTES,
)
# Compress data frame
data_frame_compressed = lzma.compress(data_out)
compression_factor = len(data_out) / len(data_frame_compressed)
static.ARQ_COMPRESSION_FACTOR = np.clip(compression_factor, 0, 255)
compression_factor = bytes([int(static.ARQ_COMPRESSION_FACTOR * 10)])
data_out = data_frame_compressed
# Reset data transfer statistics