ARQ WIP - session closing

This commit is contained in:
DJ2LS 2023-12-21 15:05:22 +01:00
parent 2faf398e4b
commit 53955a8107
13 changed files with 104 additions and 50 deletions

View file

@ -20,7 +20,7 @@ import infoScreen from "./infoScreen.vue";
import main_modem_healthcheck from "./main_modem_healthcheck.vue";
import Dynamic_components2 from "./dynamic_components2.vue";
import { stopTransmission } from "../js/sock";
import { stopTransmission } from "../js/api";
function stopAllTransmissions() {
console.log("stopping transmissions");

View file

@ -97,6 +97,12 @@ export function sendModemARQRaw(mycall, dxcall, data, uuid) {
});
}
export function stopTransmission() {
return apiPost("/modem/stop_transmission");
}
export function sendModemTestFrame() {
return apiPost("/modem/send_test_frame");
}

View file

@ -719,11 +719,6 @@ function sendResponseSharedFile(dxcallsign, sharedFile, sharedFileData) {
sendResponse(dxcallsign, 255, 1, sharedFile + "/" + sharedFileData, "res-2");
}
*/
//STOP TRANSMISSION
export function stopTransmission() {
var command = '{"type" : "arq", "command": "stop_transmission"}';
writeTncCommand(command);
}
// Get RX BUffer
export function getRxBuffer() {

View file

@ -45,6 +45,8 @@ class ARQSession():
self.id = None
self.final = False # class wide final state for stopping transmissions on command
def log(self, message, isWarning = False):
msg = f"[{type(self).__name__}]: {message}"
logger = self.logger.warn if isWarning else self.logger.info
@ -88,3 +90,4 @@ class ARQSession():
return
self.log(f"Ignoring unknow transition from state {self.state.name} with frame {frame['frame_type']}")

View file

@ -16,29 +16,39 @@ class IRS_State(Enum):
class ARQSessionIRS(arq_session.ARQSession):
TIMEOUT_CONNECT = 3
TIMEOUT_CONNECT = 10
TIMEOUT_DATA = 12
STATE_TRANSITION = {
IRS_State.NEW: {
FRAME_TYPE.ARQ_SESSION_OPEN.value : 'send_open_ack',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
IRS_State.OPEN_ACK_SENT: {
FRAME_TYPE.ARQ_SESSION_OPEN.value: 'send_open_ack',
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
IRS_State.INFO_ACK_SENT: {
FRAME_TYPE.ARQ_SESSION_INFO.value: 'send_info_ack',
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
IRS_State.BURST_REPLY_SENT: {
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
IRS_State.ENDED: {
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
IRS_State.FAILED: {
FRAME_TYPE.ARQ_BURST_FRAME.value: 'receive_data',
FRAME_TYPE.ARQ_STOP.value: 'send_stop_ack'
},
}
@ -107,16 +117,10 @@ class ARQSessionIRS(arq_session.ARQSession):
info_ack = self.frame_factory.build_arq_session_info_ack(
self.id, self.total_crc, self.snr[0],
self.speed_level, self.frames_per_burst)
self.speed_level, self.frames_per_burst, flag_final=self.final)
self.launch_transmit_and_wait(info_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling)
self.set_state(IRS_State.INFO_ACK_SENT)
def send_burst_nack(self):
self.calibrate_speed_settings()
self.set_decode_mode()
nack = self.frame_factory.build_arq_burst_ack(self.id, self.received_bytes, self.speed_level, self.frames_per_burst, self.snr[0])
self.launch_transmit_and_wait(nack, self.TIMEOUT_DATA, mode=FREEDV_MODE.signalling)
self.log("NACK sent")
def process_incoming_data(self, frame):
if frame['offset'] != self.received_bytes:
@ -148,7 +152,7 @@ class ARQSessionIRS(arq_session.ARQSession):
if not self.all_data_received():
ack = self.frame_factory.build_arq_burst_ack(
self.id, self.received_bytes,
self.speed_level, self.frames_per_burst, self.snr[0])
self.speed_level, self.frames_per_burst, self.snr[0], flag_final=self.final)
# increase ack counter
self.transmitted_acks += 1
@ -199,3 +203,11 @@ class ARQSessionIRS(arq_session.ARQSession):
if self.snr[0] >= self.SPEED_LEVEL_DICT[new_speed_level]["min_snr"]:
self.speed_level = new_speed_level
def stop_transmission(self):
self.log(f"Stopping transmission...., setting final flag")
self.final = True
def send_stop_ack(self, stop_frame):
stop_ack = self.frame_factory.build_arq_stop_ack(self.id)
self.launch_transmit_and_wait(stop_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.signalling)
self.set_state(IRS_State.FAILED)

View file

@ -34,8 +34,10 @@ class ARQSessionISS(arq_session.ARQSession):
ISS_State.BURST_SENT: {
FRAME_TYPE.ARQ_SESSION_INFO_ACK.value: 'send_data',
FRAME_TYPE.ARQ_BURST_ACK.value: 'send_data',
FRAME_TYPE.ARQ_BURST_NACK.value: 'send_data',
},
ISS_State.FAILED:{
FRAME_TYPE.ARQ_STOP_ACK.value: 'transmission_failed'
}
}
def __init__(self, config: dict, modem, dxcall: str, data: bytearray):
@ -54,7 +56,7 @@ class ARQSessionISS(arq_session.ARQSession):
return random.randint(1,255)
def transmit_wait_and_retry(self, frame_or_burst, timeout, retries, mode):
while retries > 0:
while retries > 0 and not self.final:
self.event_frame_received = threading.Event()
if isinstance(frame_or_burst, list): burst = frame_or_burst
else: burst = [frame_or_burst]
@ -129,4 +131,10 @@ class ARQSessionISS(arq_session.ARQSession):
def transmission_failed(self):
self.set_state(ISS_State.FAILED)
self.log("Transmission failed!")
self.event_manager.send_arq_session_finished(True, self.id, self.dxcall, len(self.data),False)
self.event_manager.send_arq_session_finished(True, self.id, self.dxcall, len(self.data),False)
def stop_transmission(self):
self.log(f"Stopping transmission...")
stop_frame = self.frame_factory.build_arq_stop(self.id)
self.launch_twr(stop_frame, self.TIMEOUT_CONNECT_ACK, self.RETRIES_CONNECT, mode=FREEDV_MODE.signalling)
self.set_state(ISS_State.FAILED)

View file

@ -4,6 +4,8 @@ import api_validations
import base64
from queue import Queue
from arq_session_iss import ARQSessionISS
class ARQRawCommand(TxCommand):
def set_params_from_api(self, apiParams):

View file

@ -127,6 +127,16 @@ class DataFrameFactory:
"flag": 1,
}
self.template_list[FR_TYPE.ARQ_STOP.value] = {
"frame_length": self.LENGTH_SIG0_FRAME,
"session_id": 1,
}
self.template_list[FR_TYPE.ARQ_STOP_ACK.value] = {
"frame_length": self.LENGTH_SIG0_FRAME,
"session_id": 1,
}
# arq burst frame
self.template_list[FR_TYPE.ARQ_BURST_FRAME.value] = {
"frame_length": None,
@ -146,23 +156,6 @@ class DataFrameFactory:
"flag": 1,
}
# arq burst nack
self.template_list[FR_TYPE.ARQ_BURST_NACK.value] = {
"frame_length": self.LENGTH_SIG1_FRAME,
"session_id": 1,
"offset":4,
"speed_level": 1,
"frames_per_burst": 1,
"snr": 1,
}
# arq data ack nack
self.template_list[FR_TYPE.ARQ_DATA_ACK_NACK.value] = {
"frame_length": self.LENGTH_SIG1_FRAME,
"session_id": 1,
"state": 1,
"snr": 1,
}
def construct(self, frametype, content, frame_length = LENGTH_SIG1_FRAME):
frame_template = self.template_list[frametype.value]
@ -222,9 +215,12 @@ class DataFrameFactory:
elif key in ["session_id", "speed_level",
"frames_per_burst", "version",
"snr", "offset", "total_length", "state"]:
"offset", "total_length", "state"]:
extracted_data[key] = int.from_bytes(data, 'big')
elif key in ["snr"]:
extracted_data[key] = helpers.snr_from_bytes(data)
elif key == "flag":
data = int.from_bytes(data, "big")
@ -342,7 +338,8 @@ class DataFrameFactory:
"origin": helpers.callsign_to_bytes(self.myfullcall),
"destination_crc": helpers.get_crc_24(destination),
"version": bytes([version]),
"snr": snr.to_bytes(1, 'big'), }
"snr": helpers.snr_to_bytes(1),
}
return self.construct(FR_TYPE.ARQ_SESSION_OPEN_ACK, payload)
def build_arq_session_info(self, session_id: int, total_length: int, total_crc: bytes, snr):
@ -350,10 +347,23 @@ class DataFrameFactory:
"session_id": session_id.to_bytes(1, 'big'),
"total_length": total_length.to_bytes(4, 'big'),
"total_crc": total_crc,
"snr": snr.to_bytes(1, 'big'),
"snr": helpers.snr_to_bytes(1),
}
return self.construct(FR_TYPE.ARQ_SESSION_INFO, payload)
def build_arq_stop(self, session_id: int):
payload = {
"session_id": session_id.to_bytes(1, 'big'),
}
return self.construct(FR_TYPE.ARQ_STOP, payload)
def build_arq_stop_ack(self, session_id: int):
payload = {
"session_id": session_id.to_bytes(1, 'big'),
}
return self.construct(FR_TYPE.ARQ_STOP_ACK, payload)
def build_arq_session_info_ack(self, session_id, total_crc, snr, speed_level, frames_per_burst, flag_final=False):
flag = 0b00000000
if flag_final:
@ -363,7 +373,7 @@ class DataFrameFactory:
"frame_length": self.LENGTH_SIG0_FRAME,
"session_id": session_id.to_bytes(1, 'big'),
"total_crc": bytes.fromhex(total_crc),
"snr": snr.to_bytes(1, 'big'),
"snr": helpers.snr_to_bytes(1),
"speed_level": speed_level.to_bytes(1, 'big'),
"frames_per_burst": frames_per_burst.to_bytes(1, 'big'),
"flag": flag.to_bytes(1, 'big'),

View file

@ -24,12 +24,11 @@ class DISPATCHER():
FR_TYPE.ARQ_CONNECTION_CLOSE.value: {"class": ARQFrameHandler, "name": "ARQ CLOSE SESSION"},
FR_TYPE.ARQ_CONNECTION_HB.value: {"class": ARQFrameHandler, "name": "ARQ HEARTBEAT"},
FR_TYPE.ARQ_CONNECTION_OPEN.value: {"class": ARQFrameHandler, "name": "ARQ OPEN SESSION"},
FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP TX"},
FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP"},
FR_TYPE.ARQ_STOP_ACK.value: {"class": ARQFrameHandler, "name": "ARQ STOP ACK"},
FR_TYPE.BEACON.value: {"class": FrameHandler, "name": "BEACON"},
FR_TYPE.ARQ_BURST_FRAME.value:{"class": ARQFrameHandler, "name": "BURST FRAME"},
FR_TYPE.ARQ_BURST_ACK.value: {"class": ARQFrameHandler, "name": "BURST ACK"},
FR_TYPE.ARQ_BURST_NACK.value: {"class": ARQFrameHandler, "name": "BURST NACK"},
FR_TYPE.ARQ_DATA_ACK_NACK.value: {"class": ARQFrameHandler, "name": "DATA ACK NACK"},
FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"},
FR_TYPE.PING_ACK.value: {"class": FrameHandler, "name": "PING ACK"},
FR_TYPE.PING.value: {"class": PingFrameHandler, "name": "PING"},

View file

@ -38,8 +38,9 @@ class ARQFrameHandler(frame_handler.FrameHandler):
FR.ARQ_SESSION_OPEN_ACK.value,
FR.ARQ_SESSION_INFO_ACK.value,
FR.ARQ_BURST_ACK.value,
FR.ARQ_DATA_ACK_NACK.value
]:
FR.ARQ_STOP.value,
FR.ARQ_STOP_ACK.value
]:
session = self.states.get_arq_iss_session(session_id)
else:

View file

@ -10,14 +10,13 @@ class FRAME_TYPE(Enum):
ARQ_CONNECTION_HB = 2
ARQ_CONNECTION_CLOSE = 3
ARQ_STOP = 10
ARQ_SESSION_OPEN = 11
ARQ_SESSION_OPEN_ACK = 12
ARQ_SESSION_INFO = 13
ARQ_SESSION_INFO_ACK = 14
ARQ_STOP_ACK = 11
ARQ_SESSION_OPEN = 12
ARQ_SESSION_OPEN_ACK = 13
ARQ_SESSION_INFO = 14
ARQ_SESSION_INFO_ACK = 15
ARQ_BURST_FRAME = 20
ARQ_BURST_ACK = 21
ARQ_BURST_NACK = 22
ARQ_DATA_ACK_NACK = 23
MESH_BROADCAST = 100
MESH_SIGNALLING_PING = 101
MESH_SIGNALLING_PING_ACK = 102

View file

@ -215,6 +215,19 @@ def post_modem_send_raw():
# server_commands.modem_arq_send_raw(request.json)
return "Not implemented yet"
@app.route('/modem/stop_transmission', methods=['POST'])
def post_modem_send_raw_stop():
if request.method not in ['POST']:
return api_response({"info": "endpoint for SENDING a STOP command via POST"})
if not app.state_manager.is_modem_running:
api_abort('Modem not running', 503)
print("stop")
app.state_manager.set_final_to_arq_transmissions()
# server_commands.modem_arq_send_raw(request.json)
return api_response(request.json)
# @app.route('/modem/arq_connect', methods=['POST'])
# @app.route('/modem/arq_disconnect', methods=['POST'])
# @app.route('/modem/send_raw', methods=['POST'])

View file

@ -144,6 +144,12 @@ class StateManager:
raise RuntimeError(f"ARQ ISS Session '{id}' not found!")
del self.arq_irs_sessions[id]
def set_final_to_arq_transmissions(self):
for id in self.arq_irs_sessions:
self.arq_irs_sessions[id].stop_transmission()
for id in self.arq_iss_sessions:
self.arq_iss_sessions[id].stop_transmission()
def add_activity(self, activity_data):
# Generate a random 8-byte string as hex
activity_id = np.random.bytes(8).hex()