mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
first mesh ping tx part
This commit is contained in:
parent
415ff0c777
commit
35576bb760
8 changed files with 234 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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"}';
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
134
tnc/mesh.py
134
tnc/mesh.py
|
@ -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........")
|
||||
|
@ -266,3 +319,80 @@ class MeshRouter():
|
|||
|
||||
def calculate_new_avg_score(self, value_old, value):
|
||||
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)
|
|
@ -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()
|
||||
|
|
42
tnc/sock.py
42
tnc/sock.py
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue