mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
multimode testrun
added multimode test and added a SM and MM for single mode and multimode
This commit is contained in:
parent
9565005f71
commit
e79aa0b457
4 changed files with 288 additions and 7 deletions
|
@ -22,26 +22,34 @@ set(FRAMESPERBURST 3)
|
|||
set(BURSTS 1)
|
||||
set(TESTFRAMES 3)
|
||||
|
||||
add_test(NAME 001_highsnr_stdio_P_C
|
||||
add_test(NAME 001_highsnr_stdio_P_C_SM
|
||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test/001_highsnr_stdio_audio;
|
||||
python3 test_tx.py --mode datac0 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||
freedv_data_raw_rx datac0 - - --framesperburst ${FRAMESPERBURST} | hexdump -C")
|
||||
set_tests_properties(001_highsnr_stdio_P_C PROPERTIES PASS_REGULAR_EXPRESSION "HELLO WORLD")
|
||||
set_tests_properties(001_highsnr_stdio_P_C_SM PROPERTIES PASS_REGULAR_EXPRESSION "HELLO WORLD")
|
||||
|
||||
add_test(NAME 001_highsnr_stdio_C_P
|
||||
add_test(NAME 001_highsnr_stdio_C_P_SM
|
||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test/001_highsnr_stdio_audio;
|
||||
freedv_data_raw_tx datac0 --testframes ${TESTFRAMES} --bursts ${BURSTS} --framesperburst ${FRAMESPERBURST} /dev/zero - |
|
||||
python3 test_rx.py --mode datac0 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
||||
set_tests_properties(001_highsnr_stdio_C_P PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||
set_tests_properties(001_highsnr_stdio_C_P_SM PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||
|
||||
add_test(NAME 001_highsnr_stdio_P_P
|
||||
add_test(NAME 001_highsnr_stdio_P_P_SM
|
||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test/001_highsnr_stdio_audio;
|
||||
python3 test_tx.py --mode datac0 --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||
python3 test_rx.py --mode datac0 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
||||
set_tests_properties(001_highsnr_stdio_P_P PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||
set_tests_properties(001_highsnr_stdio_P_P_SM PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: ${BURSTS} RECEIVED FRAMES: ${FRAMESPERBURST}")
|
||||
|
||||
add_test(NAME 001_highsnr_stdio_P_P_MM
|
||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test/001_highsnr_stdio_audio;
|
||||
python3 test_multimode_tx.py --delay 500 --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS} |
|
||||
python3 test_multimode_rx.py --framesperburst ${FRAMESPERBURST} --bursts ${BURSTS}")
|
||||
set_tests_properties(001_highsnr_stdio_P_P_MM PROPERTIES PASS_REGULAR_EXPRESSION "DATAC0: ${BURSTS}/${FRAMESPERBURST} DATAC1: ${BURSTS}/${FRAMESPERBURST} DATAC3: ${BURSTS}/${FRAMESPERBURST}")
|
||||
|
|
144
test/001_highsnr_stdio_audio/test_multimode_rx.py
Executable file
144
test/001_highsnr_stdio_audio/test_multimode_rx.py
Executable file
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pyaudio
|
||||
import audioop
|
||||
import time
|
||||
import argparse
|
||||
import sys
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import pathlib
|
||||
sys.path.insert(0,'..')
|
||||
import codec2
|
||||
|
||||
#--------------------------------------------GET PARAMETER INPUTS
|
||||
parser = argparse.ArgumentParser(description='Simons TEST TNC')
|
||||
parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int)
|
||||
parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=0, type=int)
|
||||
parser.add_argument('--audioinput', dest="AUDIO_INPUT", default=0, type=int)
|
||||
parser.add_argument('--debug', dest="DEBUGGING_MODE", action="store_true")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
N_BURSTS = args.N_BURSTS
|
||||
N_FRAMES_PER_BURST = args.N_FRAMES_PER_BURST
|
||||
AUDIO_INPUT_DEVICE = args.AUDIO_INPUT
|
||||
|
||||
|
||||
# SET COUNTERS
|
||||
rx_total_frames_datac0 = 0
|
||||
rx_frames_datac0 = 0
|
||||
rx_bursts_datac0 = 0
|
||||
|
||||
rx_total_frames_datac1 = 0
|
||||
rx_frames_datac1 = 0
|
||||
rx_bursts_datac1 = 0
|
||||
|
||||
rx_total_frames_datac3 = 0
|
||||
rx_frames_datac3 = 0
|
||||
rx_bursts_datac3 = 0
|
||||
|
||||
|
||||
# open codec2 instance
|
||||
datac0_freedv = cast(codec2.api.freedv_open(14), c_void_p)
|
||||
datac0_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac0_freedv)/8)
|
||||
datac0_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac0_freedv)
|
||||
datac0_bytes_out = create_string_buffer(datac0_bytes_per_frame * 2)
|
||||
codec2.api.freedv_set_frames_per_burst(datac0_freedv,N_FRAMES_PER_BURST)
|
||||
datac0_buffer = bytes()
|
||||
|
||||
datac1_freedv = cast(codec2.api.freedv_open(10), c_void_p)
|
||||
datac1_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac1_freedv)/8)
|
||||
datac1_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac1_freedv)
|
||||
datac1_bytes_out = create_string_buffer(datac1_bytes_per_frame * 2)
|
||||
codec2.api.freedv_set_frames_per_burst(datac1_freedv,N_FRAMES_PER_BURST)
|
||||
datac1_buffer = bytes()
|
||||
|
||||
datac3_freedv = cast(codec2.api.freedv_open(12), c_void_p)
|
||||
datac3_bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(datac3_freedv)/8)
|
||||
datac3_n_max_modem_samples = codec2.api.freedv_get_n_max_modem_samples(datac3_freedv)
|
||||
datac3_bytes_out = create_string_buffer(datac3_bytes_per_frame * 2)
|
||||
codec2.api.freedv_set_frames_per_burst(datac3_freedv,N_FRAMES_PER_BURST)
|
||||
datac3_buffer = bytes()
|
||||
|
||||
# check if we want to use an audio device then do an pyaudio init
|
||||
if AUDIO_INPUT_DEVICE != 0:
|
||||
p = pyaudio.PyAudio()
|
||||
# --------------------------------------------OPEN AUDIO CHANNEL RX
|
||||
stream_rx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=48000,
|
||||
frames_per_buffer=16,
|
||||
input=True,
|
||||
input_device_index=5
|
||||
)
|
||||
|
||||
|
||||
timeout = time.time() + 10
|
||||
receive = True
|
||||
|
||||
while receive and time.time() < timeout:
|
||||
if AUDIO_INPUT_DEVICE != 0:
|
||||
data_in = stream_rx.read(1024, exception_on_overflow=True)
|
||||
data_in = audioop.ratecv(data_in, 2, 1, 48000, 8000, None)
|
||||
data_in = data_in[0] # .rstrip(b'\x00')
|
||||
else:
|
||||
data_in = sys.stdin.buffer.read(1024)
|
||||
|
||||
|
||||
datac0_buffer += data_in
|
||||
datac1_buffer += data_in
|
||||
datac3_buffer += data_in
|
||||
|
||||
|
||||
datac0_nin = codec2.api.freedv_nin(datac0_freedv) * 2
|
||||
|
||||
if len(datac0_buffer) >= (datac0_nin):
|
||||
datac0_audio = datac0_buffer[:datac0_nin]
|
||||
datac0_buffer = datac0_buffer[datac0_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_audio) # demodulate audio
|
||||
if nbytes == datac0_bytes_per_frame:
|
||||
rx_total_frames_datac0 = rx_total_frames_datac0 + 1
|
||||
rx_frames_datac0 = rx_frames_datac0 + 1
|
||||
|
||||
if rx_frames_datac0 == N_FRAMES_PER_BURST:
|
||||
rx_frames_datac0 = 0
|
||||
rx_bursts_datac0 = rx_bursts_datac0 + 1
|
||||
|
||||
|
||||
datac1_nin = codec2.api.freedv_nin(datac1_freedv) * 2
|
||||
if len(datac1_buffer) >= (datac1_nin):
|
||||
datac1_audio = datac1_buffer[:datac1_nin]
|
||||
datac1_buffer = datac1_buffer[datac1_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_audio) # demodulate audio
|
||||
if nbytes == datac1_bytes_per_frame:
|
||||
rx_total_frames_datac1 = rx_total_frames_datac1 + 1
|
||||
rx_frames_datac1 = rx_frames_datac1 + 1
|
||||
|
||||
if rx_frames_datac1 == N_FRAMES_PER_BURST:
|
||||
rx_frames_datac1 = 0
|
||||
rx_bursts_datac1 = rx_bursts_datac1 + 1
|
||||
|
||||
datac3_nin = codec2.api.freedv_nin(datac3_freedv) * 2
|
||||
if len(datac3_buffer) >= (datac3_nin):
|
||||
datac3_audio = datac3_buffer[:datac3_nin]
|
||||
datac3_buffer = datac3_buffer[datac3_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_audio) # demodulate audio
|
||||
if nbytes == datac3_bytes_per_frame:
|
||||
rx_total_frames_datac3 = rx_total_frames_datac3 + 1
|
||||
rx_frames_datac3 = rx_frames_datac3 + 1
|
||||
|
||||
if rx_frames_datac3 == N_FRAMES_PER_BURST:
|
||||
rx_frames_datac3 = 0
|
||||
rx_bursts_datac3 = rx_bursts_datac3 + 1
|
||||
|
||||
|
||||
if rx_bursts_datac0 == N_BURSTS and rx_bursts_datac1 == N_BURSTS and rx_bursts_datac3 == N_BURSTS:
|
||||
receive = False
|
||||
|
||||
# INFO IF WE REACHED TIMEOUT
|
||||
if time.time() > timeout:
|
||||
print(f"TIMEOUT REACHED", file=sys.stderr)
|
||||
|
||||
print(f"DATAC0: {rx_bursts_datac0}/{rx_total_frames_datac0} DATAC1: {rx_bursts_datac1}/{rx_total_frames_datac1} DATAC3: {rx_bursts_datac3}/{rx_total_frames_datac3}", file=sys.stderr)
|
122
test/001_highsnr_stdio_audio/test_multimode_tx.py
Normal file
122
test/001_highsnr_stdio_audio/test_multimode_tx.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import pathlib
|
||||
import pyaudio
|
||||
import time
|
||||
import threading
|
||||
import audioop
|
||||
import argparse
|
||||
import sys
|
||||
sys.path.insert(0,'..')
|
||||
import codec2
|
||||
|
||||
|
||||
# GET PARAMETER INPUTS
|
||||
parser = argparse.ArgumentParser(description='FreeDATA TEST')
|
||||
parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int)
|
||||
parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=0, type=int)
|
||||
parser.add_argument('--delay', dest="DELAY_BETWEEN_BURSTS", default=0, type=int)
|
||||
parser.add_argument('--audiooutput', dest="AUDIO_OUTPUT", default=0, type=int)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
N_BURSTS = args.N_BURSTS
|
||||
N_FRAMES_PER_BURST = args.N_FRAMES_PER_BURST
|
||||
DELAY_BETWEEN_BURSTS = args.DELAY_BETWEEN_BURSTS/1000
|
||||
AUDIO_OUTPUT_DEVICE = args.AUDIO_OUTPUT
|
||||
|
||||
|
||||
# AUDIO PARAMETERS
|
||||
AUDIO_FRAMES_PER_BUFFER = 2048
|
||||
MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000
|
||||
AUDIO_SAMPLE_RATE_TX = 48000
|
||||
|
||||
|
||||
|
||||
if AUDIO_OUTPUT_DEVICE != 0:
|
||||
# pyaudio init
|
||||
p = pyaudio.PyAudio()
|
||||
stream_tx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=AUDIO_SAMPLE_RATE_TX,
|
||||
frames_per_buffer=AUDIO_FRAMES_PER_BUFFER, #n_nom_modem_samples
|
||||
output=True,
|
||||
output_device_index=AUDIO_OUTPUT_DEVICE,
|
||||
)
|
||||
|
||||
|
||||
modes = [14,10,12]
|
||||
for m in modes:
|
||||
|
||||
freedv = cast(codec2.api.freedv_open(m), c_void_p)
|
||||
|
||||
n_tx_modem_samples = codec2.api.freedv_get_n_tx_modem_samples(freedv)
|
||||
mod_out = create_string_buffer(2*n_tx_modem_samples)
|
||||
|
||||
n_tx_preamble_modem_samples = codec2.api.freedv_get_n_tx_preamble_modem_samples(freedv)
|
||||
mod_out_preamble = create_string_buffer(2*n_tx_preamble_modem_samples)
|
||||
|
||||
n_tx_postamble_modem_samples = codec2.api.freedv_get_n_tx_postamble_modem_samples(freedv)
|
||||
mod_out_postamble = create_string_buffer(2*n_tx_postamble_modem_samples)
|
||||
|
||||
bytes_per_frame = int(codec2.api.freedv_get_bits_per_modem_frame(freedv) / 8)
|
||||
payload_per_frame = bytes_per_frame - 2
|
||||
|
||||
|
||||
# data binary string
|
||||
data_out = b'HELLO WORLD!'
|
||||
|
||||
buffer = bytearray(payload_per_frame)
|
||||
# set buffersize to length of data which will be send
|
||||
buffer[:len(data_out)] = data_out
|
||||
|
||||
crc = ctypes.c_ushort(codec2.api.freedv_gen_crc16(bytes(buffer), payload_per_frame)) # generate CRC16
|
||||
# convert crc to 2 byte hex string
|
||||
crc = crc.value.to_bytes(2, byteorder='big')
|
||||
buffer += crc # append crc16 to buffer
|
||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||
|
||||
for i in range(1,N_BURSTS+1):
|
||||
|
||||
# write preamble to txbuffer
|
||||
codec2.api.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
txbuffer = bytes(mod_out_preamble)
|
||||
|
||||
# create modulaton for N = FRAMESPERBURST and append it to txbuffer
|
||||
for n in range(1,N_FRAMES_PER_BURST+1):
|
||||
|
||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||
codec2.api.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and save it into mod_out pointer
|
||||
|
||||
txbuffer += bytes(mod_out)
|
||||
|
||||
# append postamble to txbuffer
|
||||
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
txbuffer += bytes(mod_out_postamble)
|
||||
|
||||
# append a delay between bursts as audio silence
|
||||
samples_delay = int(MODEM_SAMPLE_RATE*DELAY_BETWEEN_BURSTS)
|
||||
mod_out_silence = create_string_buffer(samples_delay)
|
||||
txbuffer += bytes(mod_out_silence)
|
||||
|
||||
# check if we want to use an audio device or stdout
|
||||
if AUDIO_OUTPUT_DEVICE != 0:
|
||||
|
||||
# sample rate conversion from 8000Hz to 48000Hz
|
||||
audio = audioop.ratecv(txbuffer,2,1,MODEM_SAMPLE_RATE, AUDIO_SAMPLE_RATE_TX, None)
|
||||
stream_tx.write(audio[0])
|
||||
|
||||
else:
|
||||
# print data to terminal for piping the output to other programs
|
||||
sys.stdout.buffer.write(txbuffer)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
# and at last check if we had an openend pyaudio instance and close it
|
||||
if AUDIO_OUTPUT_DEVICE != 0:
|
||||
stream_tx.close()
|
||||
p.terminate()
|
|
@ -4,6 +4,7 @@
|
|||
import ctypes
|
||||
from ctypes import *
|
||||
import sys
|
||||
import pathlib
|
||||
from enum import Enum
|
||||
|
||||
print("loading codec2 module", file=sys.stderr)
|
||||
|
@ -14,7 +15,9 @@ class FREEDV_MODE(Enum):
|
|||
datac0 = 14
|
||||
datac1 = 10
|
||||
datac3 = 12
|
||||
|
||||
|
||||
def FREEDV_GET_MODE(mode):
|
||||
return FREEDV_MODE[mode].value
|
||||
|
||||
|
||||
|
||||
|
@ -22,6 +25,7 @@ class FREEDV_MODE(Enum):
|
|||
libname = "libcodec2.so"
|
||||
api = ctypes.CDLL(libname)
|
||||
|
||||
|
||||
# ctypes function init
|
||||
|
||||
api.freedv_open.argype = [c_int]
|
||||
|
@ -54,6 +58,9 @@ api.freedv_set_frames_per_burst.restype = c_void_p
|
|||
api.freedv_get_rx_status.argtype = [c_void_p]
|
||||
api.freedv_get_rx_status.restype = c_int
|
||||
|
||||
api.freedv_get_modem_stats.argtype = [c_void_p, c_void_p, c_void_p]
|
||||
api.freedv_get_modem_stats.restype = c_int
|
||||
|
||||
api.freedv_get_n_tx_postamble_modem_samples.argtype = [c_void_p]
|
||||
api.freedv_get_n_tx_postamble_modem_samples.restype = c_int
|
||||
|
||||
|
|
Loading…
Reference in a new issue