first mesh ping tx part

This commit is contained in:
DJ2LS 2023-06-11 09:12:40 +02:00
parent 415ff0c777
commit 35576bb760
8 changed files with 234 additions and 5 deletions

View file

@ -2983,6 +2983,12 @@ ipcRenderer.on("run-tnc-command", (event, arg) => {
if (arg.command == "responseSharedFile") {
sock.sendResponseSharedFile(arg.dxcallsign, arg.file, arg.filedata);
}
if (arg.command == "mesh_ping") {
sock.sendMeshPing(arg.dxcallsign);
}
});
// IPC ACTION FOR AUTO UPDATER

View file

@ -13,6 +13,21 @@ const config = require(configPath);
// WINDOW LISTENER
window.addEventListener("DOMContentLoaded", () => {
// startPing button clicked
document.getElementById("transmit_mesh_ping").addEventListener("click", () => {
var dxcallsign = document.getElementById("dxCallMesh").value.toUpperCase();
if (dxcallsign == "" || dxcallsign == null || dxcallsign == undefined)
return;
//pauseButton(document.getElementById("transmit_mesh_ping"), 2000);
ipcRenderer.send("run-tnc-command", {
command: "mesh_ping",
dxcallsign: dxcallsign,
});
});
document
.getElementById("enable_mesh")
.addEventListener("click", () => {
@ -42,9 +57,18 @@ let Data = {
ipcRenderer.on("action-update-mesh-table", (event, arg) => {
var routes = arg.routing_table;
if (typeof routes == "undefined") {
return;
}
var tbl = document.getElementById("mesh-table");
if (tbl !== null) {
tbl.innerHTML = "";
}
for (i = 0; i < routes.length; i++) {
@ -119,7 +143,10 @@ for (i = 0; i < routes.length; i++) {
}
if (tbl !== null) {
// scroll to bottom of page
// https://stackoverflow.com/a/11715670
window.scrollTo(0, document.body.scrollHeight);
}
});

View file

@ -587,6 +587,15 @@ exports.sendPing = function (dxcallsign) {
writeTncCommand(command);
};
// Send Mesh Ping
exports.sendMeshPing = function (dxcallsign) {
command =
'{"type" : "mesh", "command" : "ping", "dxcallsign" : "' +
dxcallsign +
'"}';
writeTncCommand(command);
};
// Send CQ
exports.sendCQ = function () {
command = '{"type" : "broadcast", "command" : "cqcqcq"}';

View file

@ -31,8 +31,21 @@
<label class="btn btn-outline-info" for="enable_mesh"
>Enable / Disable Mesh</label
>
<input
type="text"
class="form-control"
style="max-width: 6rem; text-transform: uppercase"
placeholder="DXcall"
pattern="[A-Z]*"
id="dxCallMesh"
maxlength="11"
aria-label="Input group"
aria-describedby="btnGroupAddon"
/>
<button id="transmit_mesh_ping" type="button" class="btn btn-primary">mesh ping</button>
</div>
</nav>

View file

@ -44,8 +44,11 @@ import threading
import modem
import helpers
import structlog
import ujson as json
from queues import MESH_RECEIVED_QUEUE
from queues import MESH_RECEIVED_QUEUE, MESH_QUEUE_TRANSMIT
MESH_SIGNALLING_TABLE = []
class MeshRouter():
def __init__(self):
@ -63,6 +66,15 @@ class MeshRouter():
)
self.mesh_rx_dispatcher_thread.start()
self.mesh_tx_dispatcher_thread = threading.Thread(
target=self.mesh_tx_dispatcher, name="worker thread receive", daemon=True
)
self.mesh_tx_dispatcher_thread.start()
self.mesh_signalling_dispatcher_thread = threading.Thread(
target=self.mesh_signalling_dispatcher, name="worker thread receive", daemon=True
)
self.mesh_signalling_dispatcher_thread.start()
def get_from_heard_stations(self):
"""
@ -123,7 +135,7 @@ class MeshRouter():
except Exception as e:
self.log.warning("[MESH] error adding data to routing table", e=e, router=new_router)
def broadcast_routing_table(self, interval=180):
def broadcast_routing_table(self, interval=600):
while True:
# always enable receiving for datac4 if broadcasting
@ -192,9 +204,50 @@ class MeshRouter():
data_in = MESH_RECEIVED_QUEUE.get()
if int.from_bytes(data_in[:1], "big") in [FRAME_TYPE.MESH_BROADCAST.value]:
self.received_routing_table(data_in[:-2])
elif int.from_bytes(data_in[:1], "big") in [FRAME_TYPE.MESH_SIGNALLING_PING.value]:
self.received_mesh_ping(data_in[:-2])
else:
print("wrong mesh data received")
print(data_in)
def mesh_tx_dispatcher(self):
while True:
data = MESH_QUEUE_TRANSMIT.get()
print(data)
if data[0] == "PING":
self.add_mesh_ping_to_signalling_table(data[2])
else:
print("wrong mesh command")
def mesh_signalling_dispatcher(self):
# [timestamp, destination, router, frametype, payload, attempt]
# --------------0------------1---------2---------3--------4---------5---- #
while True:
threading.Event().wait(1.0)
for entry in MESH_SIGNALLING_TABLE:
print(entry)
timestamp = entry[0]
attempt = entry[5]
# check for PING cases
if entry[3] == "PING" and attempt < 10:
# Calculate the transmission time with exponential increase
transmission_time = timestamp + (2 ** attempt) * 10
# check if it is time to transmit
if time.time() >= transmission_time:
entry[5] += 1
print(attempt)
print("transmit mesh ping")
self.transmit_mesh_signalling(entry)
else:
print("wait some more time")
else:
print("...")
def received_routing_table(self, data_in):
try:
print("data received........")
@ -265,4 +318,81 @@ class MeshRouter():
return int(score)
def calculate_new_avg_score(self, value_old, value):
return int((value_old + value) / 2)
return int((value_old + value) / 2)
def received_mesh_ping(self, data_in):
pass
def add_mesh_ping_to_signalling_table(self, dxcallsign):
timestamp = time.time()
destination = helpers.get_crc_24(dxcallsign).hex()
router = ""
frametype = "PING"
payload = ""
attempt = 0
# [timestamp, destination, router, frametype, payload, attempt]
# --------------0------------1---------2---------3--------4---------5---- #
new_entry = [timestamp, destination, router, frametype, payload, attempt]
print(MESH_SIGNALLING_TABLE)
for _, item in enumerate(MESH_SIGNALLING_TABLE):
# update routing entry if exists
if new_entry[0] in item[0] and new_entry[1] in item[1]:
print(f"UPDATE {MESH_SIGNALLING_TABLE[_]} >>> {new_entry}")
MESH_SIGNALLING_TABLE[_] = new_entry
# add new routing entry if not exists
if new_entry not in MESH_SIGNALLING_TABLE:
print(f"INSERT {new_entry} >>> SIGNALLING TABLE")
MESH_SIGNALLING_TABLE.append(new_entry)
def enqueue_frame_for_tx(
self,
frame_to_tx, # : list[bytearray], # this causes a crash on python 3.7
c2_mode=FREEDV_MODE.sig0.value,
copies=1,
repeat_delay=0,
) -> None:
"""
Send (transmit) supplied frame to TNC
:param frame_to_tx: Frame data to send
:type frame_to_tx: list of bytearrays
:param c2_mode: Codec2 mode to use, defaults to datac13
:type c2_mode: int, optional
:param copies: Number of frame copies to send, defaults to 1
:type copies: int, optional
:param repeat_delay: Delay time before sending repeat frame, defaults to 0
:type repeat_delay: int, optional
"""
#print(frame_to_tx[0])
#print(frame_to_tx)
frame_type = FRAME_TYPE(int.from_bytes(frame_to_tx[0][:1], byteorder="big")).name
self.log.debug("[TNC] enqueue_frame_for_tx", c2_mode=FREEDV_MODE(c2_mode).name, data=frame_to_tx,
type=frame_type)
# Set the TRANSMITTING flag before adding an object to the transmit queue
# TODO: This is not that nice, we could improve this somehow
TNC.transmitting = True
modem.MODEM_TRANSMIT_QUEUE.put([c2_mode, copies, repeat_delay, frame_to_tx])
# Wait while transmitting
while TNC.transmitting:
threading.Event().wait(0.01)
def transmit_mesh_signalling(self, data):
dxcallsign_crc = bytes.fromhex(data[1])
frame_type = bytes([FRAME_TYPE.MESH_SIGNALLING_PING.value])
ping_frame = bytearray(14)
ping_frame[:1] = frame_type
ping_frame[1:4] = dxcallsign_crc
ping_frame[4:7] = helpers.get_crc_24(Station.mycallsign)
ping_frame[7:13] = helpers.callsign_to_bytes(Station.mycallsign)
self.enqueue_frame_for_tx([ping_frame], c2_mode=FREEDV_MODE.sig0.value)

View file

@ -14,6 +14,9 @@ MODEM_TRANSMIT_QUEUE = queue.Queue()
# Initialize FIFO queue to store received frames
MESH_RECEIVED_QUEUE = queue.Queue()
MESH_QUEUE_TRANSMIT = queue.Queue()
MESH_COMMAND_STATES = {}
# Initialize FIFO queue to store audio frames
AUDIO_RECEIVED_QUEUE = queue.Queue()

View file

@ -32,7 +32,7 @@ import structlog
from random import randrange
import ujson as json
from exceptions import NoCallsign
from queues import DATA_QUEUE_TRANSMIT, RX_BUFFER, RIGCTLD_COMMAND_QUEUE
from queues import DATA_QUEUE_TRANSMIT, RX_BUFFER, RIGCTLD_COMMAND_QUEUE, MESH_QUEUE_TRANSMIT
SOCKET_QUEUE = queue.Queue()
DAEMON_QUEUE = queue.Queue()
@ -402,6 +402,10 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
# DISABLE MESH
if received_json["type"] == "set" and received_json["command"] == "disable_mesh":
MeshParam.enable_protocol = False
# -------------- MESH ---------------- #
# MESH PING
if received_json["type"] == "mesh" and received_json["command"] == "ping":
self.tnc_mesh_ping(received_json)
except Exception as err:
log.error("[SCK] JSON decoding error", e=err)
@ -418,6 +422,8 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
ARQ.arq_session_state = "disconnecting"
command_response("disconnect", True)
except Exception as err:
command_response("listen", False)
log.warning(
@ -571,6 +577,40 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
command=received_json,
)
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
)
def tnc_ping_ping(self, received_json):
# send ping frame and wait for ACK

View file

@ -129,7 +129,7 @@ class TCIParam:
@dataclass
class TNC:
version = "0.10.0-alpha.1-mesh-exp8"
version = "0.10.0-alpha.1-mesh-exp9"
host: str = "0.0.0.0"
port: int = 3000
SOCKET_TIMEOUT: int = 1 # seconds
@ -162,6 +162,7 @@ class FRAME_TYPE(Enum):
FR_NACK = 63
BURST_NACK = 64
MESH_BROADCAST = 100
MESH_SIGNALLING_PING = 101
CQ = 200
QRV = 201
PING = 210