2020-12-23 16:48:54 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 23 07 : 04 : 24 2020
@author : DJ2LS
"""
import ctypes
from ctypes import *
import pathlib
import pyaudio
import audioop
import sys
2020-12-26 18:27:09 +00:00
import logging
2020-12-23 16:48:54 +00:00
2020-12-28 14:20:51 +00:00
2020-12-23 16:48:54 +00:00
import static
2020-12-27 21:38:49 +00:00
import arq
#arq = arq.ARQ()
2020-12-23 16:48:54 +00:00
class RF ( ) :
def __init__ ( self ) :
2021-01-05 14:03:41 +00:00
#self.p = pyaudio.PyAudio()
#self.defaultFrames = static.DEFAULT_FRAMES
#self.audio_input_device = static.AUDIO_INPUT_DEVICE
#self.audio_output_device = static.AUDIO_OUTPUT_DEVICE
#self.tx_sample_state = static.TX_SAMPLE_STATE
#self.rx_sample_state = static.RX_SAMPLE_STATE
#self.audio_sample_rate = static.AUDIO_SAMPLE_RATE
#self.modem_sample_rate = static.MODEM_SAMPLE_RATE
#self.audio_frames_per_buffer = static.AUDIO_FRAMES_PER_BUFFER
#self.audio_channels = static.AUDIO_CHANNELS
#self.format = pyaudio.paInt16
#self.stream = None
2020-12-28 14:20:51 +00:00
2020-12-26 10:02:14 +00:00
libname = pathlib . Path ( ) . absolute ( ) / " codec2/build_linux/src/libcodec2.so "
2020-12-23 16:48:54 +00:00
self . c_lib = ctypes . CDLL ( libname )
2021-01-05 14:03:41 +00:00
#self.mode = static.FREEDV_MODE # define mode
2020-12-28 14:20:51 +00:00
2021-01-05 14:03:41 +00:00
#self.freedv = self.c_lib.freedv_open(self.mode)
#self.bytes_per_frame = int(self.c_lib.freedv_get_bits_per_modem_frame(self.freedv)/8)
#self.payload_per_frame = self.bytes_per_frame -2
#self.n_tx_modem_samples = self.c_lib.freedv_get_n_tx_modem_samples(self.freedv)*2 #get n_tx_modem_samples which defines the size of the modulation object
#self.n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(self.freedv)
#self.n_nom_modem_samples = self.c_lib.freedv_get_n_nom_modem_samples(self.freedv)
#self.nin = self.c_lib.freedv_nin(self.freedv)
#static.FREEDV_BYTES_PER_FRAME = self.bytes_per_frame
#static.FREEDV_PAYLOAD_PER_FRAME = self.payload_per_frame
#print(static.AUDIO_INPUT_DEVICE)
# Open Audio Channel once
self . p = pyaudio . PyAudio ( )
self . stream_rx = self . p . open ( format = pyaudio . paInt16 ,
channels = static . AUDIO_CHANNELS ,
rate = static . AUDIO_SAMPLE_RATE ,
frames_per_buffer = 4096 ,
input = True ,
input_device_index = static . AUDIO_INPUT_DEVICE ,
)
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
2020-12-23 16:48:54 +00:00
# GET DATA AND MODULATE IT
2020-12-27 21:38:49 +00:00
2021-01-05 14:03:41 +00:00
def Transmit ( self , mode , data_out ) :
static . MODEM_RECEIVE = False
self . c_lib . freedv_open . restype = ctypes . POINTER ( ctypes . c_ubyte )
freedv = self . c_lib . freedv_open ( mode )
bytes_per_frame = int ( self . c_lib . freedv_get_bits_per_modem_frame ( freedv ) / 8 )
payload_per_frame = bytes_per_frame - 2
n_nom_modem_samples = self . c_lib . freedv_get_n_nom_modem_samples ( freedv )
n_tx_modem_samples = self . c_lib . freedv_get_n_tx_modem_samples ( freedv ) * 2 #get n_tx_modem_samples which defines the size of the modulation object
mod_out = ctypes . c_short * n_tx_modem_samples
mod_out = mod_out ( )
2020-12-28 14:20:51 +00:00
2021-01-05 14:03:41 +00:00
data_list = [ data_out [ i : i + payload_per_frame ] for i in range ( 0 , len ( data_out ) , payload_per_frame ) ] # split incomming bytes to size of 30bytes, create a list and loop through it
2020-12-28 14:20:51 +00:00
data_list_length = len ( data_list )
for i in range ( data_list_length ) : # LOOP THROUGH DATA LIST
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
if mode < 10 : # don't generate CRC16 for modes 0 - 9
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
buffer = bytearray ( bytes_per_frame ) # use this if no CRC16 checksum is required
2020-12-28 14:20:51 +00:00
buffer [ : len ( data_list [ i ] ) ] = data_list [ i ] # set buffersize to length of data which will be send
2020-12-27 21:38:49 +00:00
2021-01-05 14:03:41 +00:00
if mode > = 10 : #generate CRC16 for modes 10-12..
2020-12-27 21:38:49 +00:00
2021-01-05 14:03:41 +00:00
buffer = bytearray ( payload_per_frame ) # use this if CRC16 checksum is required ( DATA1-3)
2020-12-28 14:20:51 +00:00
buffer [ : len ( data_list [ i ] ) ] = data_list [ i ] # set buffersize to length of data which will be send
2021-01-05 14:03:41 +00:00
crc = ctypes . c_ushort ( self . c_lib . freedv_gen_crc16 ( bytes ( buffer ) , payload_per_frame ) ) # generate CRC16
2020-12-28 14:20:51 +00:00
crc = crc . value . to_bytes ( 2 , byteorder = ' big ' ) # convert crc to 2 byte hex string
buffer + = crc # append crc16 to buffer
2021-01-05 14:03:41 +00:00
data = ( ctypes . c_ubyte * bytes_per_frame ) . from_buffer_copy ( buffer )
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
self . c_lib . freedv_rawdatatx ( freedv , mod_out , data ) # modulate DATA and safe it into mod_out pointer
p = pyaudio . PyAudio ( )
stream_tx = p . open ( format = pyaudio . paInt16 ,
channels = static . AUDIO_CHANNELS ,
rate = static . AUDIO_SAMPLE_RATE ,
frames_per_buffer = n_nom_modem_samples ,
2020-12-23 16:48:54 +00:00
output = True ,
2021-01-05 14:03:41 +00:00
output_device_index = static . AUDIO_OUTPUT_DEVICE ,
2020-12-23 16:48:54 +00:00
)
2021-01-05 14:03:41 +00:00
audio = audioop . ratecv ( mod_out , 2 , 1 , static . MODEM_SAMPLE_RATE , static . AUDIO_SAMPLE_RATE , static . TX_SAMPLE_STATE )
stream_tx . write ( audio [ 0 ] )
print ( " KILL " )
stream_tx . stop_stream ( )
stream_tx . close ( )
p . terminate ( )
2020-12-23 16:48:54 +00:00
return mod_out
# DEMODULATE DATA AND RETURN IT
2021-01-05 14:03:41 +00:00
def Receive ( self , mode ) :
static . MODEM_RECEIVE = True
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
self . c_lib . freedv_open . restype = ctypes . POINTER ( ctypes . c_ubyte )
freedv = self . c_lib . freedv_open ( mode )
#n_max_modem_samples = self.c_lib.freedv_get_n_max_modem_samples(freedv)
bytes_per_frame = int ( self . c_lib . freedv_get_bits_per_modem_frame ( freedv ) / 8 )
2020-12-23 16:48:54 +00:00
2021-01-05 14:03:41 +00:00
#####################################################################################################
bytes_out = ( ctypes . c_ubyte * bytes_per_frame )
bytes_out = bytes_out ( ) #get pointer from bytes_out
#i = 0
while static . MODEM_RECEIVE == True : # Listne to audio until data arrives
nin = self . c_lib . freedv_nin ( freedv )
data_in = self . stream_rx . read ( nin , exception_on_overflow = False )
2020-12-25 21:55:56 +00:00
2021-01-05 14:03:41 +00:00
nbytes = self . c_lib . freedv_rawdatarx ( freedv , bytes_out , data_in ) # Demodulated data and get number of demodulated bytes
if nbytes == bytes_per_frame : # make sure, we receive a full frame
if mode > = 10 :
print ( " MODE: " + str ( mode ) + " DATA: " + str ( bytes ( bytes_out [ : - 2 ] ) ) )
else :
print ( " MODE: " + str ( mode ) + " DATA: " + str ( bytes ( bytes_out ) ) )
self . c_lib . freedv_set_sync ( freedv , 0 ) #FORCE UNSYNC
2020-12-27 21:38:49 +00:00
# CHECK IF FRAMETYPE CONTAINS ACK------------------------
frametype = int . from_bytes ( bytes ( bytes_out [ : 1 ] ) , " big " )
2020-12-28 14:20:51 +00:00
if 50 > = frametype > = 10 :
arq . data_received ( bytes ( bytes_out [ : - 2 ] ) ) #send payload data to arq checker without CRC16
2020-12-25 21:55:56 +00:00
# CHECK IF FRAME CONTAINS ACK------------------------
2020-12-28 14:20:51 +00:00
if bytes ( bytes_out [ : 1 ] ) == b ' \7 ' :
arq . ack_received ( )
2020-12-25 21:55:56 +00:00
2020-12-23 16:48:54 +00:00
#return bytes(bytes_out[:-2])
2021-01-05 14:03:41 +00:00
#print("KILL")
#stream_rx.stop_stream()
#stream_rx.close()
#p.terminate()