tests with ping and beacon

This commit is contained in:
DJ2LS 2023-11-09 15:48:10 +01:00
parent 24ad55081c
commit 1dc766e70e
8 changed files with 463 additions and 39 deletions

View file

@ -11,7 +11,6 @@ const settings = useSettingsStore(pinia);
import { useStateStore } from "../store/stateStore.js"; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { sendPing, startBeacon, stopBeacon } from "../js/sock.js";
import { postToServer } from "../js/rest.js"; import { postToServer } from "../js/rest.js";
@ -20,17 +19,20 @@ function transmitCQ() {
} }
function transmitPing() { function transmitPing() {
sendPing((<HTMLInputElement>document.getElementById("dxCall")).value); let command = {"dxcall": (<HTMLInputElement>document.getElementById("dxCall")).value}
postToServer("localhost", 5000, "modem/ping_ping", command);
} }
function startStopBeacon() { function startStopBeacon() {
switch (state.beacon_state) { switch (state.beacon_state) {
case "False": case "False":
startBeacon(settings.beacon_interval); postToServer("localhost", 5000, "modem/beacon", {"enabled": "True"});
break; break;
case "True": case "True":
stopBeacon(); postToServer("localhost", 5000, "modem/beacon", {"enabled": "False"});
break; break;
default: default:

378
gui/src/js/eventHandler.js Normal file
View file

@ -0,0 +1,378 @@
import { addDataToWaterfall } from "../js/waterfallHandler.js";
import {
newMessageReceived,
newBeaconReceived,
updateTransmissionStatus,
setStateSuccess,
setStateFailed,
} from "./chatHandler";
import { displayToast } from "./popupHandler";
// ----------------- init pinia stores -------------
import { setActivePinia } from "pinia";
import pinia from "../store/index";
setActivePinia(pinia);
import { useStateStore } from "../store/stateStore.js";
const stateStore = useStateStore(pinia);
import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia);
export function eventDispatcher(data){
console.log(data)
if (data["command"] == "modem_state") {
//console.log(data)
stateStore.rx_buffer_length = data["rx_buffer_length"];
stateStore.frequency = data["frequency"];
stateStore.busy_state = data["modem_state"];
stateStore.arq_state = data["arq_state"];
stateStore.mode = data["mode"];
stateStore.bandwidth = data["bandwidth"];
stateStore.tx_audio_level = data["tx_audio_level"];
stateStore.rx_audio_level = data["rx_audio_level"];
// if audio level is different from config one, send new audio level to modem
//console.log(parseInt(stateStore.tx_audio_level))
//console.log(parseInt(settings.tx_audio_level))
if (
parseInt(stateStore.tx_audio_level) !==
parseInt(settings.tx_audio_level) &&
setTxAudioLevelOnce === true
) {
setTxAudioLevelOnce = false;
console.log(setTxAudioLevelOnce);
setTxAudioLevel(settings.tx_audio_level);
}
if (
parseInt(stateStore.rx_audio_level) !==
parseInt(settings.rx_audio_level) &&
setRxAudioLevelOnce === true
) {
setRxAudioLevelOnce = false;
console.log(setRxAudioLevelOnce);
setRxAudioLevel(settings.rx_audio_level);
}
stateStore.dbfs_level = data["audio_dbfs"];
stateStore.ptt_state = data["ptt_state"];
stateStore.speed_level = data["speed_level"];
stateStore.fft = JSON.parse(data["fft"]);
stateStore.channel_busy = data["channel_busy"];
stateStore.channel_busy_slot = data["channel_busy_slot"];
addDataToWaterfall(JSON.parse(data["fft"]));
if (data["scatter"].length > 0) {
stateStore.scatter = data["scatter"];
}
// s meter strength
stateStore.s_meter_strength_raw = data["strength"];
if (stateStore.s_meter_strength_raw == "") {
stateStore.s_meter_strength_raw = "Unsupported";
stateStore.s_meter_strength_percent = 0;
} else {
// https://www.moellerstudios.org/converting-amplitude-representations/
stateStore.s_meter_strength_percent = Math.round(
Math.pow(10, stateStore.s_meter_strength_raw / 20) * 100,
);
}
stateStore.dbfs_level_percent = Math.round(
Math.pow(10, stateStore.dbfs_level / 20) * 100,
);
stateStore.dbfs_level = Math.round(stateStore.dbfs_level);
stateStore.arq_total_bytes = data["total_bytes"];
stateStore.heard_stations = data["stations"].sort(
sortByPropertyDesc("timestamp"),
);
stateStore.dxcallsign = data["dxcallsign"];
stateStore.beacon_state = data["beacon_state"];
stateStore.audio_recording = data["audio_recording"];
stateStore.hamlib_status = data["hamlib_status"];
stateStore.alc = data["alc"];
stateStore.rf_level = data["rf_level"];
stateStore.is_codec2_traffic = data["is_codec2_traffic"];
stateStore.arq_session_state = data["arq_session"];
stateStore.arq_state = data["arq_state"];
stateStore.arq_transmission_percent = data["arq_transmission_percent"];
stateStore.arq_seconds_until_finish = data["arq_seconds_until_finish"];
stateStore.arq_seconds_until_timeout =
data["arq_seconds_until_timeout"];
stateStore.arq_seconds_until_timeout_percent =
(stateStore.arq_seconds_until_timeout / 180) * 100;
if (data["speed_list"].length > 0) {
prepareStatsDataForStore(data["speed_list"]);
}
// TODO: Remove ported objects
/*
let Data = {
mycallsign: data["mycallsign"],
mygrid: data["mygrid"],
//channel_state: data['CHANNEL_STATE'],
info: data["info"],
rx_msg_buffer_length: data["rx_msg_buffer_length"],
tx_n_max_retries: data["tx_n_max_retries"],
arq_tx_n_frames_per_burst: data["arq_tx_n_frames_per_burst"],
arq_tx_n_bursts: data["arq_tx_n_bursts"],
arq_tx_n_current_arq_frame: data["arq_tx_n_current_arq_frame"],
arq_tx_n_total_arq_frames: data["arq_tx_n_total_arq_frames"],
arq_rx_frame_n_bursts: data["arq_rx_frame_n_bursts"],
arq_rx_n_current_arq_frame: data["arq_rx_n_current_arq_frame"],
arq_n_arq_frames_per_data_frame:
data["arq_n_arq_frames_per_data_frame"],
arq_bytes_per_minute: data["arq_bytes_per_minute"],
arq_compression_factor: data["arq_compression_factor"],
routing_table: data["routing_table"],
mesh_signalling_table: data["mesh_signalling_table"],
listen: data["listen"],
//speed_table: [{"bpm" : 5200, "snr": -3, "timestamp":1673555399},{"bpm" : 2315, "snr": 12, "timestamp":1673555500}],
};
*/
}
var message = "";
if (data["freedata"] == "modem-message") {
// break early if we received a dummy callsign
// thats a kind of hotfix, as long as the modem isnt handling this better
if (
data["dxcallsign"] == "AA0AA-0" ||
data["dxcallsign"] == "ZZ9YY-0"
) {
return;
}
console.log(data);
switch (data["fec"]) {
case "is_writing":
// RX'd FECiswriting
break;
case "broadcast":
// RX'd FEC BROADCAST
var encoded_data = atob_FD(data["data"]);
var splitted_data = encoded_data.split(split_char);
var messageArray = [];
if (splitted_data[0] == "m") {
messageArray.push(data);
console.log(data);
}
break;
}
switch (data["cq"]) {
case "transmitting":
// CQ TRANSMITTING
displayToast(
"success",
"bi-arrow-left-right",
"Transmitting CQ",
5000,
);
break;
case "received":
// CQ RECEIVED
message = "CQ from " + data["dxcallsign"];
displayToast("success", "bi-person-arms-up", message, 5000);
break;
}
switch (data["qrv"]) {
case "transmitting":
// QRV TRANSMITTING
displayToast(
"info",
"bi-person-raised-hand",
"Transmitting QRV ",
5000,
);
break;
case "received":
// QRV RECEIVED
message = "QRV from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("success", "bi-person-raised-hand", message, 5000);
break;
}
switch (data["beacon"]) {
case "transmitting":
// BEACON TRANSMITTING
displayToast(
"success",
"bi-broadcast-pin",
"Transmitting beacon",
5000,
);
break;
case "received":
// BEACON RECEIVED
newBeaconReceived(data);
message =
"Beacon from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("info", "bi-broadcast", message, 5000);
break;
}
switch (data["ping"]) {
case "transmitting":
// PING TRANSMITTING
message = "Sending ping to " + data["dxcallsign"];
displayToast("success", "bi-arrow-right", message, 5000);
break;
case "received":
// PING RECEIVED
message =
"Ping request from " +
data["dxcallsign"] +
" | " +
data["dxgrid"];
displayToast("success", "bi-arrow-right-short", message, 5000);
break;
case "acknowledge":
// PING ACKNOWLEDGE
message =
"Received ping-ack from " +
data["dxcallsign"] +
" | " +
data["dxgrid"];
displayToast("success", "bi-arrow-left-right", message, 5000);
break;
}
// ARQ SESSION && freedata == modem-message
if (data["arq"] == "session") {
switch (data["status"]) {
case "connecting":
// ARQ Open
break;
case "connected":
// ARQ Opening
break;
case "waiting":
// ARQ Opening
break;
case "close":
// ARQ Closing
break;
case "failed":
// ARQ Failed
break;
}
}
// ARQ TRANSMISSION && freedata == modem-message
if (data["arq"] == "transmission") {
switch (data["status"]) {
case "opened":
// ARQ Open
message = "ARQ session opened: " + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000);
break;
case "opening":
// ARQ Opening IRS/ISS
if (data["irs"] == "False") {
message = "ARQ session opening: " + data["dxcallsign"];
displayToast("info", "bi-arrow-left-right", message, 5000);
break;
} else {
message = "ARQ sesson request from: " + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000);
break;
}
case "waiting":
// ARQ waiting
message = "Channel busy | ARQ protocol is waiting";
displayToast("warning", "bi-hourglass-split", message, 5000);
break;
case "receiving":
// ARQ RX
break;
case "failed":
// ARQ TX Failed
if (data["reason"] == "protocol version missmatch") {
message = "Protocol version mismatch!";
displayToast("danger", "bi-chevron-bar-expand", message, 5000);
setStateFailed();
break;
} else {
message = "Transmission failed";
displayToast("danger", "bi-x-octagon", message, 5000);
updateTransmissionStatus(data);
setStateFailed();
break;
}
switch (data["irs"]) {
case "True":
updateTransmissionStatus(data);
break;
default:
updateTransmissionStatus(data);
break;
}
break;
case "received":
// ARQ data received
console.log(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_FD(data["data"]);
var splitted_data = encoded_data.split(split_char);
// new message received
if (splitted_data[0] == "m") {
console.log(splitted_data);
newMessageReceived(splitted_data, data);
}
break;
case "transmitting":
// ARQ transmitting
updateTransmissionStatus(data);
break;
case "transmitted":
// ARQ transmitted
message = "Data transmitted";
displayToast("success", "bi-check-sqaure", message, 5000);
updateTransmissionStatus(data);
setStateSuccess();
break;
}
}
}
}

View file

@ -1,3 +1,8 @@
import {
eventDispatcher
} from "../js/eventHandler.js";
let socket; let socket;
let retries = 0; let retries = 0;
let maxRetries = 15; let maxRetries = 15;
@ -14,7 +19,7 @@ function connect() {
// handle data // handle data
socket.addEventListener("message", function (event) { socket.addEventListener("message", function (event) {
console.log("Message from server:", event.data); console.log("Message from server:", event.data);
console.log("Message from server:", event); eventDispatcher(event.data)
}); });
// handle errors // handle errors
@ -27,12 +32,11 @@ function connect() {
console.log("WebSocket connection closed:", event.code); console.log("WebSocket connection closed:", event.code);
// Reconnect handler // Reconnect handler
if (!event.wasClean && retries < maxRetries) { if (!event.wasClean) {
setTimeout(() => { setTimeout(() => {
console.log("Reconnecting to websocket. Attempt: " + retries); console.log("Reconnecting to websocket");
connect(); connect();
}, 1000); }, 1000);
retries++;
} }
}); });
} }

View file

@ -9,6 +9,8 @@ import {
getModemConfigAsJSON, getModemConfigAsJSON,
} from "../js/settingsHandler.ts"; } from "../js/settingsHandler.ts";
export async function getFromServer(host, port, endpoint) { export async function getFromServer(host, port, endpoint) {
// our central function for fetching the modems REST API by a specific endpoint // our central function for fetching the modems REST API by a specific endpoint
// TODO make this function using the host and port, specified in settings // TODO make this function using the host and port, specified in settings

View file

@ -733,20 +733,7 @@ export function getRxBuffer() {
writeTncCommand(command); writeTncCommand(command);
} }
// START BEACON
export function startBeacon(interval) {
var command =
'{"type" : "broadcast", "command" : "start_beacon", "parameter": "' +
interval +
'"}';
writeTncCommand(command);
}
// STOP BEACON
export function stopBeacon() {
var command = '{"type" : "broadcast", "command" : "stop_beacon"}';
writeTncCommand(command);
}
// OPEN ARQ SESSION // OPEN ARQ SESSION
export function connectARQ(dxcallsign) { export function connectARQ(dxcallsign) {

View file

@ -2543,10 +2543,23 @@ class DATA:
dxcallsign:bytes: dxcallsign:bytes:
""" """
# check if specific callsign is set with different SSID than the Modem is initialized
try:
mycallsign = helpers.callsign_to_bytes(mycallsign)
mycallsign = helpers.bytes_to_callsign(mycallsign)
except Exception:
mycallsign = self.mycallsign
if not str(dxcallsign).strip(): if not str(dxcallsign).strip():
# TODO We should display a message to this effect on the UI.
self.log.warning("[Modem] Missing required callsign", dxcallsign=dxcallsign) self.log.warning("[Modem] Missing required callsign", dxcallsign=dxcallsign)
return return
# additional step for being sure our callsign is correctly
# in case we are not getting a station ssid
# then we are forcing a station ssid = 0
dxcallsign = helpers.callsign_to_bytes(dxcallsign)
dxcallsign = helpers.bytes_to_callsign(dxcallsign)
Station.dxcallsign = dxcallsign Station.dxcallsign = dxcallsign
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign) Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
self.send_data_to_socket_queue( self.send_data_to_socket_queue(

View file

@ -14,7 +14,6 @@ app = Flask(__name__)
CORS(app) CORS(app)
CORS(app, resources={r"/*": {"origins": "*"}}) CORS(app, resources={r"/*": {"origins": "*"}})
sock = Sock(app) sock = Sock(app)
print(sock)
# set config file to use # set config file to use
def set_config(): def set_config():
@ -76,29 +75,42 @@ def get_serial_devices():
devices = serial_ports.get_ports() devices = serial_ports.get_ports()
return api_response(devices) return api_response(devices)
# @app.route('/modem/listen', methods=['POST'])
# @app.route('/modem/record_audio', methods=['POST'])
# @app.route('/modem/responde_to_call', methods=['POST'])
# @app.route('/modem/responde_to_cq', methods=['POST'])
# @app.route('/modem/audio_levels', methods=['POST']) # tx and rx
# @app.route('/modem/send_test_frame', methods=['POST'])
# @app.route('/modem/fec_transmit', methods=['POST'])
# @app.route('/modem/fec_is_writing', methods=['POST'])
@app.route('/modem/cqcqcq', methods=['POST', 'GET']) @app.route('/modem/cqcqcq', methods=['POST', 'GET'])
def post_cqcqcq(): def post_cqcqcq():
if request.method in ['POST']: if request.method in ['POST']:
server_commands.cqcqcq() server_commands.cqcqcq()
return api_response({"cmd": "cqcqcq"}) return api_response({"cmd": "cqcqcq"})
else: else:
return api_response({"info": "endpoint for triggering a CQ via POST"}) return api_response({"info": "endpoint for triggering a CQ via POST"})
@app.route('/modem/beacon', methods=['POST'])
def post_beacon():
if request.method in ['POST']:
server_commands.beacon(request.json)
return api_response(request.json)
else:
return api_response({"info": "endpoint for controlling BEACON STATE via POST"})
@app.route('/modem/ping_ping', methods=['POST'])
def post_ping():
if request.method in ['POST']:
server_commands.ping_ping(request.json)
return api_response(request.json)
else:
return api_response({"info": "endpoint for controlling PING via POST"})
# @app.route('/modem/listen', methods=['POST']) # not needed if we are restarting modem on changing settings
# @app.route('/modem/record_audio', methods=['POST'])
# @app.route('/modem/responde_to_call', methods=['POST']) # not needed if we are restarting modem on changing settings
# @app.route('/modem/responde_to_cq', methods=['POST']) # not needed if we are restarting modem on changing settings
# @app.route('/modem/audio_levels', methods=['POST']) # tx and rx # not needed if we are restarting modem on changing settings
# @app.route('/modem/send_test_frame', methods=['POST'])
# @app.route('/modem/fec_transmit', methods=['POST'])
# @app.route('/modem/fec_is_writing', methods=['POST'])
# @app.route('/modem/beacon', methods=['POST']) # on/off
# @app.route('/modem/mesh_ping', methods=['POST']) # @app.route('/modem/mesh_ping', methods=['POST'])
# @app.route('/modem/ping_ping', methods=['POST']) # @app.route('/modem/arq_connect', methods=['POST'])
# @app.route('/modem/arc_connect', methods=['POST']) # @app.route('/modem/arq_disconnect', methods=['POST'])
# @app.route('/modem/arc_disconnect', methods=['POST'])
# @app.route('/modem/send_raw', methods=['POST']) # @app.route('/modem/send_raw', methods=['POST'])
# @app.route('/modem/stop_transmission', methods=['POST']) # @app.route('/modem/stop_transmission', methods=['POST'])
@ -116,5 +128,7 @@ def post_cqcqcq():
# Event websocket # Event websocket
@sock.route('/events') @sock.route('/events')
def echo(sock): def echo(sock):
ev = app.modem_events.get() # it seems we have to keep the logics inside a loop, otherwise connection will be terminated
sock.send(ev) while True:
ev = app.modem_events.get()
sock.send(ev)

View file

@ -1,4 +1,28 @@
from queues import DATA_QUEUE_TRANSMIT from queues import DATA_QUEUE_TRANSMIT
import structlog
log = structlog.get_logger("COMMANDS")
def cqcqcq(): def cqcqcq(self):
DATA_QUEUE_TRANSMIT.put(["CQ"]) DATA_QUEUE_TRANSMIT.put(["CQ"])
def ping_ping(data):
try:
dxcallsign = data["dxcallsign"]
if not str(dxcallsign).strip():
return
DATA_QUEUE_TRANSMIT.put(["PING", None, dxcallsign])
except Exception as err:
log.warning(
"[CMD] PING command execution error", e=err, command=data
)
def beacon(data):
beacon_state = False
if data['enabled'] in ['True']:
beacon_state = True
#Beacon.beacon_state = beacon_state
log.info(
"[CMD] Changing beacon state", state=beacon_state
)
DATA_QUEUE_TRANSMIT.put(["BEACON", 300, beacon_state])