Skip to content

Commit b7bf1d1

Browse files
authored
Merge pull request #94 from wavelog/dev
Collector for v.1.1.12
2 parents cc6283e + 23a50b2 commit b7bf1d1

File tree

4 files changed

+283
-20
lines changed

4 files changed

+283
-20
lines changed

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ A modern Electron-based gateway application that connects WSJT-X, FLRig, Hamlib,
77
- For logging QSOs from WSJT-X, you need to configure the so called "Secondary UDP Server" like shown in the picture:
88
<img width="788" height="312" alt="image" src="https://github.com/user-attachments/assets/a4d005d0-8546-4ae3-99e8-89a195df9e0e" />
99

10+
# Alternatives
11+
If you want to use a lean headless-Version for CAT or QSO-Transportation, which runs on 32bit-Systems as well, try our partner-projects (no suppert for it - experimentat):
12+
- CAT: [WaveLogGoat](https://github.com/johnsonm/WaveLogGoat)
13+
- QSO-Transport: [WaveLogStoat](https://github.com/int2001/WaveLogStoat)
1014

1115
## Features
1216

@@ -98,6 +102,61 @@ WaveLogGate supports two complete configuration profiles:
98102
### FLDigi Setup
99103
Configure FLDigi to send ADIF logs via UDP to port 2333.
100104

105+
### Hamlib Setup
106+
107+
#### Quickstart - e.g. - for Icom IC-7300
108+
In general have a look at the [pages/wiki](https://github.com/Hamlib/Hamlib) for hamlib / rigctld
109+
As an example for Icom transceivers like the IC-7300, you can use `rigctld` (Hamlib daemon) to provide CAT control:
110+
111+
1. **Install Hamlib** (if not already installed):
112+
```bash
113+
# Ubuntu/Debian
114+
sudo apt-get install hamlib-utils
115+
# macOS
116+
brew install hamlib
117+
# Windows
118+
# Download from https://github.com/Hamlib/Hamlib/releases
119+
```
120+
121+
2. **Start rigctld for IC-7300**:
122+
```bash
123+
# Basic configuration for IC-7300 on USB serial port
124+
rigctld -m 306 -r /dev/ttyUSB0 -s 38400 -T localhost -t 4532
125+
126+
# Windows example (replace COM3 with your actual port)
127+
rigctld.exe -m 306 -r COM3 -s 38400 -T localhost -t 4532
128+
```
129+
130+
**Parameters explained**:
131+
- `-m 306`: Model number for - e.g. - Icom IC-7300 (use `rigctl -l` to see all models)
132+
- `-r /dev/ttyUSB0`: Serial port device (adjust for your setup / on Windows its COMx)
133+
- `-s 38400`: Serial baud rate (IC-7300 default is 38400)
134+
- `-T localhost`: TCP host for rigctld daemon
135+
- `-t 4532`: TCP port for rigctld daemon (default WaveLogGate Hamlib port)
136+
137+
3. **Configure WaveLogGate**:
138+
- Radio type: **Hamlib**
139+
- Host: `127.0.0.1`
140+
- Port: `4532` (must match rigctld port)
141+
142+
#### Common Hamlib Model Numbers
143+
- **Icom IC-7300**: `306`
144+
- **Icom IC-705**: `439`
145+
- **Icom IC-7610**: `378`
146+
- **Yaesu FT-891**: `161`
147+
- **Yaesu FT-991A**: `146`
148+
149+
#### Troubleshooting Hamlib
150+
```bash
151+
# List all supported radios
152+
rigctl -l
153+
154+
# Test connection (run after rigctld is running)
155+
rigctl -m 306 -r /dev/ttyUSB0 get_freq
156+
```
157+
158+
**Important**: `rigctld` must remain running in the background for WaveLogGate to control your radio.
159+
101160
### WaveLog Integration
102161
1. **For Live QSOs**: Open WaveLog Live Logging → Radio tab → Select "WLGate"
103162
2. **For Manual QSOs**: In Stations tab, select "WLGate" as radio
@@ -140,6 +199,15 @@ Access advanced settings by pressing **Ctrl+Shift+D** in the configuration windo
140199

141200
**Note**: Advanced settings are in beta - restart the application after changes to ensure they're applied correctly.
142201

202+
### Special: Tiling Window Managers like i3 or Hyprland
203+
204+
With tiling window managers the window will be at it's fixed size which is usually okay for the normal user. In tiling WM this doesn't work properly. To fix that you can allow the window to resize by setting a env variable. This will only affect a handful of users and they will know how to handle it.
205+
206+
```bash
207+
export WLGATE_RESIZABLE=true
208+
./path_to_your_bin
209+
```
210+
143211
## Development
144212

145213
### Prerequisites

main.js

Lines changed: 132 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const xml = require("xml2js");
66
const net = require('net');
77
const WebSocket = require('ws');
88

9+
// In some cases we need to make the WLgate window resizable (for example for tiling window managers)
10+
// Default: false
11+
const resizable = process.env.WLGATE_RESIZABLE === 'true' || false;
12+
913
const gotTheLock = app.requestSingleInstanceLock();
1014

1115
let powerSaveBlockerId;
@@ -16,6 +20,9 @@ let currentCAT=null;
1620
var WServer;
1721
let wsServer;
1822
let wsClients = new Set();
23+
let isShuttingDown = false;
24+
let activeConnections = new Set(); // Track active TCP connections
25+
let activeHttpRequests = new Set(); // Track active HTTP requests for cancellation
1926

2027
const DemoAdif='<call:5>DJ7NT <gridsquare:4>JO30 <mode:3>FT8 <rst_sent:3>-15 <rst_rcvd:2>33 <qso_date:8>20240110 <time_on:6>051855 <qso_date_off:8>20240110 <time_off:6>051855 <band:3>40m <freq:8>7.155783 <station_callsign:5>TE1ST <my_gridsquare:6>JO30OO <eor>';
2128

@@ -47,7 +54,7 @@ function createWindow () {
4754
const mainWindow = new BrowserWindow({
4855
width: 430,
4956
height: 250,
50-
resizable: false,
57+
resizable: resizable, // Default: false, can be overwritten with WLGATE_RESIZABLE
5158
autoHideMenuBar: app.isPackaged,
5259
webPreferences: {
5360
contextIsolation: false,
@@ -112,7 +119,8 @@ ipcMain.on("setCAT", async (event,arg) => {
112119
});
113120

114121
ipcMain.on("quit", async (event,arg) => {
115-
app.isQuitting = true;
122+
console.log('Quit requested from renderer');
123+
shutdownApplication();
116124
app.quit();
117125
event.returnValue=true;
118126
});
@@ -123,6 +131,84 @@ ipcMain.on("radio_status_update", async (event,arg) => {
123131
event.returnValue=true;
124132
});
125133

134+
function cleanupConnections() {
135+
console.log('Cleaning up active TCP connections...');
136+
137+
// Close all tracked TCP connections
138+
activeConnections.forEach(connection => {
139+
try {
140+
if (connection && !connection.destroyed) {
141+
connection.destroy();
142+
console.log('Closed TCP connection');
143+
}
144+
} catch (error) {
145+
console.error('Error closing TCP connection:', error);
146+
}
147+
});
148+
149+
// Clear the connections set
150+
activeConnections.clear();
151+
console.log('All TCP connections cleaned up');
152+
153+
// Abort all in-flight HTTP requests
154+
activeHttpRequests.forEach(request => {
155+
try {
156+
request.abort();
157+
console.log('Aborted HTTP request');
158+
} catch (error) {
159+
console.error('Error aborting HTTP request:', error);
160+
}
161+
});
162+
163+
// Clear the HTTP requests set
164+
activeHttpRequests.clear();
165+
console.log('All HTTP requests aborted');
166+
}
167+
168+
function shutdownApplication() {
169+
if (isShuttingDown) {
170+
console.log('Shutdown already in progress, ignoring duplicate request');
171+
return;
172+
}
173+
174+
isShuttingDown = true;
175+
console.log('Initiating application shutdown...');
176+
177+
try {
178+
// Signal renderer to clear timers and connections
179+
if (s_mainWindow && !s_mainWindow.isDestroyed()) {
180+
console.log('Sending cleanup signal to renderer...');
181+
s_mainWindow.webContents.send('cleanup');
182+
}
183+
184+
// Clean up TCP connections
185+
cleanupConnections();
186+
187+
// Close all servers
188+
if (WServer) {
189+
console.log('Closing UDP server...');
190+
WServer.close();
191+
}
192+
if (httpServer) {
193+
console.log('Closing HTTP server...');
194+
httpServer.close();
195+
}
196+
if (wsServer) {
197+
console.log('Closing WebSocket server and clients...');
198+
// Close all WebSocket client connections
199+
wsClients.forEach(client => {
200+
if (client.readyState === WebSocket.OPEN) {
201+
client.close();
202+
}
203+
});
204+
wsClients.clear();
205+
wsServer.close();
206+
}
207+
} catch (error) {
208+
console.error('Error during server shutdown:', error);
209+
}
210+
}
211+
126212
function show_noti(arg) {
127213
if (Notification.isSupported()) {
128214
try {
@@ -161,19 +247,13 @@ ipcMain.on("test", async (event,arg) => {
161247
});
162248

163249
app.on('before-quit', () => {
164-
console.log('Shutting down servers...');
165-
if (WServer) {
166-
WServer.close();
167-
}
168-
if (httpServer) {
169-
httpServer.close();
170-
}
250+
console.log('before-quit event triggered');
251+
shutdownApplication();
171252
});
172253

173254
process.on('SIGINT', () => {
174-
console.log('SIGINT received, closing servers...');
175-
if (WServer) WServer.close();
176-
if (httpServer) httpServer.close();
255+
console.log('SIGINT received, initiating shutdown...');
256+
shutdownApplication();
177257
process.exit(0);
178258
});
179259

@@ -205,8 +285,12 @@ if (!gotTheLock) {
205285
}
206286

207287
app.on('window-all-closed', function () {
288+
console.log('All windows closed, initiating shutdown...');
289+
if (!isShuttingDown) {
290+
shutdownApplication();
291+
}
208292
if (process.platform !== 'darwin') app.quit();
209-
app.quit();
293+
else app.quit();
210294
})
211295

212296
function normalizeTxPwr(adifdata) {
@@ -236,8 +320,23 @@ function normalizeTxPwr(adifdata) {
236320
});
237321
}
238322

323+
function normalizeKIndex(adifdata) {
324+
return adifdata.replace(/<K_INDEX:(\d+)>([^<]+)/gi, (match, length, value) => {
325+
const numValue = parseFloat(value.trim());
326+
if (isNaN(numValue)) return ''; // Remove if not a number
327+
328+
// Round to nearest integer and clamp to 0-9 range
329+
let kIndex = Math.round(numValue);
330+
if (kIndex < 0) kIndex = 0;
331+
if (kIndex > 9) kIndex = 9;
332+
333+
return `<K_INDEX:${kIndex.toString().length}>${kIndex}`;
334+
});
335+
}
336+
239337
function manipulateAdifData(adifdata) {
240338
adifdata = normalizeTxPwr(adifdata);
339+
adifdata = normalizeKIndex(adifdata);
241340
// add more manipulation if necessary here
242341
// ...
243342
return adifdata;
@@ -306,6 +405,9 @@ function send2wavelog(o_cfg,adif, dryrun = false) {
306405
const body = [];
307406
res.on('data', (chunk) => body.push(chunk));
308407
res.on('end', () => {
408+
// Remove request from tracking when completed
409+
activeHttpRequests.delete(req);
410+
309411
let resString = Buffer.concat(body).toString();
310412
if (rej) {
311413
if (resString.indexOf('html>')>0) {
@@ -321,19 +423,26 @@ function send2wavelog(o_cfg,adif, dryrun = false) {
321423
})
322424

323425
req.on('error', (err) => {
426+
// Remove request from tracking on error
427+
activeHttpRequests.delete(req);
324428
rej=true;
325429
req.destroy();
326430
result.resString='{"status":"failed","reason":"internet problem"}';
327431
reject(result);
328432
})
329433

330434
req.on('timeout', (err) => {
435+
// Remove request from tracking on timeout
436+
activeHttpRequests.delete(req);
331437
rej=true;
332438
req.destroy();
333439
result.resString='{"status":"failed","reason":"timeout"}';
334440
reject(result);
335441
})
336442

443+
// Track the HTTP request for cleanup
444+
activeHttpRequests.add(req);
445+
337446
req.write(postData);
338447
req.end();
339448
});
@@ -428,7 +537,7 @@ ports.forEach(port => {
428537
s_mainWindow.webContents.send('updateTX', adobject);
429538
tomsg('');
430539
} else {
431-
tomsg('<div class="alert alert-danger" role="alert">Set ONLY Secondary UDP-Server to Port 2333 at WSJT-X</div>');
540+
tomsg('<div class="alert alert-danger" role="alert">No ADIF detected. WSJT-X: Use ONLY Secondary UDP-Server</div>');
432541
}
433542
});
434543
WServer.bind(port);
@@ -615,8 +724,15 @@ async function settrx(qrg, mode = '') {
615724
client.end();
616725
});
617726

618-
client.on("error", (err) => {});
619-
client.on("close", () => {});
727+
// Track the connection for cleanup
728+
activeConnections.add(client);
729+
730+
client.on("error", (err) => {
731+
activeConnections.delete(client);
732+
});
733+
client.on("close", () => {
734+
activeConnections.delete(client);
735+
});
620736
}
621737

622738
// Broadcast frequency/mode change to WebSocket clients

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Gateway for connecting WSJT-* and FLRig to Wavelog",
55
"keywords": [],
66
"main": "./main.js",
7-
"version": "1.1.11",
7+
"version": "1.1.12",
88
"author": "DJ7NT",
99
"scripts": {
1010
"start": "electron-forge start",

0 commit comments

Comments
 (0)