mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
First run reducing number of problems
This commit is contained in:
parent
9f8f17b633
commit
b6face744b
24
tnc/audio.py
24
tnc/audio.py
|
@ -1,20 +1,18 @@
|
|||
|
||||
import atexit
|
||||
import json
|
||||
import multiprocessing
|
||||
import sys
|
||||
|
||||
import sounddevice as sd
|
||||
|
||||
atexit.register(sd._terminate)
|
||||
|
||||
|
||||
def get_audio_devices():
|
||||
"""
|
||||
return list of input and output audio devices in own process to avoid crashes of portaudio on raspberry pi
|
||||
|
||||
also uses a process data manager
|
||||
"""
|
||||
# we need to run this on windows for multiprocessing support
|
||||
# we need to run this on Windows for multiprocessing support
|
||||
# multiprocessing.freeze_support()
|
||||
# multiprocessing.get_context('spawn')
|
||||
|
||||
|
@ -33,34 +31,34 @@ def get_audio_devices():
|
|||
|
||||
return list(proxy_input_devices), list(proxy_output_devices)
|
||||
|
||||
|
||||
def fetch_audio_devices(input_devices, output_devices):
|
||||
"""
|
||||
get audio devices from portaudio
|
||||
|
||||
Args:
|
||||
input_devices: proxy variable for input devices
|
||||
output_devices: proxy variable for outout devices
|
||||
output_devices: proxy variable for output devices
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
devices = sd.query_devices(device=None, kind=None)
|
||||
for index, device in enumerate(devices):
|
||||
#for i in range(0, p.get_device_count()):
|
||||
# we need to do a try exception, beacuse for windows theres no audio device range
|
||||
# we need to do a try exception, because for windows there's no audio device range
|
||||
try:
|
||||
name = device["name"]
|
||||
|
||||
maxOutputChannels = device["max_output_channels"]
|
||||
maxInputChannels = device["max_input_channels"]
|
||||
max_output_channels = device["max_output_channels"]
|
||||
max_input_channels = device["max_input_channels"]
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
maxInputChannels = 0
|
||||
maxOutputChannels = 0
|
||||
max_input_channels = 0
|
||||
max_output_channels = 0
|
||||
name = ''
|
||||
|
||||
if maxInputChannels > 0:
|
||||
if max_input_channels > 0:
|
||||
input_devices.append({"id": index, "name": name})
|
||||
if maxOutputChannels > 0:
|
||||
if max_output_channels > 0:
|
||||
output_devices.append({"id": index, "name": name})
|
||||
|
|
|
@ -42,6 +42,7 @@ def freedv_get_mode_value_by_name(mode: str) -> int:
|
|||
"""
|
||||
return FREEDV_MODE[mode].value
|
||||
|
||||
|
||||
# Function for returning the mode name
|
||||
def freedv_get_mode_name_by_value(mode: int) -> str:
|
||||
"""
|
||||
|
@ -54,6 +55,7 @@ def freedv_get_mode_name_by_value(mode: int) -> str:
|
|||
"""
|
||||
return FREEDV_MODE(mode).name
|
||||
|
||||
|
||||
# Check if we are running in a pyinstaller environment
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
sys.path.append(getattr(sys, "_MEIPASS"))
|
||||
|
@ -144,6 +146,7 @@ api.FREEDV_MODE_DATAC3 = 12
|
|||
api.FREEDV_MODE_DATAC0 = 14
|
||||
api.FREEDV_MODE_FSK_LDPC = 9
|
||||
|
||||
|
||||
# -------------------------------- FSK LDPC MODE SETTINGS
|
||||
|
||||
# Advanced structure for fsk modes
|
||||
|
@ -159,6 +162,7 @@ class ADVANCED(ctypes.Structure):
|
|||
("codename", ctypes.c_char_p),
|
||||
]
|
||||
|
||||
|
||||
'''
|
||||
adv.interleave_frames = 0 # max amplitude
|
||||
adv.M = 2 # number of fsk tones 2/4
|
||||
|
@ -209,6 +213,7 @@ MODEM_STATS_NSPEC = 512
|
|||
MODEM_STATS_MAX_F_HZ = 4000
|
||||
MODEM_STATS_MAX_F_EST = 4
|
||||
|
||||
|
||||
# Modem stats structure
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
""" """
|
||||
|
@ -231,6 +236,7 @@ class MODEMSTATS(ctypes.Structure):
|
|||
("fft_buf", (ctypes.c_float * MODEM_STATS_NSPEC * 2)),
|
||||
]
|
||||
|
||||
|
||||
# Return code flags for freedv_get_rx_status() function
|
||||
api.FREEDV_RX_TRIAL_SYNC = 0x1 # demodulator has trial sync
|
||||
api.FREEDV_RX_SYNC = 0x2 # demodulator has sync
|
||||
|
@ -255,6 +261,7 @@ api.rx_sync_flags_to_text = [
|
|||
"EBS-",
|
||||
"EBST"]
|
||||
|
||||
|
||||
# Audio buffer ---------------------------------------------------------
|
||||
class audio_buffer:
|
||||
"""
|
||||
|
@ -262,6 +269,7 @@ class audio_buffer:
|
|||
|
||||
made by David Rowe, VK5DGR
|
||||
"""
|
||||
|
||||
# A buffer of int16 samples, using a fixed length numpy array self.buffer for storage
|
||||
# self.nbuffer is the current number of samples in the buffer
|
||||
def __init__(self, size):
|
||||
|
@ -304,14 +312,16 @@ class audio_buffer:
|
|||
assert self.nbuffer >= 0
|
||||
self.mutex.release()
|
||||
|
||||
|
||||
# Resampler ---------------------------------------------------------
|
||||
|
||||
api.FDMDV_OS_48 = int(6) # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = int(48) # number of OS filter taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = int(api.FDMDV_OS_TAPS_48K/api.FDMDV_OS_48) # number of OS filter taps at 8kHz
|
||||
api.FDMDV_OS_48 = 6 # oversampling rate
|
||||
api.FDMDV_OS_TAPS_48K = 48 # number of OS filter taps at 48kHz
|
||||
api.FDMDV_OS_TAPS_48_8K = api.FDMDV_OS_TAPS_48K // api.FDMDV_OS_48 # number of OS filter taps at 8kHz
|
||||
api.fdmdv_8_to_48_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
|
||||
api.fdmdv_48_to_8_short.argtype = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
|
||||
|
||||
|
||||
class resampler:
|
||||
"""
|
||||
Re-sampler class
|
||||
|
@ -375,7 +385,7 @@ class resampler:
|
|||
# In C: pin8=&in8_mem[MEM8]
|
||||
pin8 = ctypes.byref(np.ctypeslib.as_ctypes(in8_mem), 2 * self.MEM8)
|
||||
out48 = np.zeros(api.FDMDV_OS_48 * len(in8), dtype=np.int16)
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8));
|
||||
api.fdmdv_8_to_48_short(out48.ctypes, pin8, len(in8))
|
||||
|
||||
# Store memory for next time
|
||||
self.filter_mem8 = in8_mem[:self.MEM8]
|
||||
|
|
|
@ -15,8 +15,6 @@ import argparse
|
|||
import atexit
|
||||
import multiprocessing
|
||||
import os
|
||||
import queue
|
||||
import re
|
||||
import signal
|
||||
import socketserver
|
||||
import subprocess
|
||||
|
@ -25,13 +23,11 @@ import threading
|
|||
import time
|
||||
|
||||
import crcengine
|
||||
import psutil
|
||||
import serial.tools.list_ports
|
||||
import structlog
|
||||
import ujson as json
|
||||
|
||||
import audio
|
||||
import helpers
|
||||
import log_handler
|
||||
import sock
|
||||
import static
|
||||
|
@ -51,9 +47,11 @@ def signal_handler(sig, frame):
|
|||
sock.CLOSE_SIGNAL = True
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
class DAEMON():
|
||||
|
||||
class DAEMON:
|
||||
"""
|
||||
Daemon class
|
||||
|
||||
|
@ -215,6 +213,7 @@ class DAEMON():
|
|||
options.append('--tuning_range_fmax')
|
||||
options.append(data[20])
|
||||
|
||||
|
||||
# overriding FSK mode
|
||||
# if data[21] == 'True':
|
||||
# options.append('--fsk')
|
||||
|
@ -304,7 +303,7 @@ class DAEMON():
|
|||
serialspeed=serialspeed, pttport=pttport, data_bits=data_bits, stop_bits=stop_bits,
|
||||
handshake=handshake, rigctld_ip=rigctld_ip, rigctld_port = rigctld_port)
|
||||
|
||||
hamlib_version = rig.hamlib_version
|
||||
# hamlib_version = rig.hamlib_version
|
||||
|
||||
hamlib.set_ptt(True)
|
||||
pttstate = hamlib.get_ptt()
|
||||
|
@ -327,10 +326,10 @@ class DAEMON():
|
|||
|
||||
except Exception as e:
|
||||
structlog.get_logger("structlog").error("[DMN] worker: Exception: ", e=e)
|
||||
# print(e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# we need to run this on windows for multiprocessing support
|
||||
# we need to run this on Windows for multiprocessing support
|
||||
multiprocessing.freeze_support()
|
||||
|
||||
# --------------------------------------------GET PARAMETER INPUTS
|
||||
|
|
|
@ -8,9 +8,7 @@ Created on Sun Dec 27 20:43:40 2020
|
|||
# pylint: disable=invalid-name, line-too-long, c-extension-no-member
|
||||
# pylint: disable=import-outside-toplevel
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import logging
|
||||
import queue
|
||||
import sys
|
||||
import threading
|
||||
|
@ -25,7 +23,6 @@ import ujson as json
|
|||
|
||||
import codec2
|
||||
import helpers
|
||||
import log_handler
|
||||
import modem
|
||||
import sock
|
||||
import static
|
||||
|
@ -362,11 +359,11 @@ class DATA():
|
|||
self.enqueue_frame_for_tx(ack_frame, copies=3, repeat_delay=100)
|
||||
|
||||
def send_retransmit_request_frame(self, freedv):
|
||||
# check where a None is in our burst buffer and do frame+1, beacuse lists start at 0
|
||||
# check where a None is in our burst buffer and do frame+1, because lists start at 0
|
||||
missing_frames = [frame + 1 for frame, element in enumerate(static.RX_BURST_BUFFER) if element is None]
|
||||
|
||||
# set n frames per burst to modem
|
||||
# this is an idea so its not getting lost....
|
||||
# this is an idea, so it's not getting lost....
|
||||
# we need to work on this
|
||||
codec2.api.freedv_set_frames_per_burst(freedv,len(missing_frames))
|
||||
|
||||
|
@ -490,7 +487,7 @@ class DATA():
|
|||
# Here we are going to search for our data in the last received bytes.
|
||||
# This reduces the chance we will lose the entire frame in the case of signalling frame loss
|
||||
|
||||
# static.RX_FRAME_BUFFER --> exisitng data
|
||||
# static.RX_FRAME_BUFFER --> existing data
|
||||
# temp_burst_buffer --> new data
|
||||
# search_area --> area where we want to search
|
||||
search_area = 510
|
||||
|
@ -504,7 +501,7 @@ class DATA():
|
|||
static.RX_FRAME_BUFFER = static.RX_FRAME_BUFFER[:search_position + get_position]
|
||||
static.RX_FRAME_BUFFER += temp_burst_buffer
|
||||
structlog.get_logger("structlog").warning("[TNC] ARQ | RX | replacing existing buffer data", area=search_area, pos=get_position)
|
||||
# if we dont find data n this range, we really have new data and going to replace it
|
||||
# if we don't find data n this range, we really have new data and going to replace it
|
||||
else:
|
||||
static.RX_FRAME_BUFFER += temp_burst_buffer
|
||||
structlog.get_logger("structlog").debug("[TNC] ARQ | RX | appending data to buffer")
|
||||
|
@ -609,7 +606,6 @@ class DATA():
|
|||
jsondata = {"arq":"received", "uuid" : uniqueid, "timestamp": timestamp, "mycallsign" : str(mycallsign, 'utf-8'), "dxcallsign": str(static.DXCALLSIGN, 'utf-8'), "dxgrid": str(static.DXGRID, 'utf-8'), "data": base64_data}
|
||||
json_data_out = json.dumps(jsondata)
|
||||
structlog.get_logger("structlog").debug("[TNC] arq_data_received:", jsondata=jsondata)
|
||||
# print(jsondata)
|
||||
sock.SOCKET_QUEUE.put(json_data_out)
|
||||
static.INFO.append("ARQ;RECEIVING;SUCCESS")
|
||||
|
||||
|
@ -710,10 +706,10 @@ class DATA():
|
|||
structlog.get_logger("structlog").debug("[TNC] FIXED MODE:", mode=data_mode)
|
||||
else:
|
||||
# we are doing a modulo check of transmission retries of the actual burst
|
||||
# every 2nd retry which failes, decreases speedlevel by 1.
|
||||
# every 2nd retry which fails, decreases speedlevel by 1.
|
||||
# as soon as we received an ACK for the current burst, speed_level will increase
|
||||
# by 1.
|
||||
# the can be optimised by checking the optimal speed level for the current conditions
|
||||
# They can be optimised by checking the optimal speed level for the current conditions
|
||||
'''
|
||||
if not self.tx_n_retry_of_burst % 2 and self.tx_n_retry_of_burst > 0:
|
||||
self.speed_level -= 1
|
||||
|
@ -980,7 +976,7 @@ class DATA():
|
|||
Returns:
|
||||
|
||||
"""
|
||||
# das hier müssen wir checken. Sollte vielleicht in INIT!!!
|
||||
# TODO: we need to check this, maybe placing it to class init
|
||||
self.datachannel_timeout = False
|
||||
structlog.get_logger("structlog").info("[TNC] SESSION [" + str(self.mycallsign, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]", state=static.ARQ_SESSION_STATE)
|
||||
|
||||
|
@ -1028,7 +1024,6 @@ class DATA():
|
|||
time.sleep(0.01)
|
||||
# break if data channel is opened
|
||||
if static.ARQ_SESSION:
|
||||
# eventuell einfach nur return true um die nächste break ebene zu vermeiden?
|
||||
return True
|
||||
# if static.ARQ_SESSION:
|
||||
# break
|
||||
|
@ -1233,7 +1228,6 @@ class DATA():
|
|||
if attempt == self.data_channel_max_retries:
|
||||
static.INFO.append("DATACHANNEL;FAILED")
|
||||
structlog.get_logger("structlog").debug("[TNC] arq_open_data_channel:", transmission_uuid=self.transmission_uuid)
|
||||
# print(self.transmission_uuid)
|
||||
jsondata = {"arq":"transmission", "status" :"failed", "uuid" : self.transmission_uuid, "percent" : static.ARQ_TRANSMISSION_PERCENT, "bytesperminute" : static.ARQ_BYTES_PER_MINUTE}
|
||||
json_data_out = json.dumps(jsondata)
|
||||
sock.SOCKET_QUEUE.put(json_data_out)
|
||||
|
@ -1486,7 +1480,7 @@ class DATA():
|
|||
"""
|
||||
Controlling funktion for running a beacon
|
||||
Args:
|
||||
interval:int:
|
||||
self:
|
||||
|
||||
Returns:
|
||||
|
||||
|
@ -1686,7 +1680,7 @@ class DATA():
|
|||
|
||||
def calculate_transfer_rate_tx(self, tx_start_of_transmission:float, sentbytes:int, tx_buffer_length:int) -> list:
|
||||
"""
|
||||
Calcualte Transferrate for transmission
|
||||
Calculate transfer rate for transmission
|
||||
Args:
|
||||
tx_start_of_transmission:float:
|
||||
sentbytes:int:
|
||||
|
|
|
@ -27,6 +27,7 @@ def wait(seconds: float) -> bool:
|
|||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
|
||||
def get_crc_8(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -45,6 +46,7 @@ def get_crc_8(data) -> bytes:
|
|||
crc_data = crc_data.to_bytes(1, byteorder='big')
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_16(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -63,6 +65,7 @@ def get_crc_16(data) -> bytes:
|
|||
crc_data = crc_data.to_bytes(2, byteorder='big')
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_24(data) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -84,6 +87,7 @@ def get_crc_24(data) -> bytes:
|
|||
crc_data = crc_data.to_bytes(3, byteorder='big')
|
||||
return crc_data
|
||||
|
||||
|
||||
def get_crc_32(data: bytes) -> bytes:
|
||||
"""Author: DJ2LS
|
||||
|
||||
|
@ -102,6 +106,7 @@ def get_crc_32(data: bytes) -> bytes:
|
|||
crc_data = crc_data.to_bytes(4, byteorder='big')
|
||||
return crc_data
|
||||
|
||||
|
||||
def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
||||
"""
|
||||
|
||||
|
@ -136,6 +141,7 @@ def add_to_heard_stations(dxcallsign, dxgrid, datatype, snr, offset, frequency):
|
|||
# item = [dxcallsign, int(time.time())]
|
||||
# static.HEARD_STATIONS[idx] = item
|
||||
|
||||
|
||||
def callsign_to_bytes(callsign) -> bytes:
|
||||
"""
|
||||
|
||||
|
@ -235,6 +241,7 @@ def bytes_to_callsign(bytestring: bytes) -> bytes:
|
|||
ssid = ord(bytes(decoded[-1], "utf-8"))
|
||||
return bytes(f"{callsign}-{ssid}", "utf-8")
|
||||
|
||||
|
||||
def check_callsign(callsign:bytes, crc_to_check:bytes):
|
||||
"""
|
||||
Funktion to check a crc against a callsign to calculate the ssid by generating crc until we got it
|
||||
|
@ -270,9 +277,10 @@ def check_callsign(callsign:bytes, crc_to_check:bytes):
|
|||
|
||||
return [False, ""]
|
||||
|
||||
|
||||
def encode_grid(grid):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
grid:string: maidenhead QTH locater [a-r][a-r][0-9][0-9][a-x][a-x]
|
||||
Returns:
|
||||
|
@ -305,7 +313,7 @@ def encode_grid(grid):
|
|||
|
||||
def decode_grid(b_code_word:bytes):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
b_code_word:bytes: 4 bytes with 26 bit valid data LSB
|
||||
Returns:
|
||||
|
@ -334,7 +342,7 @@ def decode_grid(b_code_word:bytes):
|
|||
|
||||
def encode_call(call):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
call:string: ham radio call sign [A-Z,0-9], last char SSID 0-63
|
||||
|
||||
|
@ -355,9 +363,10 @@ def encode_call(call):
|
|||
|
||||
return out_code_word.to_bytes(length=6, byteorder='big')
|
||||
|
||||
|
||||
def decode_call(b_code_word:bytes):
|
||||
"""
|
||||
@auther: DB1UJ
|
||||
@author: DB1UJ
|
||||
Args:
|
||||
b_code_word:bytes: 6 bytes with 6 bits/sign valid data char signs LSB
|
||||
|
||||
|
|
Loading…
Reference in a new issue