2021-02-16 13:23:57 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
Created on Fri Dec 25 21:25:14 2020
|
|
|
|
|
|
|
|
@author: DJ2LS
|
2021-08-08 09:08:34 +00:00
|
|
|
|
|
|
|
# GET COMMANDS
|
2022-05-25 22:27:33 +00:00
|
|
|
# "command" : "..."
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-05-25 22:27:33 +00:00
|
|
|
# SET COMMANDS
|
|
|
|
# "command" : "..."
|
|
|
|
# "parameter" : " ..."
|
2021-08-08 09:08:34 +00:00
|
|
|
|
2022-05-25 22:27:33 +00:00
|
|
|
# DATA COMMANDS
|
|
|
|
# "command" : "..."
|
|
|
|
# "type" : "..."
|
|
|
|
# "dxcallsign" : "..."
|
|
|
|
# "data" : "..."
|
2021-02-16 13:23:57 +00:00
|
|
|
"""
|
2022-05-11 22:10:59 +00:00
|
|
|
import atexit
|
|
|
|
import base64
|
|
|
|
import queue
|
2021-02-16 13:23:57 +00:00
|
|
|
import socketserver
|
2022-05-11 22:10:59 +00:00
|
|
|
import sys
|
2021-02-16 13:23:57 +00:00
|
|
|
import threading
|
2021-03-17 10:22:06 +00:00
|
|
|
import time
|
2022-12-27 20:13:08 +00:00
|
|
|
import wave
|
2022-05-11 22:10:59 +00:00
|
|
|
import helpers
|
|
|
|
import static
|
2023-10-17 12:30:34 +00:00
|
|
|
from global_instances import ARQ, AudioParam, Beacon, Channel, Daemon, HamlibParam, ModemParam, Station, Statistics, TCIParam, TNC, MeshParam
|
2022-05-26 01:23:30 +00:00
|
|
|
import structlog
|
2023-01-29 16:50:57 +00:00
|
|
|
from random import randrange
|
2022-05-26 01:23:30 +00:00
|
|
|
import ujson as json
|
2022-06-17 23:48:47 +00:00
|
|
|
from exceptions import NoCallsign
|
2023-06-13 12:03:36 +00:00
|
|
|
from queues import DATA_QUEUE_TRANSMIT, RX_BUFFER, RIGCTLD_COMMAND_QUEUE, MESH_QUEUE_TRANSMIT, MESH_SIGNALLING_TABLE
|
2021-11-18 18:40:22 +00:00
|
|
|
|
2022-01-20 19:38:56 +00:00
|
|
|
SOCKET_QUEUE = queue.Queue()
|
2022-01-22 19:39:37 +00:00
|
|
|
DAEMON_QUEUE = queue.Queue()
|
2021-09-23 15:49:45 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
CONNECTED_CLIENTS = set()
|
2022-02-16 08:11:32 +00:00
|
|
|
CLOSE_SIGNAL = False
|
|
|
|
|
2023-02-10 09:15:10 +00:00
|
|
|
TESTMODE = False
|
|
|
|
|
2022-05-28 02:17:15 +00:00
|
|
|
log = structlog.get_logger("sock")
|
|
|
|
|
2022-02-16 08:11:32 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
2022-03-04 15:50:32 +00:00
|
|
|
"""
|
|
|
|
the socket handler base class
|
|
|
|
"""
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
pass
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-06-24 18:55:59 +00:00
|
|
|
|
2023-02-10 11:12:18 +00:00
|
|
|
# noinspection PyTypeChecker
|
2022-01-20 19:38:56 +00:00
|
|
|
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
|
2022-03-04 15:50:32 +00:00
|
|
|
""" """
|
2022-05-11 22:10:59 +00:00
|
|
|
connection_alive = False
|
2022-06-01 00:35:35 +00:00
|
|
|
log = structlog.get_logger("ThreadedTCPRequestHandler")
|
2022-01-22 19:39:37 +00:00
|
|
|
|
2022-01-20 19:38:56 +00:00
|
|
|
def send_to_client(self):
|
2022-03-04 15:50:32 +00:00
|
|
|
"""
|
|
|
|
function called by socket handler
|
|
|
|
send data to a network client if available
|
|
|
|
"""
|
2022-05-26 01:23:30 +00:00
|
|
|
tempdata = b""
|
2022-02-16 08:11:32 +00:00
|
|
|
while self.connection_alive and not CLOSE_SIGNAL:
|
2022-01-20 19:38:56 +00:00
|
|
|
# send tnc state as network stream
|
2022-01-22 19:39:37 +00:00
|
|
|
# check server port against daemon port and send corresponding data
|
2023-04-27 19:43:56 +00:00
|
|
|
if self.server.server_address[1] == TNC.port and not Daemon.tncstarted:
|
2022-01-22 19:39:37 +00:00
|
|
|
data = send_tnc_state()
|
2022-02-08 14:27:34 +00:00
|
|
|
if data != tempdata:
|
|
|
|
tempdata = data
|
|
|
|
SOCKET_QUEUE.put(data)
|
2022-01-22 19:39:37 +00:00
|
|
|
else:
|
|
|
|
data = send_daemon_state()
|
2022-02-08 14:27:34 +00:00
|
|
|
if data != tempdata:
|
|
|
|
tempdata = data
|
|
|
|
SOCKET_QUEUE.put(data)
|
2022-12-12 11:28:52 +00:00
|
|
|
threading.Event().wait(0.5)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
while not SOCKET_QUEUE.empty():
|
|
|
|
data = SOCKET_QUEUE.get()
|
2022-05-26 01:23:30 +00:00
|
|
|
sock_data = bytes(data, "utf-8")
|
|
|
|
sock_data += b"\n" # append line limiter
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
# send data to all clients
|
2022-12-04 14:35:41 +00:00
|
|
|
try:
|
|
|
|
for client in CONNECTED_CLIENTS:
|
|
|
|
try:
|
|
|
|
client.send(sock_data)
|
|
|
|
except Exception as err:
|
|
|
|
self.log.info("[SCK] Connection lost", e=err)
|
2023-02-10 11:12:18 +00:00
|
|
|
# TODO: Check if we really should set connection alive to false.
|
|
|
|
# This might disconnect all other clients as well...
|
2022-12-04 14:35:41 +00:00
|
|
|
self.connection_alive = False
|
|
|
|
except Exception as err:
|
|
|
|
self.log.debug("[SCK] catch harmless RuntimeError: Set changed size during iteration", e=err)
|
2022-02-17 09:11:12 +00:00
|
|
|
|
2022-01-20 19:38:56 +00:00
|
|
|
# we want to transmit scatter data only once to reduce network traffic
|
2023-04-27 19:43:56 +00:00
|
|
|
ModemParam.scatter = []
|
2022-05-26 01:23:30 +00:00
|
|
|
# self.request.sendall(sock_data)
|
2022-12-12 11:28:52 +00:00
|
|
|
threading.Event().wait(0.15)
|
2022-01-20 19:38:56 +00:00
|
|
|
|
|
|
|
def receive_from_client(self):
|
2022-03-04 15:50:32 +00:00
|
|
|
"""
|
|
|
|
function which is called by the socket handler
|
|
|
|
it processes the data which is returned by a client
|
|
|
|
"""
|
2022-01-20 19:38:56 +00:00
|
|
|
data = bytes()
|
2022-02-16 08:11:32 +00:00
|
|
|
while self.connection_alive and not CLOSE_SIGNAL:
|
|
|
|
try:
|
|
|
|
chunk = self.request.recv(1024)
|
|
|
|
data += chunk
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
if chunk == b"":
|
|
|
|
# print("connection broken. Closing...")
|
2022-02-16 08:11:32 +00:00
|
|
|
self.connection_alive = False
|
2022-03-06 16:23:04 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
if data.startswith(b"{") and data.endswith(b"}\n"):
|
2022-02-16 08:11:32 +00:00
|
|
|
# split data by \n if we have multiple commands in socket buffer
|
2022-05-26 01:23:30 +00:00
|
|
|
data = data.split(b"\n")
|
2022-02-16 08:11:32 +00:00
|
|
|
# remove empty data
|
2022-05-26 01:23:30 +00:00
|
|
|
data.remove(b"")
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-02-16 08:11:32 +00:00
|
|
|
# iterate thorugh data list
|
|
|
|
for commands in data:
|
2023-04-26 17:54:53 +00:00
|
|
|
if self.server.server_address[1] == TNC.port:
|
2023-02-09 20:43:49 +00:00
|
|
|
self.process_tnc_commands(commands)
|
2022-02-16 08:11:32 +00:00
|
|
|
else:
|
2023-02-09 20:43:49 +00:00
|
|
|
self.process_daemon_commands(commands)
|
2022-02-17 09:11:12 +00:00
|
|
|
|
|
|
|
# wait some time between processing multiple commands
|
|
|
|
# this is only a first test to avoid doubled transmission
|
2022-05-09 00:41:49 +00:00
|
|
|
# we might improve this by only processing one command or
|
2023-02-10 11:12:18 +00:00
|
|
|
# doing some kind of selection to determine which commands need to be dropped
|
2022-02-17 09:11:12 +00:00
|
|
|
# and which one can be processed during a running transmission
|
2023-01-11 15:18:29 +00:00
|
|
|
threading.Event().wait(0.5)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-02-16 08:11:32 +00:00
|
|
|
# finally delete our rx buffer to be ready for new commands
|
|
|
|
data = bytes()
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
|
|
|
self.log.info(
|
|
|
|
"[SCK] Connection closed",
|
|
|
|
ip=self.client_address[0],
|
|
|
|
port=self.client_address[1],
|
|
|
|
e=err,
|
|
|
|
)
|
2022-02-16 08:11:32 +00:00
|
|
|
self.connection_alive = False
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-01-20 19:38:56 +00:00
|
|
|
def handle(self):
|
2022-03-04 15:50:32 +00:00
|
|
|
"""
|
|
|
|
socket handler
|
|
|
|
"""
|
2022-01-22 19:39:37 +00:00
|
|
|
CONNECTED_CLIENTS.add(self.request)
|
2022-01-06 21:15:14 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
self.log.debug(
|
|
|
|
"[SCK] Client connected",
|
|
|
|
ip=self.client_address[0],
|
|
|
|
port=self.client_address[1],
|
|
|
|
)
|
2022-01-20 19:38:56 +00:00
|
|
|
self.connection_alive = True
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
self.sendThread = threading.Thread(
|
|
|
|
target=self.send_to_client, args=[], daemon=True
|
2022-05-28 15:52:05 +00:00
|
|
|
)
|
|
|
|
self.sendThread.start()
|
2022-05-26 01:23:30 +00:00
|
|
|
self.receiveThread = threading.Thread(
|
|
|
|
target=self.receive_from_client, args=[], daemon=True
|
2022-05-28 15:52:05 +00:00
|
|
|
)
|
|
|
|
self.receiveThread.start()
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-01-20 19:38:56 +00:00
|
|
|
# keep connection alive until we close it
|
2022-02-16 08:11:32 +00:00
|
|
|
while self.connection_alive and not CLOSE_SIGNAL:
|
2022-12-12 11:28:52 +00:00
|
|
|
threading.Event().wait(1)
|
2022-01-06 21:15:14 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
def finish(self):
|
2022-03-04 15:50:32 +00:00
|
|
|
""" """
|
2022-05-26 01:23:30 +00:00
|
|
|
self.log.warning(
|
|
|
|
"[SCK] Closing client socket",
|
|
|
|
ip=self.client_address[0],
|
|
|
|
port=self.client_address[1],
|
|
|
|
)
|
2022-01-28 19:07:39 +00:00
|
|
|
try:
|
|
|
|
CONNECTED_CLIENTS.remove(self.request)
|
2023-02-10 11:12:18 +00:00
|
|
|
except Exception as e:
|
2022-05-26 01:23:30 +00:00
|
|
|
self.log.warning(
|
|
|
|
"[SCK] client connection already removed from client list",
|
|
|
|
client=self.request,
|
2023-02-10 11:12:18 +00:00
|
|
|
e=e,
|
2022-05-26 01:23:30 +00:00
|
|
|
)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# ------------------------ TNC COMMANDS
|
|
|
|
def process_tnc_commands(self, data):
|
|
|
|
"""
|
|
|
|
process tnc commands
|
2022-06-24 18:55:59 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
Args:
|
|
|
|
data:
|
2022-12-04 15:56:12 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
Returns:
|
2022-12-04 15:56:12 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
"""
|
|
|
|
log = structlog.get_logger("process_tnc_commands")
|
2022-11-29 06:28:28 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# we need to do some error handling in case of socket timeout or decoding issue
|
|
|
|
try:
|
|
|
|
# convert data to json object
|
|
|
|
received_json = json.loads(data)
|
|
|
|
log.debug("[SCK] CMD", command=received_json)
|
|
|
|
|
|
|
|
# ENABLE TNC LISTENING STATE
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "listen":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_listen(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_listen(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# START STOP AUDIO RECORDING
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "record_audio":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_record_audio(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_record_audio(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# SET ENABLE/DISABLE RESPOND TO CALL
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "respond_to_call":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_respond_to_call(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_respond_to_call(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# SET ENABLE RESPOND TO CQ
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "respond_to_cq":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_record_audio(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_record_audio(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
# SET TX AUDIO LEVEL
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "tx_audio_level":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_tx_audio_level(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_tx_audio_level(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
# TRANSMIT TEST FRAME
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "send_test_frame":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_send_test_frame(None, received_json)
|
2023-05-06 14:07:33 +00:00
|
|
|
elif TNC.tnc_state in ['busy']:
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 09:15:10 +00:00
|
|
|
else:
|
|
|
|
self.tnc_set_send_test_frame(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
2023-02-12 17:24:42 +00:00
|
|
|
# TRANSMIT FEC FRAME
|
2023-02-12 16:39:13 +00:00
|
|
|
if received_json["type"] == "fec" and received_json["command"] == "transmit":
|
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_fec_transmit(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_fec_transmit(received_json)
|
|
|
|
|
2023-02-12 17:24:42 +00:00
|
|
|
# TRANSMIT IS WRITING FRAME
|
|
|
|
if received_json["type"] == "fec" and received_json["command"] == "transmit_is_writing":
|
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_fec_is_writing(None, received_json)
|
2023-05-06 14:07:33 +00:00
|
|
|
elif TNC.tnc_state in ['busy']:
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-12 17:24:42 +00:00
|
|
|
else:
|
|
|
|
self.tnc_fec_is_writing(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# CQ CQ CQ
|
|
|
|
if received_json["command"] == "cqcqcq":
|
2023-02-10 09:31:33 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_cqcqcq(None, received_json)
|
2023-05-08 14:17:11 +00:00
|
|
|
elif TNC.tnc_state in ['BUSY']:
|
2023-05-06 14:07:33 +00:00
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 09:31:33 +00:00
|
|
|
else:
|
|
|
|
self.tnc_cqcqcq(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# START_BEACON
|
|
|
|
if received_json["command"] == "start_beacon":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_start_beacon(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_start_beacon(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# STOP_BEACON
|
|
|
|
if received_json["command"] == "stop_beacon":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_stop_beacon(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_stop_beacon(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# PING
|
|
|
|
if received_json["type"] == "ping" and received_json["command"] == "ping":
|
2023-02-10 09:15:10 +00:00
|
|
|
|
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_ping_ping(None, received_json)
|
2023-05-08 14:17:11 +00:00
|
|
|
elif TNC.tnc_state in ['BUSY']:
|
2023-05-06 14:07:33 +00:00
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
|
|
|
|
2023-02-10 09:15:10 +00:00
|
|
|
else:
|
|
|
|
self.tnc_ping_ping(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# CONNECT
|
|
|
|
if received_json["type"] == "arq" and received_json["command"] == "connect":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_arq_connect(None, received_json)
|
2023-05-08 14:17:11 +00:00
|
|
|
elif TNC.tnc_state in ['BUSY']:
|
2023-05-06 14:07:33 +00:00
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 09:15:10 +00:00
|
|
|
else:
|
|
|
|
self.tnc_arq_connect(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# DISCONNECT
|
|
|
|
if received_json["type"] == "arq" and received_json["command"] == "disconnect":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_arq_disconnect(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_arq_disconnect(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# TRANSMIT RAW DATA
|
|
|
|
if received_json["type"] == "arq" and received_json["command"] == "send_raw":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_arq_send_raw(None, received_json)
|
2023-05-06 14:07:33 +00:00
|
|
|
elif TNC.tnc_state in ['busy']:
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Dropping command",
|
|
|
|
e="tnc state",
|
|
|
|
state=TNC.tnc_state,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 09:15:10 +00:00
|
|
|
else:
|
|
|
|
self.tnc_arq_send_raw(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# STOP TRANSMISSION
|
|
|
|
if received_json["type"] == "arq" and received_json["command"] == "stop_transmission":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_arq_stop_transmission(None, received_json)
|
|
|
|
else:
|
2023-02-10 11:12:18 +00:00
|
|
|
self.tnc_arq_stop_transmission(received_json)
|
2023-02-10 09:15:10 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# GET RX BUFFER
|
|
|
|
if received_json["type"] == "get" and received_json["command"] == "rx_buffer":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_get_rx_buffer(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_get_rx_buffer(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# DELETE RX BUFFER
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "del_rx_buffer":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_del_rx_buffer(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_del_rx_buffer(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
# SET FREQUENCY
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "frequency":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_frequency(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_frequency(received_json)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# SET MODE
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "mode":
|
2023-02-10 09:15:10 +00:00
|
|
|
if TESTMODE:
|
|
|
|
ThreadedTCPRequestHandler.tnc_set_mode(None, received_json)
|
|
|
|
else:
|
|
|
|
self.tnc_set_mode(received_json)
|
2022-11-29 06:28:28 +00:00
|
|
|
|
2023-05-28 10:13:19 +00:00
|
|
|
# GET ROUTING TABLE
|
|
|
|
if received_json["type"] == "get" and received_json["command"] == "routing_table":
|
|
|
|
self.tnc_get_mesh_routing_table(received_json)
|
|
|
|
|
2023-07-03 07:26:42 +00:00
|
|
|
|
|
|
|
# -------------- MESH ---------------- #
|
2023-06-11 07:12:40 +00:00
|
|
|
# MESH PING
|
|
|
|
if received_json["type"] == "mesh" and received_json["command"] == "ping":
|
|
|
|
self.tnc_mesh_ping(received_json)
|
2023-05-28 10:13:19 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
log.error("[SCK] JSON decoding error", e=err)
|
2023-02-10 09:15:10 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_listen(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
TNC.listen = received_json["state"] in ['true', 'True', True, "ON", "on"]
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("listen", True)
|
2022-12-01 09:05:24 +00:00
|
|
|
|
2023-04-27 19:43:56 +00:00
|
|
|
# if tnc is connected, force disconnect when TNC.listen == False
|
|
|
|
if not TNC.listen and ARQ.arq_session_state not in ["disconnecting", "disconnected", "failed"]:
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
|
|
|
# set early disconnecting state so we can interrupt connection attempts
|
2023-04-27 19:43:56 +00:00
|
|
|
ARQ.arq_session_state = "disconnecting"
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("disconnect", True)
|
2022-12-01 09:05:24 +00:00
|
|
|
|
2023-06-11 07:12:40 +00:00
|
|
|
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("listen", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] CQ command execution error", e=err, command=received_json
|
|
|
|
)
|
2023-02-10 11:12:18 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_record_audio(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
if not AudioParam.audio_record:
|
2023-05-06 14:13:46 +00:00
|
|
|
AudioParam.audio_record_file = wave.open(f"{int(time.time())}_audio_recording.wav", 'w')
|
|
|
|
AudioParam.audio_record_file.setnchannels(1)
|
|
|
|
AudioParam.audio_record_file.setsampwidth(2)
|
|
|
|
AudioParam.audio_record_file.setframerate(8000)
|
2023-04-27 19:43:56 +00:00
|
|
|
AudioParam.audio_record = True
|
2023-02-09 20:43:49 +00:00
|
|
|
else:
|
2023-04-27 19:43:56 +00:00
|
|
|
AudioParam.audio_record = False
|
2023-05-06 14:13:46 +00:00
|
|
|
AudioParam.audio_record_file.close()
|
2022-03-31 19:13:30 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("respond_to_call", True)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("respond_to_call", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] CQ command execution error", e=err, command=received_json
|
|
|
|
)
|
2022-05-09 01:27:24 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_respond_to_call(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
TNC.respond_to_call = received_json["state"] in ['true', 'True', True]
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("respond_to_call", True)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("respond_to_call", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] CQ command execution error", e=err, command=received_json
|
|
|
|
)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_respond_to_cq(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
TNC.respond_to_cq = received_json["state"] in ['true', 'True', True]
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("respond_to_cq", True)
|
2022-02-21 11:20:36 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("respond_to_cq", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] CQ command execution error", e=err, command=received_json
|
|
|
|
)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_tx_audio_level(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
AudioParam.tx_audio_level = int(received_json["value"])
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("tx_audio_level", True)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("tx_audio_level", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] TX audio command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2022-11-18 09:09:16 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_send_test_frame(self, received_json):
|
|
|
|
try:
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
|
|
|
command_response("send_test_frame", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("send_test_frame", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send test frame command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 11:12:18 +00:00
|
|
|
|
2023-02-12 16:39:13 +00:00
|
|
|
def tnc_fec_transmit(self, received_json):
|
|
|
|
try:
|
|
|
|
mode = received_json["mode"]
|
2023-05-14 16:05:47 +00:00
|
|
|
wakeup = received_json["wakeup"]
|
2023-02-12 16:48:01 +00:00
|
|
|
base64data = received_json["payload"]
|
|
|
|
if len(base64data) % 4:
|
|
|
|
raise TypeError
|
|
|
|
payload = base64.b64decode(base64data)
|
2023-02-12 16:39:13 +00:00
|
|
|
|
2023-05-14 16:12:06 +00:00
|
|
|
try:
|
|
|
|
mycallsign = received_json["mycallsign"]
|
|
|
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
|
|
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
mycallsign = Station.mycallsign
|
|
|
|
|
|
|
|
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["FEC", mode, wakeup, payload, mycallsign])
|
2023-02-12 16:39:13 +00:00
|
|
|
command_response("fec_transmit", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("fec_transmit", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send fec frame command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
|
|
|
|
2023-02-12 17:24:42 +00:00
|
|
|
def tnc_fec_is_writing(self, received_json):
|
|
|
|
try:
|
|
|
|
mycallsign = received_json["mycallsign"]
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["FEC_IS_WRITING", mycallsign])
|
|
|
|
command_response("fec_is_writing", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("fec_is_writing", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send fec frame command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_cqcqcq(self, received_json):
|
|
|
|
try:
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["CQ"])
|
|
|
|
command_response("cqcqcq", True)
|
2022-03-04 15:50:32 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("cqcqcq", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] CQ command execution error", e=err, command=received_json
|
|
|
|
)
|
2022-11-20 10:44:29 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_start_beacon(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_state = True
|
2023-02-09 20:43:49 +00:00
|
|
|
interval = int(received_json["parameter"])
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["BEACON", interval, True])
|
|
|
|
command_response("start_beacon", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("start_beacon", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Start beacon command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 11:12:18 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_stop_beacon(self, received_json):
|
|
|
|
try:
|
|
|
|
log.warning("[SCK] Stopping beacon!")
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_state = False
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(["BEACON", None, False])
|
|
|
|
command_response("stop_beacon", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("stop_beacon", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Stop beacon command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-02-10 11:12:18 +00:00
|
|
|
|
2023-06-11 07:12:40 +00:00
|
|
|
|
|
|
|
def tnc_mesh_ping(self, received_json):
|
|
|
|
# send ping frame and wait for ACK
|
|
|
|
try:
|
|
|
|
dxcallsign = received_json["dxcallsign"]
|
|
|
|
if not str(dxcallsign).strip():
|
|
|
|
raise NoCallsign
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
# check if specific callsign is set with different SSID than the TNC is initialized
|
|
|
|
try:
|
|
|
|
mycallsign = received_json["mycallsign"]
|
|
|
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
|
|
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
mycallsign = Station.mycallsign
|
|
|
|
|
|
|
|
MESH_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign])
|
|
|
|
command_response("ping", True)
|
|
|
|
except NoCallsign:
|
|
|
|
command_response("ping", False)
|
|
|
|
log.warning("[SCK] callsign required for ping", command=received_json)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("ping", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] PING command execution error", e=err, command=received_json
|
|
|
|
)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_ping_ping(self, received_json):
|
|
|
|
# send ping frame and wait for ACK
|
2023-05-06 14:07:33 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
try:
|
2022-11-18 09:09:16 +00:00
|
|
|
dxcallsign = received_json["dxcallsign"]
|
2023-02-09 20:43:49 +00:00
|
|
|
if not str(dxcallsign).strip():
|
|
|
|
raise NoCallsign
|
|
|
|
|
|
|
|
# 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)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-12-04 12:01:09 +00:00
|
|
|
# check if specific callsign is set with different SSID than the TNC is initialized
|
|
|
|
try:
|
2022-12-05 15:57:45 +00:00
|
|
|
mycallsign = received_json["mycallsign"]
|
2022-12-04 12:01:09 +00:00
|
|
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
|
|
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
|
|
|
|
|
|
|
except Exception:
|
2023-04-27 19:43:56 +00:00
|
|
|
mycallsign = Station.mycallsign
|
2022-12-04 12:01:09 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(["PING", mycallsign, dxcallsign])
|
|
|
|
command_response("ping", True)
|
|
|
|
except NoCallsign:
|
|
|
|
command_response("ping", False)
|
|
|
|
log.warning("[SCK] callsign required for ping", command=received_json)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("ping", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] PING command execution error", e=err, command=received_json
|
|
|
|
)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_arq_connect(self, received_json):
|
2022-11-18 09:29:20 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# pause our beacon first
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_pause = True
|
2022-11-18 09:29:20 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# check for connection attempts key
|
|
|
|
try:
|
|
|
|
attempts = int(received_json["attempts"])
|
|
|
|
except Exception:
|
|
|
|
# 15 == self.session_connect_max_retries
|
|
|
|
attempts = 15
|
2022-11-18 09:29:20 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
dxcallsign = received_json["dxcallsign"]
|
2022-11-18 09:09:16 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# check if specific callsign is set with different SSID than the TNC is initialized
|
|
|
|
try:
|
|
|
|
mycallsign = received_json["mycallsign"]
|
|
|
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
|
|
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
|
|
|
|
|
|
|
except Exception:
|
2023-04-27 19:43:56 +00:00
|
|
|
mycallsign = Station.mycallsign
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
2023-04-27 19:43:56 +00:00
|
|
|
if ARQ.arq_session_state not in ["disconnected", "failed"]:
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("connect", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Connect command execution error",
|
2023-04-27 19:43:56 +00:00
|
|
|
e=f"already connected to station:{Station.dxcallsign}",
|
2023-02-09 20:43:49 +00:00
|
|
|
command=received_json,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
|
|
|
|
# finally check again if we are disconnected or failed
|
2022-11-20 11:54:59 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# try connecting
|
2022-03-04 15:50:32 +00:00
|
|
|
try:
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
DATA_QUEUE_TRANSMIT.put(["CONNECT", mycallsign, dxcallsign, attempts])
|
|
|
|
command_response("connect", True)
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("connect", False)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.warning(
|
2023-02-09 20:43:49 +00:00
|
|
|
"[SCK] Connect command execution error",
|
2022-06-24 18:55:59 +00:00
|
|
|
e=err,
|
|
|
|
command=received_json,
|
2022-05-26 01:23:30 +00:00
|
|
|
)
|
2023-02-09 20:43:49 +00:00
|
|
|
# allow beacon transmission again
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_pause = False
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# allow beacon transmission again
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_pause = False
|
2022-11-20 10:44:29 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_arq_disconnect(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
if ARQ.arq_session_state not in ["disconnecting", "disconnected", "failed"]:
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(["DISCONNECT"])
|
2023-01-29 16:50:57 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# set early disconnecting state so we can interrupt connection attempts
|
2023-04-27 19:43:56 +00:00
|
|
|
ARQ.arq_session_state = "disconnecting"
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("disconnect", True)
|
|
|
|
else:
|
|
|
|
command_response("disconnect", False)
|
2023-05-08 14:13:37 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("disconnect", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Disconnect command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-01-22 14:19:42 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_arq_send_raw(self, received_json):
|
2023-04-27 19:43:56 +00:00
|
|
|
Beacon.beacon_pause = True
|
2022-12-04 11:22:35 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# wait some random time
|
|
|
|
helpers.wait(randrange(5, 25, 5) / 10.0)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-05-14 07:20:39 +00:00
|
|
|
# TODO: carefully test this
|
|
|
|
# avoid sending data while we are receiving codec2 signalling data
|
|
|
|
interrupt_time = time.time() + 5
|
|
|
|
while ModemParam.is_codec2_traffic and time.time() < interrupt_time:
|
|
|
|
threading.Event().wait(0.01)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# we need to warn if already in arq state
|
2023-04-27 19:43:56 +00:00
|
|
|
if ARQ.arq_state:
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("send_raw", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send raw command execution warning",
|
|
|
|
e="already in arq state",
|
|
|
|
i="command queued",
|
|
|
|
command=received_json,
|
|
|
|
)
|
2022-11-20 11:02:53 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
if not ARQ.arq_session:
|
2023-02-09 20:43:49 +00:00
|
|
|
dxcallsign = received_json["parameter"][0]["dxcallsign"]
|
|
|
|
# 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)
|
2023-05-09 13:04:23 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("send_raw", True)
|
|
|
|
else:
|
2023-04-27 19:43:56 +00:00
|
|
|
dxcallsign = Station.dxcallsign
|
|
|
|
Station.dxcallsign_crc = helpers.get_crc_24(Station.dxcallsign)
|
2022-11-20 10:44:29 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
base64data = received_json["parameter"][0]["data"]
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# check if specific callsign is set with different SSID than the TNC is initialized
|
|
|
|
try:
|
|
|
|
mycallsign = received_json["parameter"][0]["mycallsign"]
|
|
|
|
mycallsign = helpers.callsign_to_bytes(mycallsign)
|
|
|
|
mycallsign = helpers.bytes_to_callsign(mycallsign)
|
2022-06-24 18:55:59 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception:
|
2023-04-27 19:43:56 +00:00
|
|
|
mycallsign = Station.mycallsign
|
2022-06-24 18:55:59 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# check for connection attempts key
|
|
|
|
try:
|
|
|
|
attempts = int(received_json["parameter"][0]["attempts"])
|
2022-06-24 18:55:59 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
except Exception:
|
|
|
|
attempts = 10
|
2022-04-11 09:10:32 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# check if transmission uuid provided else set no-uuid
|
2022-01-30 13:16:08 +00:00
|
|
|
try:
|
2023-02-09 20:43:49 +00:00
|
|
|
arq_uuid = received_json["uuid"]
|
|
|
|
except Exception:
|
|
|
|
arq_uuid = "no-uuid"
|
|
|
|
|
|
|
|
if len(base64data) % 4:
|
|
|
|
raise TypeError
|
|
|
|
|
|
|
|
binarydata = base64.b64decode(base64data)
|
2023-08-06 21:08:55 +00:00
|
|
|
# check if hmac hash is provided
|
|
|
|
try:
|
2023-08-08 06:27:22 +00:00
|
|
|
log.info("[SCK] [HMAC] Looking for salt/token", local=mycallsign, remote=dxcallsign)
|
2023-08-06 21:08:55 +00:00
|
|
|
hmac_salt = helpers.get_hmac_salt(dxcallsign, mycallsign)
|
2023-08-19 08:54:36 +00:00
|
|
|
log.info("[SCK] [HMAC] Salt info", local=mycallsign, remote=dxcallsign, salt=hmac_salt)
|
2023-08-06 21:08:55 +00:00
|
|
|
except Exception:
|
2023-08-08 06:27:22 +00:00
|
|
|
log.warning("[SCK] [HMAC] No salt/token found")
|
2023-08-06 21:08:55 +00:00
|
|
|
hmac_salt = ''
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(
|
2023-08-06 21:08:55 +00:00
|
|
|
["ARQ_RAW", binarydata, arq_uuid, mycallsign, dxcallsign, attempts, hmac_salt]
|
2023-02-09 20:43:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
except Exception as err:
|
|
|
|
command_response("send_raw", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send raw command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_arq_stop_transmission(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
if TNC.tnc_state == "BUSY" or ARQ.arq_state:
|
2023-02-09 20:43:49 +00:00
|
|
|
DATA_QUEUE_TRANSMIT.put(["STOP"])
|
|
|
|
log.warning("[SCK] Stopping transmission!")
|
2023-04-27 19:43:56 +00:00
|
|
|
TNC.tnc_state = "IDLE"
|
|
|
|
ARQ.arq_state = False
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("stop_transmission", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("stop_transmission", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] STOP command execution error", e=err, command=received_json
|
|
|
|
)
|
|
|
|
|
2023-05-28 10:13:19 +00:00
|
|
|
def tnc_get_mesh_routing_table(self, received_json):
|
|
|
|
try:
|
2023-10-11 18:26:44 +00:00
|
|
|
output = {
|
|
|
|
"command": "routing_table",
|
|
|
|
"routes": [],
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, route in enumerate(MeshParam.routing_table):
|
|
|
|
if MeshParam.routing_table[_][0].hex() == helpers.get_crc_24(b"direct").hex():
|
|
|
|
router = "direct"
|
|
|
|
else:
|
|
|
|
router = MeshParam.routing_table[_][0].hex()
|
|
|
|
output["routes"].append(
|
|
|
|
{
|
|
|
|
"dxcall": MeshParam.routing_table[_][0].hex(),
|
|
|
|
"router": router,
|
|
|
|
"hops": MeshParam.routing_table[_][2],
|
|
|
|
"snr": MeshParam.routing_table[_][3],
|
|
|
|
"score": MeshParam.routing_table[_][4],
|
|
|
|
"timestamp": MeshParam.routing_table[_][5],
|
|
|
|
}
|
|
|
|
)
|
2023-05-28 10:13:19 +00:00
|
|
|
|
|
|
|
|
2023-10-11 18:26:44 +00:00
|
|
|
jsondata = json.dumps(output)
|
|
|
|
# self.request.sendall(bytes(jsondata, encoding))
|
|
|
|
SOCKET_QUEUE.put(jsondata)
|
|
|
|
command_response("routing_table", True)
|
2023-05-28 10:13:19 +00:00
|
|
|
|
|
|
|
except Exception as err:
|
|
|
|
command_response("routing_table", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send RX buffer command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_get_rx_buffer(self, received_json):
|
2023-02-10 11:12:18 +00:00
|
|
|
try:
|
|
|
|
if not RX_BUFFER.empty():
|
2023-10-11 18:26:44 +00:00
|
|
|
# TODO: REMOVE DEPRECATED MESSAGES
|
|
|
|
#output = {
|
|
|
|
# "command": "rx_buffer",
|
|
|
|
# "data-array": [],
|
|
|
|
#}#
|
|
|
|
|
|
|
|
#for _buffer_length in range(RX_BUFFER.qsize()):
|
|
|
|
# base64_data = RX_BUFFER.queue[_buffer_length][4]
|
|
|
|
# output["data-array"].append(
|
|
|
|
# {
|
|
|
|
# "uuid": RX_BUFFER.queue[_buffer_length][0],
|
|
|
|
# "timestamp": RX_BUFFER.queue[_buffer_length][1],
|
|
|
|
# "dxcallsign": str(RX_BUFFER.queue[_buffer_length][2], "utf-8"),
|
|
|
|
# "dxgrid": str(RX_BUFFER.queue[_buffer_length][3], "utf-8"),
|
|
|
|
# "data": base64_data,
|
|
|
|
# }
|
|
|
|
# )
|
|
|
|
#jsondata = json.dumps(output)
|
|
|
|
## self.request.sendall(bytes(jsondata, encoding))
|
|
|
|
#SOCKET_QUEUE.put(jsondata)
|
|
|
|
#command_response("rx_buffer", True)
|
|
|
|
|
|
|
|
|
|
|
|
# REQUEST REQUEST RX BUFFER AGAIN
|
|
|
|
# NEW BEHAVIOUR IS, PUSHING DATA TO NETWORK LIKE WE RECEIVED IT
|
|
|
|
# RX_BUFFER[0] = transmission uuid
|
|
|
|
# RX_BUFFER[1] = timestamp
|
|
|
|
# RX_BUFFER[2] = dxcallsign
|
|
|
|
# RX_BUFFER[3] = dxgrid
|
|
|
|
# RX_BUFFER[4] = data
|
|
|
|
# RX_BUFFER[5] = hmac signed
|
|
|
|
# RX_BUFFER[6] = compression factor
|
|
|
|
# RX_BUFFER[7] = bytes per minute
|
|
|
|
# RX_BUFFER[8] = duration
|
|
|
|
# RX_BUFFER[9] = self.frame_nack_counter
|
|
|
|
# RX_BUFFER[10] = speed list stats
|
2023-02-10 11:12:18 +00:00
|
|
|
for _buffer_length in range(RX_BUFFER.qsize()):
|
2023-10-11 18:26:44 +00:00
|
|
|
output = {
|
|
|
|
"freedata" : "tnc-message",
|
|
|
|
"arq" : "transmission",
|
|
|
|
"status" : "received",
|
|
|
|
"uuid" : RX_BUFFER.queue[_buffer_length][0],
|
|
|
|
"percent" : 100,
|
|
|
|
"bytesperminute" : RX_BUFFER.queue[_buffer_length][7],
|
|
|
|
"compression" : RX_BUFFER.queue[_buffer_length][6],
|
|
|
|
"timestamp" : RX_BUFFER.queue[_buffer_length][1],
|
|
|
|
"finished" : 0,
|
|
|
|
"mycallsign" : str(Station.mycallsign, "UTF-8"),
|
|
|
|
"dxcallsign" : str(RX_BUFFER.queue[_buffer_length][2], "utf-8"),
|
|
|
|
"dxgrid" : str(RX_BUFFER.queue[_buffer_length][3], "utf-8"),
|
|
|
|
"data" : RX_BUFFER.queue[_buffer_length][4],
|
|
|
|
"irs" : RX_BUFFER.queue[_buffer_length][5],
|
|
|
|
"hmac_signed" : "False",
|
|
|
|
"duration" : RX_BUFFER.queue[_buffer_length][8],
|
|
|
|
"nacks" : RX_BUFFER.queue[_buffer_length][9],
|
|
|
|
"speed_list" : RX_BUFFER.queue[_buffer_length][10]
|
|
|
|
}
|
|
|
|
|
|
|
|
jsondata = json.dumps(output)
|
|
|
|
SOCKET_QUEUE.put(jsondata)
|
|
|
|
print(jsondata)
|
|
|
|
|
|
|
|
command_response("rx_buffer", True)
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-10 11:12:18 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("rx_buffer", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Send RX buffer command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_del_rx_buffer(self, received_json):
|
|
|
|
try:
|
|
|
|
RX_BUFFER.queue.clear()
|
|
|
|
command_response("del_rx_buffer", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("del_rx_buffer", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Delete RX buffer command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2022-01-30 13:16:08 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_mode(self, received_json):
|
|
|
|
try:
|
|
|
|
RIGCTLD_COMMAND_QUEUE.put(["set_mode", received_json["mode"]])
|
|
|
|
command_response("set_mode", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("set_mode", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Set mode command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-01-04 19:12:03 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def tnc_set_frequency(self, received_json):
|
|
|
|
try:
|
|
|
|
RIGCTLD_COMMAND_QUEUE.put(["set_frequency", received_json["frequency"]])
|
|
|
|
command_response("set_frequency", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("set_frequency", False)
|
|
|
|
log.warning(
|
|
|
|
"[SCK] Set frequency command execution error",
|
|
|
|
e=err,
|
|
|
|
command=received_json,
|
|
|
|
)
|
2023-01-04 18:26:11 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# ------------------------ DAEMON COMMANDS
|
|
|
|
def process_daemon_commands(self, data):
|
|
|
|
"""
|
|
|
|
process daemon commands
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
Args:
|
|
|
|
data:
|
2022-03-04 15:50:32 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
Returns:
|
2022-03-04 15:50:32 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
"""
|
|
|
|
log = structlog.get_logger("process_daemon_commands")
|
2022-03-04 15:50:32 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
# convert data to json object
|
|
|
|
received_json = json.loads(data)
|
|
|
|
log.debug("[SCK] CMD", command=received_json)
|
|
|
|
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "mycallsign":
|
|
|
|
self.daemon_set_mycallsign(received_json)
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
if received_json["type"] == "set" and received_json["command"] == "mygrid":
|
|
|
|
self.daemon_set_mygrid(received_json)
|
|
|
|
|
|
|
|
if (
|
2023-02-10 11:12:18 +00:00
|
|
|
received_json["type"] == "set"
|
|
|
|
and received_json["command"] == "start_tnc"
|
2023-04-27 19:43:56 +00:00
|
|
|
and not Daemon.tncstarted
|
2023-02-09 20:43:49 +00:00
|
|
|
):
|
|
|
|
self.daemon_start_tnc(received_json)
|
|
|
|
|
|
|
|
if received_json["type"] == "get" and received_json["command"] == "test_hamlib":
|
|
|
|
self.daemon_test_hamlib(received_json)
|
|
|
|
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "stop_tnc":
|
|
|
|
self.daemon_stop_tnc(received_json)
|
|
|
|
|
2023-10-08 20:09:09 +00:00
|
|
|
if received_json["type"] == "set" and received_json["command"] == "start_rigctld" and not Daemon.rigctldstarted:
|
2023-10-08 19:09:30 +00:00
|
|
|
self.daemon_start_rigctld(received_json)
|
|
|
|
|
|
|
|
if received_json["type"] == "set" and received_json["command"] == "stop_rigctld":
|
|
|
|
self.daemon_stop_rigctld(received_json)
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def daemon_set_mycallsign(self, received_json):
|
2022-01-30 13:16:08 +00:00
|
|
|
try:
|
|
|
|
callsign = received_json["parameter"]
|
2022-03-06 16:23:04 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
if bytes(callsign, "utf-8") == b"":
|
|
|
|
self.request.sendall(b"INVALID CALLSIGN")
|
|
|
|
log.warning(
|
2022-06-24 18:55:59 +00:00
|
|
|
"[SCK] SET MYCALL FAILED",
|
2023-04-27 19:43:56 +00:00
|
|
|
call=Station.mycallsign,
|
|
|
|
crc=Station.mycallsign_crc.hex(),
|
2022-05-26 01:23:30 +00:00
|
|
|
)
|
2022-01-30 13:16:08 +00:00
|
|
|
else:
|
2023-04-27 19:43:56 +00:00
|
|
|
Station.mycallsign = bytes(callsign, "utf-8")
|
|
|
|
Station.mycallsign_crc = helpers.get_crc_24(Station.mycallsign)
|
2022-01-20 19:38:56 +00:00
|
|
|
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("mycallsign", True)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.info(
|
2022-06-24 18:55:59 +00:00
|
|
|
"[SCK] SET MYCALL",
|
2023-04-27 19:43:56 +00:00
|
|
|
call=Station.mycallsign,
|
|
|
|
crc=Station.mycallsign_crc.hex(),
|
2022-05-26 01:23:30 +00:00
|
|
|
)
|
|
|
|
except Exception as err:
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("mycallsign", False)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def daemon_set_mygrid(self, received_json):
|
2022-01-30 13:16:08 +00:00
|
|
|
try:
|
|
|
|
mygrid = received_json["parameter"]
|
2022-01-20 19:38:56 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
if bytes(mygrid, "utf-8") == b"":
|
|
|
|
self.request.sendall(b"INVALID GRID")
|
2022-06-24 18:55:59 +00:00
|
|
|
command_response("mygrid", False)
|
2022-01-30 13:16:08 +00:00
|
|
|
else:
|
2023-04-27 19:43:56 +00:00
|
|
|
Station.mygrid = bytes(mygrid, "utf-8")
|
|
|
|
log.info("[SCK] SET MYGRID", grid=Station.mygrid)
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("mygrid", True)
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("mygrid", False)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def daemon_start_tnc(self, received_json):
|
2022-01-30 13:16:08 +00:00
|
|
|
try:
|
2023-02-02 21:41:35 +00:00
|
|
|
startparam = received_json["parameter"][0]
|
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
mycall = str(helpers.return_key_from_object("AA0AA", startparam, "mycall"))
|
|
|
|
mygrid = str(helpers.return_key_from_object("JN12ab", startparam, "mygrid"))
|
|
|
|
rx_audio = str(helpers.return_key_from_object("0", startparam, "rx_audio"))
|
|
|
|
tx_audio = str(helpers.return_key_from_object("0", startparam, "tx_audio"))
|
|
|
|
radiocontrol = str(helpers.return_key_from_object("disabled", startparam, "radiocontrol"))
|
|
|
|
rigctld_ip = str(helpers.return_key_from_object("127.0.0.1", startparam, "rigctld_ip"))
|
|
|
|
rigctld_port = str(helpers.return_key_from_object("4532", startparam, "rigctld_port"))
|
|
|
|
enable_scatter = str(helpers.return_key_from_object("True", startparam, "enable_scatter"))
|
|
|
|
enable_fft = str(helpers.return_key_from_object("True", startparam, "enable_fft"))
|
|
|
|
enable_fsk = str(helpers.return_key_from_object("False", startparam, "enable_fsk"))
|
|
|
|
low_bandwidth_mode = str(helpers.return_key_from_object("False", startparam, "low_bandwidth_mode"))
|
|
|
|
tuning_range_fmin = str(helpers.return_key_from_object("-50", startparam, "tuning_range_fmin"))
|
|
|
|
tuning_range_fmax = str(helpers.return_key_from_object("50", startparam, "tuning_range_fmax"))
|
|
|
|
tx_audio_level = str(helpers.return_key_from_object("100", startparam, "tx_audio_level"))
|
|
|
|
respond_to_cq = str(helpers.return_key_from_object("False", startparam, "respond_to_cq"))
|
|
|
|
rx_buffer_size = str(helpers.return_key_from_object("16", startparam, "rx_buffer_size"))
|
|
|
|
enable_explorer = str(helpers.return_key_from_object("False", startparam, "enable_explorer"))
|
|
|
|
enable_auto_tune = str(helpers.return_key_from_object("False", startparam, "enable_auto_tune"))
|
|
|
|
enable_stats = str(helpers.return_key_from_object("False", startparam, "enable_stats"))
|
2023-03-06 11:48:27 +00:00
|
|
|
tx_delay = str(helpers.return_key_from_object("0", startparam, "tx_delay"))
|
2023-05-24 13:29:12 +00:00
|
|
|
tci_ip = str(helpers.return_key_from_object("127.0.0.1", startparam, "tci_ip"))
|
|
|
|
tci_port = str(helpers.return_key_from_object("50001", startparam, "tci_port"))
|
2023-07-03 15:54:24 +00:00
|
|
|
enable_mesh = str(helpers.return_key_from_object("False", startparam, "enable_mesh"))
|
2022-12-08 17:09:13 +00:00
|
|
|
try:
|
|
|
|
# convert ssid list to python list
|
2023-02-02 22:49:52 +00:00
|
|
|
ssid_list = str(helpers.return_key_from_object("0, 1, 2, 3, 4, 5, 6, 7, 8, 9", startparam, "ssid_list"))
|
2022-12-08 17:09:13 +00:00
|
|
|
ssid_list = ssid_list.replace(" ", "")
|
|
|
|
ssid_list = ssid_list.split(",")
|
|
|
|
# convert str to int
|
|
|
|
ssid_list = list(map(int, ssid_list))
|
|
|
|
except KeyError:
|
2023-02-02 22:49:52 +00:00
|
|
|
ssid_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
2022-12-08 15:26:33 +00:00
|
|
|
|
2022-04-02 16:40:12 +00:00
|
|
|
# print some debugging parameters
|
2023-02-02 22:49:52 +00:00
|
|
|
for item in startparam:
|
2022-05-26 01:23:30 +00:00
|
|
|
log.debug(
|
2022-06-24 18:55:59 +00:00
|
|
|
f"[SCK] TNC Startup Config : {item}",
|
2023-02-02 22:49:52 +00:00
|
|
|
value=startparam[item],
|
2022-05-26 01:23:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
DAEMON_QUEUE.put(
|
|
|
|
[
|
|
|
|
"STARTTNC",
|
|
|
|
mycall,
|
|
|
|
mygrid,
|
|
|
|
rx_audio,
|
|
|
|
tx_audio,
|
|
|
|
radiocontrol,
|
|
|
|
rigctld_ip,
|
|
|
|
rigctld_port,
|
|
|
|
enable_scatter,
|
|
|
|
enable_fft,
|
2022-05-28 15:52:05 +00:00
|
|
|
low_bandwidth_mode,
|
2022-05-26 01:23:30 +00:00
|
|
|
tuning_range_fmin,
|
|
|
|
tuning_range_fmax,
|
|
|
|
enable_fsk,
|
|
|
|
tx_audio_level,
|
|
|
|
respond_to_cq,
|
2022-09-05 09:54:50 +00:00
|
|
|
rx_buffer_size,
|
2022-11-05 21:27:33 +00:00
|
|
|
enable_explorer,
|
2022-12-08 15:26:33 +00:00
|
|
|
ssid_list,
|
2023-02-01 15:11:07 +00:00
|
|
|
enable_auto_tune,
|
2023-03-06 11:48:27 +00:00
|
|
|
enable_stats,
|
2023-05-24 13:29:12 +00:00
|
|
|
tx_delay,
|
|
|
|
tci_ip,
|
2023-07-03 15:54:24 +00:00
|
|
|
tci_port,
|
|
|
|
enable_mesh
|
2022-05-26 01:23:30 +00:00
|
|
|
]
|
|
|
|
)
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("start_tnc", True)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
2022-05-09 00:41:49 +00:00
|
|
|
command_response("start_tnc", False)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
2022-01-22 19:39:37 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def daemon_stop_tnc(self, received_json):
|
|
|
|
try:
|
2023-04-27 19:43:56 +00:00
|
|
|
Daemon.tncprocess.kill()
|
2023-02-09 20:43:49 +00:00
|
|
|
# unregister process from atexit to avoid process zombies
|
2023-04-27 19:43:56 +00:00
|
|
|
atexit.unregister(Daemon.tncprocess.kill)
|
2023-02-09 20:43:49 +00:00
|
|
|
|
|
|
|
log.warning("[SCK] Stopping TNC")
|
2023-04-27 19:43:56 +00:00
|
|
|
Daemon.tncstarted = False
|
2023-02-09 20:43:49 +00:00
|
|
|
command_response("stop_tnc", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("stop_tnc", False)
|
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
|
|
|
|
|
|
|
def daemon_test_hamlib(self, received_json):
|
2022-01-30 13:16:08 +00:00
|
|
|
try:
|
|
|
|
radiocontrol = str(received_json["parameter"][0]["radiocontrol"])
|
|
|
|
rigctld_ip = str(received_json["parameter"][0]["rigctld_ip"])
|
|
|
|
rigctld_port = str(received_json["parameter"][0]["rigctld_port"])
|
2022-02-08 14:27:34 +00:00
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
DAEMON_QUEUE.put(
|
|
|
|
[
|
|
|
|
"TEST_HAMLIB",
|
|
|
|
radiocontrol,
|
|
|
|
rigctld_ip,
|
|
|
|
rigctld_port,
|
|
|
|
]
|
|
|
|
)
|
2022-03-08 07:44:19 +00:00
|
|
|
command_response("test_hamlib", True)
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
2022-05-09 00:41:49 +00:00
|
|
|
command_response("test_hamlib", False)
|
2022-05-26 01:23:30 +00:00
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-10-08 19:09:30 +00:00
|
|
|
def daemon_start_rigctld(self, received_json):
|
|
|
|
"""
|
|
|
|
hamlib_deviceid: settings.hamlib_deviceid,
|
|
|
|
hamlib_deviceport: settings.hamlib_deviceport,
|
|
|
|
hamlib_stop_bits: settings.hamlib_stop_bits,
|
|
|
|
hamlib_data_bits: settings.hamlib_data_bits,
|
|
|
|
hamlib_handshake: settings.hamlib_handshake,
|
|
|
|
hamlib_serialspeed: settings.hamlib_serialspeed,
|
|
|
|
hamlib_dtrstate: settings.hamlib_dtrstate,
|
|
|
|
hamlib_pttprotocol: settings.hamlib_pttprotocol,
|
|
|
|
hamlib_ptt_port: settings.hamlib_ptt_port,
|
|
|
|
hamlib_dcd: settings.hamlib_dcd,
|
|
|
|
hamlbib_serialspeed_ptt: settings.hamlib_serialspeed,
|
|
|
|
hamlib_rigctld_port: settings.hamlib_rigctld_port,
|
|
|
|
hamlib_rigctld_ip: settings.hamlib_rigctld_ip,
|
|
|
|
hamlib_rigctld_path: settings.hamlib_rigctld_path,
|
|
|
|
hamlib_rigctld_server_port: settings.hamlib_rigctld_server_port,
|
|
|
|
hamlib_rigctld_custom_args: settings.hamlib_rigctld_custom_args
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
|
|
|
|
hamlib_deviceid = str(received_json["parameter"][0]["hamlib_deviceid"])
|
|
|
|
hamlib_deviceport = str(received_json["parameter"][0]["hamlib_deviceport"])
|
|
|
|
hamlib_stop_bits = str(received_json["parameter"][0]["hamlib_stop_bits"])
|
|
|
|
hamlib_data_bits = str(received_json["parameter"][0]["hamlib_data_bits"])
|
|
|
|
hamlib_handshake = str(received_json["parameter"][0]["hamlib_handshake"])
|
|
|
|
hamlib_serialspeed = str(received_json["parameter"][0]["hamlib_serialspeed"])
|
|
|
|
hamlib_dtrstate = str(received_json["parameter"][0]["hamlib_dtrstate"])
|
|
|
|
hamlib_pttprotocol = str(received_json["parameter"][0]["hamlib_pttprotocol"])
|
|
|
|
hamlib_ptt_port = str(received_json["parameter"][0]["hamlib_ptt_port"])
|
|
|
|
hamlib_dcd = str(received_json["parameter"][0]["hamlib_dcd"])
|
|
|
|
hamlbib_serialspeed_ptt = str(received_json["parameter"][0]["hamlib_serialspeed"])
|
|
|
|
hamlib_rigctld_port = str(received_json["parameter"][0]["hamlib_rigctld_port"])
|
|
|
|
hamlib_rigctld_ip = str(received_json["parameter"][0]["hamlib_rigctld_ip"])
|
|
|
|
hamlib_rigctld_path = str(received_json["parameter"][0]["hamlib_rigctld_path"])
|
|
|
|
hamlib_rigctld_server_port = str(received_json["parameter"][0]["hamlib_rigctld_server_port"])
|
|
|
|
hamlib_rigctld_custom_args = str(received_json["parameter"][0]["hamlib_rigctld_custom_args"])
|
|
|
|
|
|
|
|
DAEMON_QUEUE.put(
|
|
|
|
[
|
|
|
|
"START_RIGCTLD",
|
|
|
|
hamlib_deviceid,
|
|
|
|
hamlib_deviceport,
|
|
|
|
hamlib_stop_bits,
|
|
|
|
hamlib_data_bits,
|
|
|
|
hamlib_handshake,
|
|
|
|
hamlib_serialspeed,
|
|
|
|
hamlib_dtrstate,
|
|
|
|
hamlib_pttprotocol,
|
|
|
|
hamlib_ptt_port,
|
|
|
|
hamlib_dcd,
|
|
|
|
hamlbib_serialspeed_ptt,
|
|
|
|
hamlib_rigctld_port,
|
|
|
|
hamlib_rigctld_ip,
|
|
|
|
hamlib_rigctld_path,
|
|
|
|
hamlib_rigctld_server_port,
|
|
|
|
hamlib_rigctld_custom_args
|
|
|
|
]
|
|
|
|
)
|
|
|
|
command_response("start_rigctld", True)
|
|
|
|
except Exception as err:
|
|
|
|
command_response("start_rigctld", False)
|
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
|
|
|
|
|
|
|
|
|
|
|
def daemon_stop_rigctld(self, received_json):
|
|
|
|
|
|
|
|
try:
|
|
|
|
log.warning("[SCK] Stopping rigctld")
|
|
|
|
|
2023-10-08 20:09:09 +00:00
|
|
|
if Daemon.rigctldstarted:
|
|
|
|
Daemon.rigctldprocess.kill()
|
|
|
|
# unregister process from atexit to avoid process zombies
|
|
|
|
atexit.unregister(Daemon.rigctldprocess.kill)
|
2023-10-08 19:09:30 +00:00
|
|
|
|
2023-10-08 20:09:09 +00:00
|
|
|
Daemon.rigctldstarted = False
|
|
|
|
command_response("stop_rigctld", True)
|
2023-10-08 19:09:30 +00:00
|
|
|
except Exception as err:
|
|
|
|
command_response("stop_tnc", False)
|
|
|
|
log.warning("[SCK] command execution error", e=err, command=received_json)
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2022-01-22 19:39:37 +00:00
|
|
|
def send_daemon_state():
|
2022-03-04 15:50:32 +00:00
|
|
|
"""
|
|
|
|
send the daemon state to network
|
|
|
|
"""
|
2022-06-01 00:35:35 +00:00
|
|
|
log = structlog.get_logger("send_daemon_state")
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2023-10-17 12:30:34 +00:00
|
|
|
# we need to do some process checking for providing the correct state
|
|
|
|
# at least we are checking the returncode of rigctld
|
|
|
|
# None state means, the process is still running
|
|
|
|
try:
|
|
|
|
retcode_rigctld = Daemon.rigctldprocess.poll()
|
|
|
|
if retcode_rigctld in [None, "None"]:
|
2023-10-17 12:47:03 +00:00
|
|
|
Daemon.rigctldstarted = True
|
|
|
|
# This is a blocking code ....
|
2023-10-17 12:49:13 +00:00
|
|
|
# output, errs = Daemon.rigctldprocess.communicate()
|
|
|
|
# print(f"rigctld out: {output}")
|
|
|
|
# print(f"rigctld err: {errs}")
|
2023-10-17 12:30:34 +00:00
|
|
|
else:
|
|
|
|
# print(f"rigctld closed with code: {retcode_rigctld}")
|
|
|
|
Daemon.rigctldstarted = False
|
|
|
|
|
|
|
|
|
|
|
|
retcode_tnc = Daemon.tncprocess.poll()
|
|
|
|
if retcode_tnc in [None, "None"]:
|
2023-10-17 12:47:03 +00:00
|
|
|
Daemon.tncstarted = True
|
|
|
|
# This is a blocking code ....
|
2023-10-17 12:49:13 +00:00
|
|
|
# output, errs = Daemon.tncprocess.communicate()
|
|
|
|
# print(f"tnc out: {output}")
|
|
|
|
# print(f"tnc err: {errs}")
|
2023-10-17 12:30:34 +00:00
|
|
|
else:
|
|
|
|
# print(f"tnc closed with code: {retcode_tnc}")
|
|
|
|
Daemon.tncstarted = False
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
pass
|
|
|
|
|
2022-02-15 17:10:14 +00:00
|
|
|
try:
|
2022-05-11 22:10:59 +00:00
|
|
|
python_version = f"{str(sys.version_info[0])}.{str(sys.version_info[1])}"
|
2022-02-15 17:10:14 +00:00
|
|
|
|
|
|
|
output = {
|
2022-05-26 01:23:30 +00:00
|
|
|
"command": "daemon_state",
|
|
|
|
"daemon_state": [],
|
2023-10-08 20:09:09 +00:00
|
|
|
"rigctld_state": [],
|
2022-05-26 01:23:30 +00:00
|
|
|
"python_version": str(python_version),
|
2023-04-27 19:43:56 +00:00
|
|
|
"input_devices": AudioParam.audio_input_devices,
|
|
|
|
"output_devices": AudioParam.audio_output_devices,
|
|
|
|
"serial_devices": Daemon.serial_devices,
|
2023-02-10 11:12:18 +00:00
|
|
|
# 'cpu': str(psutil.cpu_percent()),
|
|
|
|
# 'ram': str(psutil.virtual_memory().percent),
|
2023-10-08 20:09:09 +00:00
|
|
|
"version": TNC.version,
|
2022-05-26 01:23:30 +00:00
|
|
|
}
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-04-27 19:43:56 +00:00
|
|
|
if Daemon.tncstarted:
|
2022-02-15 17:10:14 +00:00
|
|
|
output["daemon_state"].append({"status": "running"})
|
|
|
|
else:
|
|
|
|
output["daemon_state"].append({"status": "stopped"})
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-10-08 20:09:09 +00:00
|
|
|
if Daemon.rigctldstarted:
|
|
|
|
output["rigctld_state"].append({"status": "running"})
|
|
|
|
else:
|
|
|
|
output["rigctld_state"].append({"status": "stopped"})
|
|
|
|
|
2022-05-23 12:02:22 +00:00
|
|
|
return json.dumps(output)
|
2022-05-26 01:23:30 +00:00
|
|
|
except Exception as err:
|
|
|
|
log.warning("[SCK] error", e=err)
|
2022-02-17 09:11:12 +00:00
|
|
|
return None
|
2022-05-09 00:41:49 +00:00
|
|
|
|
2023-02-10 11:12:18 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
def send_tnc_state():
|
|
|
|
"""
|
|
|
|
send the tnc state to network
|
|
|
|
"""
|
|
|
|
encoding = "utf-8"
|
|
|
|
output = {
|
|
|
|
"command": "tnc_state",
|
2023-04-27 19:43:56 +00:00
|
|
|
"ptt_state": str(HamlibParam.ptt_state),
|
|
|
|
"tnc_state": str(TNC.tnc_state),
|
|
|
|
"arq_state": str(ARQ.arq_state),
|
|
|
|
"arq_session": str(ARQ.arq_session),
|
|
|
|
"arq_session_state": str(ARQ.arq_session_state),
|
|
|
|
"audio_dbfs": str(AudioParam.audio_dbfs),
|
|
|
|
"snr": str(ModemParam.snr),
|
|
|
|
"frequency": str(HamlibParam.hamlib_frequency),
|
|
|
|
"rf_level": str(HamlibParam.hamlib_rf),
|
|
|
|
"strength": str(HamlibParam.hamlib_strength),
|
|
|
|
"alc": str(HamlibParam.alc),
|
|
|
|
"audio_level": str(AudioParam.tx_audio_level),
|
|
|
|
"audio_auto_tune": str(AudioParam.audio_auto_tune),
|
|
|
|
"speed_level": str(ARQ.arq_speed_level),
|
|
|
|
"mode": str(HamlibParam.hamlib_mode),
|
|
|
|
"bandwidth": str(HamlibParam.hamlib_bandwidth),
|
|
|
|
"fft": str(AudioParam.fft),
|
|
|
|
"channel_busy": str(ModemParam.channel_busy),
|
|
|
|
"channel_busy_slot": str(ModemParam.channel_busy_slot),
|
|
|
|
"is_codec2_traffic": str(ModemParam.is_codec2_traffic),
|
|
|
|
"scatter": ModemParam.scatter,
|
2023-02-09 20:43:49 +00:00
|
|
|
"rx_buffer_length": str(RX_BUFFER.qsize()),
|
2023-04-27 19:43:56 +00:00
|
|
|
"rx_msg_buffer_length": str(len(ARQ.rx_msg_buffer)),
|
|
|
|
"arq_bytes_per_minute": str(ARQ.bytes_per_minute),
|
|
|
|
"arq_bytes_per_minute_burst": str(ARQ.bytes_per_minute_burst),
|
|
|
|
"arq_seconds_until_finish": str(ARQ.arq_seconds_until_finish),
|
2023-09-30 18:29:55 +00:00
|
|
|
"arq_seconds_until_timeout": str(ARQ.arq_seconds_until_timeout),
|
2023-04-27 19:43:56 +00:00
|
|
|
"arq_compression_factor": str(ARQ.arq_compression_factor),
|
|
|
|
"arq_transmission_percent": str(ARQ.arq_transmission_percent),
|
|
|
|
"speed_list": ARQ.speed_list,
|
|
|
|
"total_bytes": str(ARQ.total_bytes),
|
|
|
|
"beacon_state": str(Beacon.beacon_state),
|
2023-02-09 20:43:49 +00:00
|
|
|
"stations": [],
|
2023-05-28 10:16:01 +00:00
|
|
|
"routing_table": [],
|
2023-06-13 12:03:36 +00:00
|
|
|
"mesh_signalling_table" : [],
|
2023-04-27 19:43:56 +00:00
|
|
|
"mycallsign": str(Station.mycallsign, encoding),
|
|
|
|
"mygrid": str(Station.mygrid, encoding),
|
|
|
|
"dxcallsign": str(Station.dxcallsign, encoding),
|
|
|
|
"dxgrid": str(Station.dxgrid, encoding),
|
|
|
|
"hamlib_status": HamlibParam.hamlib_status,
|
|
|
|
"listen": str(TNC.listen),
|
|
|
|
"audio_recording": str(AudioParam.audio_record),
|
2023-10-08 20:09:09 +00:00
|
|
|
|
2023-02-09 20:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# add heard stations to heard stations object
|
2023-04-27 19:43:56 +00:00
|
|
|
for heard in TNC.heard_stations:
|
2023-02-09 20:43:49 +00:00
|
|
|
output["stations"].append(
|
|
|
|
{
|
2023-04-27 19:43:56 +00:00
|
|
|
"dxcallsign": str(heard[0], encoding),
|
|
|
|
"dxgrid": str(heard[1], encoding),
|
2023-02-09 20:43:49 +00:00
|
|
|
"timestamp": heard[2],
|
|
|
|
"datatype": heard[3],
|
|
|
|
"snr": heard[4],
|
|
|
|
"offset": heard[5],
|
|
|
|
"frequency": heard[6],
|
|
|
|
}
|
|
|
|
)
|
2023-05-28 10:16:01 +00:00
|
|
|
|
2023-05-28 10:23:36 +00:00
|
|
|
for _, route in enumerate(MeshParam.routing_table):
|
2023-05-28 14:06:07 +00:00
|
|
|
if MeshParam.routing_table[_][1].hex() == helpers.get_crc_24(b"direct").hex():
|
|
|
|
router = "direct"
|
|
|
|
else:
|
|
|
|
router = MeshParam.routing_table[_][1].hex()
|
2023-05-28 10:16:01 +00:00
|
|
|
output["routing_table"].append(
|
|
|
|
{
|
2023-05-28 14:06:07 +00:00
|
|
|
"dxcall": MeshParam.routing_table[_][0].hex(),
|
|
|
|
"router": router,
|
2023-05-28 10:23:36 +00:00
|
|
|
"hops": MeshParam.routing_table[_][2],
|
|
|
|
"snr": MeshParam.routing_table[_][3],
|
|
|
|
"score": MeshParam.routing_table[_][4],
|
|
|
|
"timestamp": MeshParam.routing_table[_][5],
|
2023-05-28 10:16:01 +00:00
|
|
|
}
|
|
|
|
)
|
2023-06-13 12:03:36 +00:00
|
|
|
|
|
|
|
for _, entry in enumerate(MESH_SIGNALLING_TABLE):
|
|
|
|
|
|
|
|
output["mesh_signalling_table"].append(
|
|
|
|
{
|
|
|
|
"timestamp": MESH_SIGNALLING_TABLE[_][0],
|
|
|
|
"destination": MESH_SIGNALLING_TABLE[_][1],
|
2023-07-09 07:48:50 +00:00
|
|
|
"origin": MESH_SIGNALLING_TABLE[_][2],
|
2023-06-13 12:03:36 +00:00
|
|
|
"frametype": MESH_SIGNALLING_TABLE[_][3],
|
|
|
|
"payload": MESH_SIGNALLING_TABLE[_][4],
|
|
|
|
"attempt": MESH_SIGNALLING_TABLE[_][5],
|
|
|
|
"status": MESH_SIGNALLING_TABLE[_][6],
|
|
|
|
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-05-28 14:06:07 +00:00
|
|
|
#print(output)
|
2023-02-09 20:43:49 +00:00
|
|
|
return json.dumps(output)
|
|
|
|
|
2022-05-26 01:23:30 +00:00
|
|
|
|
2022-03-08 07:44:19 +00:00
|
|
|
def command_response(command, status):
|
2022-05-11 22:10:59 +00:00
|
|
|
s_status = "OK" if status else "Failed"
|
2022-05-26 01:23:30 +00:00
|
|
|
jsondata = {"command_response": command, "status": s_status}
|
2022-06-24 19:22:16 +00:00
|
|
|
data_out = json.dumps(jsondata)
|
2022-03-08 07:44:19 +00:00
|
|
|
SOCKET_QUEUE.put(data_out)
|
2022-12-27 21:57:54 +00:00
|
|
|
|
2023-02-02 21:41:35 +00:00
|
|
|
|
|
|
|
def try_except(string):
|
|
|
|
try:
|
|
|
|
return string
|
|
|
|
except Exception:
|
2023-02-10 11:12:18 +00:00
|
|
|
return False
|