mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
WIP ARQ - cleanup and modem fix
This commit is contained in:
parent
16f37677d5
commit
c4dbe0caef
5 changed files with 32 additions and 82 deletions
|
@ -51,10 +51,13 @@ class ARQSession():
|
||||||
def get_mode_by_speed_level(self, speed_level):
|
def get_mode_by_speed_level(self, speed_level):
|
||||||
return self.SPEED_LEVEL_DICT[speed_level]["mode"]
|
return self.SPEED_LEVEL_DICT[speed_level]["mode"]
|
||||||
|
|
||||||
def transmit_frame(self, frame: bytearray):
|
def transmit_frame(self, frame: bytearray, mode = False):
|
||||||
self.log("Transmitting frame")
|
self.log("Transmitting frame")
|
||||||
|
if not mode:
|
||||||
|
self.get_mode_by_speed_level(self.speed_level)
|
||||||
|
|
||||||
modem_queue_item = {
|
modem_queue_item = {
|
||||||
'mode': self.get_mode_by_speed_level(self.speed_level),
|
'mode': mode,
|
||||||
'repeat': 1,
|
'repeat': 1,
|
||||||
'repeat_delay': 1,
|
'repeat_delay': 1,
|
||||||
'frame': frame,
|
'frame': frame,
|
||||||
|
|
|
@ -4,6 +4,8 @@ import queue
|
||||||
import arq_session
|
import arq_session
|
||||||
import helpers
|
import helpers
|
||||||
from modem_frametypes import FRAME_TYPE
|
from modem_frametypes import FRAME_TYPE
|
||||||
|
from codec2 import FREEDV_MODE
|
||||||
|
|
||||||
|
|
||||||
class ARQSessionIRS(arq_session.ARQSession):
|
class ARQSessionIRS(arq_session.ARQSession):
|
||||||
|
|
||||||
|
@ -77,9 +79,9 @@ class ARQSessionIRS(arq_session.ARQSession):
|
||||||
self.log("Timeout waiting for ISS. Session failed.")
|
self.log("Timeout waiting for ISS. Session failed.")
|
||||||
self.set_state(self.STATE_FAILED)
|
self.set_state(self.STATE_FAILED)
|
||||||
|
|
||||||
def launch_transmit_and_wait(self, frame, timeout):
|
def launch_transmit_and_wait(self, frame, timeout, mode):
|
||||||
thread_wait = threading.Thread(target = self.transmit_and_wait,
|
thread_wait = threading.Thread(target = self.transmit_and_wait,
|
||||||
args = [frame, timeout])
|
args = [frame, timeout, mode])
|
||||||
thread_wait.start()
|
thread_wait.start()
|
||||||
|
|
||||||
def send_open_ack(self, open_frame):
|
def send_open_ack(self, open_frame):
|
||||||
|
@ -88,7 +90,7 @@ class ARQSessionIRS(arq_session.ARQSession):
|
||||||
self.dxcall,
|
self.dxcall,
|
||||||
self.version,
|
self.version,
|
||||||
self.snr[0])
|
self.snr[0])
|
||||||
self.launch_transmit_and_wait(ack_frame, self.TIMEOUT_CONNECT)
|
self.launch_transmit_and_wait(ack_frame, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.datac13)
|
||||||
self.set_state(self.STATE_OPEN_ACK_SENT)
|
self.set_state(self.STATE_OPEN_ACK_SENT)
|
||||||
|
|
||||||
def send_info_ack(self, info_frame):
|
def send_info_ack(self, info_frame):
|
||||||
|
@ -97,10 +99,11 @@ class ARQSessionIRS(arq_session.ARQSession):
|
||||||
self.total_crc = info_frame['total_crc']
|
self.total_crc = info_frame['total_crc']
|
||||||
self.dx_snr.append(info_frame['snr'])
|
self.dx_snr.append(info_frame['snr'])
|
||||||
|
|
||||||
|
self.calibrate_speed_settings()
|
||||||
info_ack = self.frame_factory.build_arq_session_info_ack(
|
info_ack = self.frame_factory.build_arq_session_info_ack(
|
||||||
self.id, self.total_crc, self.snr[0],
|
self.id, self.total_crc, self.snr[0],
|
||||||
self.speed_level, self.frames_per_burst)
|
self.speed_level, self.frames_per_burst)
|
||||||
self.launch_transmit_and_wait(info_ack, self.TIMEOUT_CONNECT)
|
self.launch_transmit_and_wait(info_ack, self.TIMEOUT_CONNECT, mode=FREEDV_MODE.datac13)
|
||||||
self.set_state(self.STATE_INFO_ACK_SENT)
|
self.set_state(self.STATE_INFO_ACK_SENT)
|
||||||
|
|
||||||
def send_burst_nack(self):
|
def send_burst_nack(self):
|
||||||
|
@ -108,7 +111,6 @@ class ARQSessionIRS(arq_session.ARQSession):
|
||||||
nack = self.frame_factory.build_arq_burst_ack(self.id, self.received_bytes, self.speed_level, self.frames_per_burst, self.snr[0])
|
nack = self.frame_factory.build_arq_burst_ack(self.id, self.received_bytes, self.speed_level, self.frames_per_burst, self.snr[0])
|
||||||
self.transmit_and_wait(nack)
|
self.transmit_and_wait(nack)
|
||||||
|
|
||||||
|
|
||||||
def process_incoming_data(self, frame):
|
def process_incoming_data(self, frame):
|
||||||
if frame['offset'] != self.received_bytes:
|
if frame['offset'] != self.received_bytes:
|
||||||
self.logger.info(f"Discarding data frame due to wrong offset", frame=self.frame_received)
|
self.logger.info(f"Discarding data frame due to wrong offset", frame=self.frame_received)
|
||||||
|
|
|
@ -52,12 +52,12 @@ class ARQSessionISS(arq_session.ARQSession):
|
||||||
def generate_id(self):
|
def generate_id(self):
|
||||||
return random.randint(1,255)
|
return random.randint(1,255)
|
||||||
|
|
||||||
def transmit_wait_and_retry(self, frame_or_burst, timeout, retries):
|
def transmit_wait_and_retry(self, frame_or_burst, timeout, retries, mode):
|
||||||
while retries > 0:
|
while retries > 0:
|
||||||
if isinstance(frame_or_burst, list): burst = frame_or_burst
|
if isinstance(frame_or_burst, list): burst = frame_or_burst
|
||||||
else: burst = [frame_or_burst]
|
else: burst = [frame_or_burst]
|
||||||
for f in burst:
|
for f in burst:
|
||||||
self.transmit_frame(f)
|
self.transmit_frame(f, mode)
|
||||||
self.log(f"Waiting {timeout} seconds...")
|
self.log(f"Waiting {timeout} seconds...")
|
||||||
if self.event_frame_received.wait(timeout):
|
if self.event_frame_received.wait(timeout):
|
||||||
return
|
return
|
||||||
|
@ -66,13 +66,13 @@ class ARQSessionISS(arq_session.ARQSession):
|
||||||
self.set_state(self.STATE_FAILED)
|
self.set_state(self.STATE_FAILED)
|
||||||
self.log("Session failed")
|
self.log("Session failed")
|
||||||
|
|
||||||
def launch_twr(self, frame_or_burst, timeout, retries):
|
def launch_twr(self, frame_or_burst, timeout, retries, mode):
|
||||||
twr = threading.Thread(target = self.transmit_wait_and_retry, args=[frame_or_burst, timeout, retries])
|
twr = threading.Thread(target = self.transmit_wait_and_retry, args=[frame_or_burst, timeout, retries, mode])
|
||||||
twr.start()
|
twr.start()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
session_open_frame = self.frame_factory.build_arq_session_open(self.dxcall, self.id)
|
session_open_frame = self.frame_factory.build_arq_session_open(self.dxcall, self.id)
|
||||||
self.launch_twr(session_open_frame, self.TIMEOUT_CONNECT_ACK, self.RETRIES_CONNECT)
|
self.launch_twr(session_open_frame, self.TIMEOUT_CONNECT_ACK, self.RETRIES_CONNECT, mode=FREEDV_MODE.datac13)
|
||||||
self.set_state(self.STATE_OPEN_SENT)
|
self.set_state(self.STATE_OPEN_SENT)
|
||||||
|
|
||||||
def set_speed_and_frames_per_burst(self, frame):
|
def set_speed_and_frames_per_burst(self, frame):
|
||||||
|
|
|
@ -7,7 +7,8 @@ from arq_session_iss import ARQSessionISS
|
||||||
class ARQRawCommand(TxCommand):
|
class ARQRawCommand(TxCommand):
|
||||||
|
|
||||||
def set_params_from_api(self, apiParams):
|
def set_params_from_api(self, apiParams):
|
||||||
self.dxcall = apiParams['dxcall']
|
print(apiParams)
|
||||||
|
self.dxcall = apiParams['dxcallsign']
|
||||||
if not api_validations.validate_freedata_callsign(self.dxcall):
|
if not api_validations.validate_freedata_callsign(self.dxcall):
|
||||||
self.dxcall = f"{self.dxcall}-0"
|
self.dxcall = f"{self.dxcall}-0"
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ Created on Wed Dec 23 07:04:24 2020
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import ctypes
|
import ctypes
|
||||||
import os
|
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -25,13 +24,9 @@ import cw
|
||||||
from queues import RIGCTLD_COMMAND_QUEUE
|
from queues import RIGCTLD_COMMAND_QUEUE
|
||||||
import audio
|
import audio
|
||||||
import event_manager
|
import event_manager
|
||||||
from modem_frametypes import FRAME_TYPE
|
|
||||||
import beacon
|
import beacon
|
||||||
import demodulator
|
import demodulator
|
||||||
|
|
||||||
TESTMODE = False
|
|
||||||
TXCHANNEL = ""
|
|
||||||
|
|
||||||
class RF:
|
class RF:
|
||||||
"""Class to encapsulate interactions between the audio device and codec2"""
|
"""Class to encapsulate interactions between the audio device and codec2"""
|
||||||
|
|
||||||
|
@ -132,16 +127,14 @@ class RF:
|
||||||
def start_modem(self):
|
def start_modem(self):
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
if not TESTMODE and self.radiocontrol not in ["tci"]:
|
if self.radiocontrol not in ["tci"]:
|
||||||
result = self.init_audio()
|
result = self.init_audio()
|
||||||
if not result:
|
if not result:
|
||||||
raise RuntimeError("Unable to init audio devices")
|
raise RuntimeError("Unable to init audio devices")
|
||||||
self.demodulator.start(self.stream)
|
self.demodulator.start(self.stream)
|
||||||
|
|
||||||
elif not TESTMODE:
|
|
||||||
result = self.init_tci()
|
|
||||||
else:
|
else:
|
||||||
result = self.init_mkfifo()
|
result = self.init_tci()
|
||||||
|
|
||||||
if result not in [False]:
|
if result not in [False]:
|
||||||
# init codec2 instances
|
# init codec2 instances
|
||||||
|
@ -245,34 +238,6 @@ class RF:
|
||||||
daemon=True,
|
daemon=True,
|
||||||
)
|
)
|
||||||
tci_tx_callback_thread.start()
|
tci_tx_callback_thread.start()
|
||||||
def init_mkfifo(self):
|
|
||||||
class Object:
|
|
||||||
"""An object for simulating audio stream"""
|
|
||||||
active = True
|
|
||||||
|
|
||||||
self.stream = Object()
|
|
||||||
|
|
||||||
# Create mkfifo buffers
|
|
||||||
try:
|
|
||||||
os.mkfifo(RXCHANNEL)
|
|
||||||
os.mkfifo(TXCHANNEL)
|
|
||||||
except Exception as err:
|
|
||||||
self.log.info(f"[MDM] init:mkfifo: Exception: {err}")
|
|
||||||
|
|
||||||
mkfifo_write_callback_thread = threading.Thread(
|
|
||||||
target=self.mkfifo_write_callback,
|
|
||||||
name="MKFIFO WRITE CALLBACK THREAD",
|
|
||||||
daemon=True,
|
|
||||||
)
|
|
||||||
mkfifo_write_callback_thread.start()
|
|
||||||
|
|
||||||
self.log.debug("[MDM] Starting mkfifo_read_callback")
|
|
||||||
mkfifo_read_callback_thread = threading.Thread(
|
|
||||||
target=self.mkfifo_read_callback,
|
|
||||||
name="MKFIFO READ CALLBACK THREAD",
|
|
||||||
daemon=True,
|
|
||||||
)
|
|
||||||
mkfifo_read_callback_thread.start()
|
|
||||||
|
|
||||||
def mkfifo_write_callback(self) -> None:
|
def mkfifo_write_callback(self) -> None:
|
||||||
"""Support testing by writing the audio data to a pipe."""
|
"""Support testing by writing the audio data to a pipe."""
|
||||||
|
@ -304,20 +269,16 @@ class RF:
|
||||||
"""
|
"""
|
||||||
self.demodulator.reset_data_sync()
|
self.demodulator.reset_data_sync()
|
||||||
|
|
||||||
if mode == codec2.FREEDV_MODE.datac0.value:
|
# get freedv instance by mode
|
||||||
freedv = self.freedv_datac0_tx
|
mode_transition = {
|
||||||
elif mode == codec2.FREEDV_MODE.datac1.value:
|
codec2.FREEDV_MODE.datac0: self.freedv_datac0_tx,
|
||||||
freedv = self.freedv_datac1_tx
|
codec2.FREEDV_MODE.datac1: self.freedv_datac1_tx,
|
||||||
elif mode == codec2.FREEDV_MODE.datac3.value:
|
codec2.FREEDV_MODE.datac3: self.freedv_datac3_tx,
|
||||||
freedv = self.freedv_datac3_tx
|
codec2.FREEDV_MODE.datac4: self.freedv_datac4_tx,
|
||||||
elif mode == codec2.FREEDV_MODE.datac4.value:
|
codec2.FREEDV_MODE.datac13: self.freedv_datac13_tx,
|
||||||
freedv = self.freedv_datac4_tx
|
}
|
||||||
elif mode == codec2.FREEDV_MODE.datac13.value:
|
if mode in mode_transition:
|
||||||
freedv = self.freedv_datac13_tx
|
freedv = mode_transition[mode]
|
||||||
elif mode == codec2.FREEDV_MODE.fsk_ldpc_0.value:
|
|
||||||
freedv = self.freedv_ldpc0_tx
|
|
||||||
elif mode == codec2.FREEDV_MODE.fsk_ldpc_1.value:
|
|
||||||
freedv = self.freedv_ldpc1_tx
|
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -659,7 +620,7 @@ class RF:
|
||||||
queuesize = self.modem_transmit_queue.qsize()
|
queuesize = self.modem_transmit_queue.qsize()
|
||||||
self.log.debug("[MDM] self.modem_transmit_queue", qsize=queuesize)
|
self.log.debug("[MDM] self.modem_transmit_queue", qsize=queuesize)
|
||||||
tx = self.modem_transmit_queue.get()
|
tx = self.modem_transmit_queue.get()
|
||||||
|
print(tx)
|
||||||
# TODO Why we is this taking an array instead of a single frame?
|
# TODO Why we is this taking an array instead of a single frame?
|
||||||
if tx['mode'] in ["morse"]:
|
if tx['mode'] in ["morse"]:
|
||||||
self.transmit_morse(tx['repeat'], tx['repeat_delay'], [tx['frame']])
|
self.transmit_morse(tx['repeat'], tx['repeat_delay'], [tx['frame']])
|
||||||
|
@ -870,20 +831,3 @@ class RF:
|
||||||
# Set config boolean regarding wheter it should sent FFT data to queue
|
# Set config boolean regarding wheter it should sent FFT data to queue
|
||||||
self.enable_fft_stream = enable
|
self.enable_fft_stream = enable
|
||||||
|
|
||||||
def get_modem_error_state():
|
|
||||||
"""
|
|
||||||
get current state buffer and return True of contains 10
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if RECEIVE_DATAC1 and 10 in DAT0_DATAC1_STATE:
|
|
||||||
DAT0_DATAC1_STATE.clear()
|
|
||||||
return True
|
|
||||||
if RECEIVE_DATAC3 and 10 in DAT0_DATAC3_STATE:
|
|
||||||
DAT0_DATAC3_STATE.clear()
|
|
||||||
return True
|
|
||||||
if RECEIVE_DATAC4 and 10 in DAT0_DATAC4_STATE:
|
|
||||||
DAT0_DATAC4_STATE.clear()
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
Loading…
Reference in a new issue