mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
first attempt implementing custom api function of codec2
This commit is contained in:
parent
e998d1d3dd
commit
4004f7a02c
4 changed files with 183 additions and 108 deletions
248
modem/codec2.py
248
modem/codec2.py
|
@ -7,6 +7,8 @@ Python interface to the C-language codec2 library.
|
|||
# pylint: disable=import-outside-toplevel, attribute-defined-outside-init
|
||||
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import hashlib
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
@ -32,7 +34,8 @@ class FREEDV_MODE(Enum):
|
|||
datac4 = 18
|
||||
datac13 = 19
|
||||
datac14 = 20
|
||||
|
||||
data_ofdm_500 = 21500
|
||||
data_ofdm_2438 = 212438
|
||||
|
||||
class FREEDV_MODE_USED_SLOTS(Enum):
|
||||
"""
|
||||
|
@ -46,9 +49,8 @@ class FREEDV_MODE_USED_SLOTS(Enum):
|
|||
datac4 = [False, False, True, False, False]
|
||||
datac13 = [False, False, True, False, False]
|
||||
datac14 = [False, False, True, False, False]
|
||||
fsk_ldpc = [False, False, True, False, False]
|
||||
fsk_ldpc_0 = [False, False, True, False, False]
|
||||
fsk_ldpc_1 = [False, False, True, False, False]
|
||||
data_ofdm_500 = [False, False, True, False, False]
|
||||
data_ofdm_2438 = [True, True, True, True, True]
|
||||
|
||||
# Function for returning the mode value
|
||||
def freedv_get_mode_value_by_name(mode: str) -> int:
|
||||
|
@ -93,7 +95,6 @@ elif sys.platform in ["win32", "win64"]:
|
|||
files = glob.glob(os.path.join(script_dir, "**\\*libcodec2*.dll"), recursive=True)
|
||||
else:
|
||||
files = []
|
||||
|
||||
api = None
|
||||
for file in files:
|
||||
try:
|
||||
|
@ -108,7 +109,7 @@ for file in files:
|
|||
if api is None or "api" not in locals():
|
||||
log.critical("[C2 ] Error: Libcodec2 not loaded - Exiting")
|
||||
sys.exit(1)
|
||||
log.info("[C2 ] Libcodec2 loaded...")
|
||||
log.info("[C2 ] Libcodec2 loaded...", path=file)
|
||||
# ctypes function init
|
||||
|
||||
# api.freedv_set_tuning_range.restype = ctypes.c_int
|
||||
|
@ -170,64 +171,6 @@ api.freedv_get_n_max_modem_samples.restype = ctypes.c_int
|
|||
|
||||
api.FREEDV_FS_8000 = 8000 # type: ignore
|
||||
|
||||
# -------------------------------- FSK LDPC MODE SETTINGS
|
||||
|
||||
|
||||
class ADVANCED(ctypes.Structure):
|
||||
"""Advanced structure for fsk modes"""
|
||||
|
||||
_fields_ = [
|
||||
("interleave_frames", ctypes.c_int),
|
||||
("M", ctypes.c_int),
|
||||
("Rs", ctypes.c_int),
|
||||
("Fs", ctypes.c_int),
|
||||
("first_tone", ctypes.c_int),
|
||||
("tone_spacing", ctypes.c_int),
|
||||
("codename", ctypes.c_char_p),
|
||||
]
|
||||
|
||||
|
||||
# pylint: disable=pointless-string-statement
|
||||
"""
|
||||
adv.interleave_frames = 0 # max amplitude
|
||||
adv.M = 2 # number of fsk tones 2/4
|
||||
adv.Rs = 100 # symbol rate
|
||||
adv.Fs = 8000 # sample rate
|
||||
adv.first_tone = 1500 # first tone freq
|
||||
adv.tone_spacing = 200 # shift between tones
|
||||
adv.codename = "H_128_256_5".encode("utf-8") # code word
|
||||
|
||||
HRA_112_112 rate 0.50 (224,112) BPF: 14 not working
|
||||
HRA_56_56 rate 0.50 (112,56) BPF: 7 not working
|
||||
H_2064_516_sparse rate 0.80 (2580,2064) BPF: 258 working
|
||||
HRAb_396_504 rate 0.79 (504,396) BPF: 49 not working
|
||||
H_256_768_22 rate 0.33 (768,256) BPF: 32 working
|
||||
H_256_512_4 rate 0.50 (512,256) BPF: 32 working
|
||||
HRAa_1536_512 rate 0.75 (2048,1536) BPF: 192 not working
|
||||
H_128_256_5 rate 0.50 (256,128) BPF: 16 working
|
||||
H_4096_8192_3d rate 0.50 (8192,4096) BPF: 512 not working
|
||||
H_16200_9720 rate 0.60 (16200,9720) BPF: 1215 not working
|
||||
H_1024_2048_4f rate 0.50 (2048,1024) BPF: 128 working
|
||||
"""
|
||||
# --------------- 2 FSK H_128_256_5, 16 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV = ADVANCED() # type: ignore
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.interleave_frames = 0
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.M = 4
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.Rs = 500
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.Fs = 8000
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.first_tone = 1150 # 1150 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.tone_spacing = 200 # 200
|
||||
api.FREEDV_MODE_FSK_LDPC_0_ADV.codename = "H_128_256_5".encode("utf-8") # code word
|
||||
|
||||
# --------------- 4 H_256_512_4, 7 bytes
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV = ADVANCED() # type: ignore
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.interleave_frames = 0
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.M = 4
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.Rs = 1000
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.Fs = 8000
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.first_tone = 1150 # 1250 4fsk, 1500 2fsk
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.tone_spacing = 200
|
||||
api.FREEDV_MODE_FSK_LDPC_1_ADV.codename = "H_4096_8192_3d".encode("utf-8") # code word
|
||||
|
||||
# ------- MODEM STATS STRUCTURES
|
||||
MODEM_STATS_NC_MAX = 50 + 1 * 2
|
||||
|
@ -239,6 +182,8 @@ MODEM_STATS_MAX_F_HZ = 4000
|
|||
MODEM_STATS_MAX_F_EST = 4
|
||||
|
||||
|
||||
|
||||
|
||||
class MODEMSTATS(ctypes.Structure):
|
||||
"""Modem statistics structure"""
|
||||
|
||||
|
@ -424,33 +369,21 @@ class resampler:
|
|||
return out48
|
||||
|
||||
def open_instance(mode: int) -> ctypes.c_void_p:
|
||||
"""
|
||||
Return a codec2 instance of the type `mode`
|
||||
data_custom = 21
|
||||
|
||||
if mode in [FREEDV_MODE.data_ofdm_500.value, FREEDV_MODE.data_ofdm_2438.value]:
|
||||
custom_params = ofdm_configurations[mode]
|
||||
return ctypes.cast(
|
||||
api.freedv_open_advanced(
|
||||
data_custom,
|
||||
ctypes.byref(custom_params),
|
||||
),
|
||||
ctypes.c_void_p,
|
||||
)
|
||||
else:
|
||||
if mode not in [data_custom]:
|
||||
return ctypes.cast(api.freedv_open(mode), ctypes.c_void_p)
|
||||
|
||||
:param mode: Type of codec2 instance to return
|
||||
:type mode: Union[int, str]
|
||||
:return: C-function of the requested codec2 instance
|
||||
:rtype: ctypes.c_void_p
|
||||
"""
|
||||
# if mode in [FREEDV_MODE.fsk_ldpc_0.value]:
|
||||
# return ctypes.cast(
|
||||
# api.freedv_open_advanced(
|
||||
# FREEDV_MODE.fsk_ldpc.value,
|
||||
# ctypes.byref(api.FREEDV_MODE_FSK_LDPC_0_ADV),
|
||||
# ),
|
||||
# ctypes.c_void_p,
|
||||
# )
|
||||
#
|
||||
# if mode in [FREEDV_MODE.fsk_ldpc_1.value]:
|
||||
# return ctypes.cast(
|
||||
# api.freedv_open_advanced(
|
||||
# FREEDV_MODE.fsk_ldpc.value,
|
||||
# ctypes.byref(api.FREEDV_MODE_FSK_LDPC_1_ADV),
|
||||
# ),
|
||||
# ctypes.c_void_p,
|
||||
# )
|
||||
#
|
||||
return ctypes.cast(api.freedv_open(mode), ctypes.c_void_p)
|
||||
|
||||
def get_bytes_per_frame(mode: int) -> int:
|
||||
"""
|
||||
|
@ -465,3 +398,138 @@ def get_bytes_per_frame(mode: int) -> int:
|
|||
# TODO add close session
|
||||
# get number of bytes per frame for mode
|
||||
return int(api.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
|
||||
|
||||
MAX_UW_BITS = 64
|
||||
|
||||
class OFDM_CONFIG(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("tx_centre", ctypes.c_float), # TX Centre Audio Frequency
|
||||
("rx_centre", ctypes.c_float), # RX Centre Audio Frequency
|
||||
("fs", ctypes.c_float), # Sample Frequency
|
||||
("rs", ctypes.c_float), # Symbol Rate
|
||||
("ts", ctypes.c_float), # Symbol duration
|
||||
("tcp", ctypes.c_float), # Cyclic Prefix duration
|
||||
("timing_mx_thresh", ctypes.c_float), # Threshold for timing metrics
|
||||
("nc", ctypes.c_int), # Number of carriers
|
||||
("ns", ctypes.c_int), # Number of Symbol frames
|
||||
("np", ctypes.c_int), # Number of modem frames per packet
|
||||
("bps", ctypes.c_int), # Bits per Symbol
|
||||
("txtbits", ctypes.c_int), # Number of auxiliary data bits
|
||||
("nuwbits", ctypes.c_int), # Number of unique word bits
|
||||
("bad_uw_errors", ctypes.c_int), # Threshold for bad unique word detection
|
||||
("ftwindowwidth", ctypes.c_int), # Filter window width
|
||||
("edge_pilots", ctypes.c_int), # Edge pilots configuration
|
||||
("state_machine", ctypes.c_char_p), # Name of sync state machine used
|
||||
("codename", ctypes.c_char_p), # LDPC codename
|
||||
("tx_uw", ctypes.c_uint8 * MAX_UW_BITS), # User defined unique word
|
||||
("amp_est_mode", ctypes.c_int), # Amplitude estimator algorithm mode
|
||||
("tx_bpf_en", ctypes.c_bool), # TX BPF enable flag
|
||||
("rx_bpf_en", ctypes.c_bool), # RX BPF enable flag
|
||||
("foff_limiter", ctypes.c_bool), # Frequency offset limiter enable flag
|
||||
("amp_scale", ctypes.c_float), # Amplitude scale factor
|
||||
("clip_gain1", ctypes.c_float), # Pre-clipping gain
|
||||
("clip_gain2", ctypes.c_float), # Post-clipping gain
|
||||
("clip_en", ctypes.c_bool), # Clipping enable flag
|
||||
("mode", ctypes.c_char * 16), # OFDM mode in string form
|
||||
("data_mode", ctypes.c_char_p), # Data mode ("streaming", "burst", etc.)
|
||||
("fmin", ctypes.c_float), # Minimum frequency for tuning range
|
||||
("fmax", ctypes.c_float), # Maximum frequency for tuning range
|
||||
]
|
||||
|
||||
uw_sequence = (c_uint8 * MAX_UW_BITS)(*([1, 1, 0, 0, 1, 0, 1, 0] * 8))
|
||||
|
||||
ofdm_default_config = OFDM_CONFIG(
|
||||
tx_centre=1500.0,
|
||||
rx_centre=1500.0,
|
||||
fs=8000.0,
|
||||
rs=1.0,
|
||||
ts=0.016,
|
||||
tcp=0.006,
|
||||
timing_mx_thresh=0.10,
|
||||
nc=9,
|
||||
ns=5,
|
||||
np=29,
|
||||
bps=2,
|
||||
txtbits=0,
|
||||
nuwbits=40,
|
||||
bad_uw_errors=10,
|
||||
ftwindowwidth=80,
|
||||
edge_pilots=False,
|
||||
state_machine=b"data",
|
||||
codename=b"H_1024_2048_4f",
|
||||
tx_uw=uw_sequence,
|
||||
amp_est_mode=1,
|
||||
tx_bpf_en=False,
|
||||
rx_bpf_en=False,
|
||||
foff_limiter=False,
|
||||
amp_scale=300E3,
|
||||
clip_gain1=2.2,
|
||||
clip_gain2=0.8,
|
||||
clip_en=True,
|
||||
mode=b"CUSTOM",
|
||||
data_mode=b"streaming",
|
||||
fmin=-50.0,
|
||||
fmax=50.0,
|
||||
)
|
||||
|
||||
|
||||
class FREEDV_ADVANCED(ctypes.Structure):
|
||||
"""Advanced structure for fsk and ofdm modes"""
|
||||
_fields_ = [
|
||||
("interleave_frames", ctypes.c_int),
|
||||
("M", ctypes.c_int),
|
||||
("Rs", ctypes.c_int),
|
||||
("Fs", ctypes.c_int),
|
||||
("first_tone", ctypes.c_int),
|
||||
("tone_spacing", ctypes.c_int),
|
||||
("codename", ctypes.c_char_p),
|
||||
("config", ctypes.POINTER(OFDM_CONFIG))
|
||||
]
|
||||
|
||||
api.freedv_open_advanced.argtypes = [ctypes.c_int, ctypes.POINTER(FREEDV_ADVANCED)]
|
||||
api.freedv_open_advanced.restype = ctypes.c_void_p
|
||||
|
||||
def create_default_ofdm_config():
|
||||
return FREEDV_ADVANCED(
|
||||
interleave_frames = 0,
|
||||
M = 2,
|
||||
Rs = 100,
|
||||
Fs = 8000,
|
||||
first_tone = 1000,
|
||||
tone_spacing = 200,
|
||||
codename = "H_256_512_4".encode("utf-8"),
|
||||
config = ctypes.pointer(ofdm_default_config),
|
||||
)
|
||||
|
||||
|
||||
data_ofdm_2438_config = create_default_ofdm_config()
|
||||
data_ofdm_2438_config.config.contents.ns = 5
|
||||
data_ofdm_2438_config.config.contents.np = 52
|
||||
data_ofdm_2438_config.config.contents.tcp = 0.005
|
||||
data_ofdm_2438_config.config.contents.ts = 0.018
|
||||
data_ofdm_2438_config.config.contents.nc = 39
|
||||
data_ofdm_2438_config.config.contents.nuwbits = 12
|
||||
data_ofdm_2438_config.config.contents.timing_mx_thresh = 0.10
|
||||
data_ofdm_2438_config.config.contents.bad_uw_errors = 8
|
||||
data_ofdm_2438_config.config.contents.amp_est_mode = 1
|
||||
data_ofdm_2438_config.config.contents.amp_scale = 145E3
|
||||
data_ofdm_2438_config.config.contents.codename = b"H_16200_9720"
|
||||
data_ofdm_2438_config.config.contents.clip_gain1 = 2.7;
|
||||
data_ofdm_2438_config.config.contents.clip_gain2 = 0.8;
|
||||
data_ofdm_2438_config.config.contents.timing_mx_thresh = 0.10;
|
||||
data_ofdm_2438_config.config.contents.tx_bpf_en = False
|
||||
data_ofdm_2438_config.config.contents.rx_bpf_en = False
|
||||
# Fill the tx_uw field with the uw_sequence, and pad the rest with zeros if necessary
|
||||
uw_sequence = [1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1]
|
||||
data_ofdm_2438_config.tx_uw = (ctypes.c_uint8 * MAX_UW_BITS)(*(uw_sequence + [0]*(MAX_UW_BITS-len(uw_sequence))))
|
||||
|
||||
|
||||
data_ofdm_500_config = create_default_ofdm_config()
|
||||
|
||||
|
||||
ofdm_configurations = {
|
||||
FREEDV_MODE.data_ofdm_500.value: data_ofdm_500_config,
|
||||
FREEDV_MODE.data_ofdm_2438.value: data_ofdm_2438_config
|
||||
|
||||
}
|
||||
|
|
|
@ -61,5 +61,4 @@ class TxCommand():
|
|||
def test(self, event_queue: queue.Queue):
|
||||
self.emit_event(event_queue)
|
||||
self.logger.info(self.log_message())
|
||||
frame = self.build_frame()
|
||||
return frame
|
||||
return self.build_frame()
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from command import TxCommand
|
||||
|
||||
from codec2 import FREEDV_MODE
|
||||
class CQCommand(TxCommand):
|
||||
|
||||
def build_frame(self):
|
||||
return self.frame_factory.build_cq()
|
||||
|
||||
def get_tx_mode(self):
|
||||
return FREEDV_MODE.data_ofdm_500
|
||||
|
|
|
@ -13,17 +13,17 @@ class Demodulator():
|
|||
MODE_DICT = {}
|
||||
# Iterate over the FREEDV_MODE enum members
|
||||
for mode in codec2.FREEDV_MODE:
|
||||
MODE_DICT[mode.value] = {
|
||||
'decode': False,
|
||||
'bytes_per_frame': None,
|
||||
'bytes_out': None,
|
||||
'audio_buffer': None,
|
||||
'nin': None,
|
||||
'instance': None,
|
||||
'state_buffer': [],
|
||||
'name': mode.name.upper(),
|
||||
'decoding_thread': None
|
||||
}
|
||||
MODE_DICT[mode.value] = {
|
||||
'decode': False,
|
||||
'bytes_per_frame': None,
|
||||
'bytes_out': None,
|
||||
'audio_buffer': None,
|
||||
'nin': None,
|
||||
'instance': None,
|
||||
'state_buffer': [],
|
||||
'name': mode.name.upper(),
|
||||
'decoding_thread': None
|
||||
}
|
||||
|
||||
def __init__(self, config, audio_rx_q, data_q_rx, states, event_manager, service_queue, fft_queue):
|
||||
self.log = structlog.get_logger("Demodulator")
|
||||
|
@ -71,15 +71,20 @@ class Demodulator():
|
|||
"""
|
||||
|
||||
# create codec2 instance
|
||||
c2instance = ctypes.cast(
|
||||
codec2.api.freedv_open(mode), ctypes.c_void_p
|
||||
)
|
||||
#c2instance = ctypes.cast(
|
||||
# codec2.api.freedv_open(mode), ctypes.c_void_p
|
||||
#)
|
||||
print(mode)
|
||||
c2instance = codec2.open_instance(mode)
|
||||
print(c2instance)
|
||||
print("hat geklappt...")
|
||||
|
||||
|
||||
# get bytes per frame
|
||||
bytes_per_frame = int(
|
||||
codec2.api.freedv_get_bits_per_modem_frame(c2instance) / 8
|
||||
)
|
||||
|
||||
print(f"bytes per frame: {bytes_per_frame}")
|
||||
# create byte out buffer
|
||||
bytes_out = ctypes.create_string_buffer(bytes_per_frame)
|
||||
|
||||
|
|
Loading…
Reference in a new issue