mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Add files via upload
This commit is contained in:
parent
156770a39c
commit
ae7213b1e1
92
__main__.py
Normal file
92
__main__.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 11 16:54:35 2020
|
||||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
import socketserver
|
||||
|
||||
import freedv
|
||||
import sound
|
||||
import tnc
|
||||
import commands
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser(description='Simons TEST TNC')
|
||||
parser.add_argument('--rx-sound-device', dest="audio_input_device", default=False, help="The sound card used to rx.", type=int)
|
||||
parser.add_argument('--tx-sound-device', dest="audio_output_device", default=False, help="The sound card used to tx.", type=int)
|
||||
parser.add_argument('--list-sound-device', dest="list_sound_devices", action='store_true', help="List audio devices")
|
||||
parser.add_argument('--port', dest="socket_port", default=9000, help="Set the port, the socket is listening on.", type=int)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_sound_devices:
|
||||
for line in commands.Helpers.getAudioDevices():
|
||||
print(line)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel("INFO") #DEBUG>INFO>WARNING>ERROR>CRITICAL
|
||||
logger.info("SIMONS ERSTES TNC PROGRAMM....DURCHHALTEN!")
|
||||
|
||||
#LADE FreeDV Klasse sonst Fehler
|
||||
try:
|
||||
modem = freedv.FreeDV()
|
||||
except OSError:
|
||||
logger.error("FREEDV NICHT GEFUNDEN")
|
||||
sys.exit(0)
|
||||
|
||||
#LADE Audio Klasse sonst Fehler
|
||||
try:
|
||||
audio = sound.Audio(
|
||||
defaultFrames = 1024 * 8,
|
||||
audio_input_device=args.audio_input_device,
|
||||
audio_output_device=args.audio_output_device,
|
||||
tx_sample_state = None,
|
||||
audio_sample_rate=48000,
|
||||
modem_sample_rate=8000,
|
||||
frames_per_buffer=1024,
|
||||
audio_channels=1,
|
||||
)
|
||||
audio.Record()
|
||||
|
||||
except OSError:
|
||||
logger.error("AUDIO NICHT GEFUNDEN")
|
||||
sys.exit(0)
|
||||
|
||||
#LADE TNC Klasse sonst Fehler
|
||||
try:
|
||||
HOST, PORT = "localhost", args.socket_port
|
||||
try:
|
||||
logger.info("Starting SOCKET SERVER")
|
||||
server = socketserver.TCPServer((HOST, PORT), tnc.MyTCPHandler)
|
||||
server.serve_forever()
|
||||
finally:
|
||||
server.server_close()
|
||||
|
||||
except OSError:
|
||||
logger.error("TNC NICHT GEFUNDEN")
|
||||
sys.exit(0)
|
||||
|
||||
####################### TEST BEREICH ############################
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
133
commands.py
Normal file
133
commands.py
Normal file
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 11 23:10:21 2020
|
||||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
import freedv
|
||||
import logging
|
||||
import sound
|
||||
|
||||
import pyaudio
|
||||
|
||||
class Helpers():
|
||||
|
||||
def crc16(data: bytes):
|
||||
|
||||
#https://stackoverflow.com/a/60604183
|
||||
|
||||
|
||||
xor_in = 0x0000 # initial value
|
||||
xor_out = 0x0000 # final XOR value
|
||||
poly = 0x8005 # generator polinom (normal form)
|
||||
|
||||
reg = xor_in
|
||||
for octet in data:
|
||||
# reflect in
|
||||
for i in range(8):
|
||||
topbit = reg & 0x8000
|
||||
if octet & (0x80 >> i):
|
||||
topbit ^= 0x8000
|
||||
reg <<= 1
|
||||
if topbit:
|
||||
reg ^= poly
|
||||
reg &= 0xFFFF
|
||||
# reflect out
|
||||
return reg ^ xor_out
|
||||
|
||||
def getAudioDevices():
|
||||
p = pyaudio.PyAudio()
|
||||
info = p.get_host_api_info_by_index(0)
|
||||
numdevices = info.get('deviceCount')
|
||||
for i in range(0, numdevices):
|
||||
if (p.get_device_info_by_host_api_device_index(0,i).get('maxInputChannels')) > 0:
|
||||
print("Input Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
||||
if (p.get_device_info_by_host_api_device_index(0,i).get('maxOutputChannels')) > 0:
|
||||
print("Output Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0, i).get('name'))
|
||||
|
||||
|
||||
class TX():
|
||||
|
||||
|
||||
def Broadcast(self, bcdata):
|
||||
|
||||
modem = freedv.FreeDV()
|
||||
audio = sound.Audio()
|
||||
|
||||
|
||||
#preamble = b'\x00' * modem.bytes_per_frame * 2 #SET PREAMPLE
|
||||
preamble = b'\x00\x00\x00'
|
||||
header = b'' # SET HEADER
|
||||
#postamble = b'\xFF' * modem.bytes_per_frame# * 2 # SET POSTAMPLE
|
||||
frame = preamble + header + bcdata# + postamble # COMBINE PREAMPLE, HEADER, DATA AND POSTAMPLE
|
||||
|
||||
logging.info(hex(Helpers.crc16(bcdata)))
|
||||
logging.info(len(hex(Helpers.crc16(bcdata))))
|
||||
#testcrc = modem.c_lib.freedv_gen_crc16(frame,modem.payload_per_frame)
|
||||
|
||||
|
||||
logging.info("BYTES PER FRAME: " + str(modem.bytes_per_frame))
|
||||
logging.info("PAYLOAD PER FRAME: " + str(modem.payload_per_frame))
|
||||
logging.info("FRAME LENGTH: " + str(len(frame)))
|
||||
#logging.info(str(len(frame)/modem.bytes_per_frame))
|
||||
#logging.info(str(len(frame) % modem.bytes_per_frame))
|
||||
|
||||
|
||||
# Check if data is divisable by bytes per frame. If yes (0) skip, If no (>0) fill up with frames
|
||||
checkframe = len(frame) % modem.bytes_per_frame
|
||||
|
||||
# filecrc = binascii.crc16(frame).to_bytes(2, byteorder='big', signed=False)
|
||||
|
||||
|
||||
|
||||
|
||||
#if checkframe != 0:
|
||||
# filler = bytes(modem.bytes_per_frame - (len(frame) % modem.bytes_per_frame))
|
||||
# logging.info("FILLER: " + str(len(filler)))
|
||||
#
|
||||
# frame = frame + filler
|
||||
# if len(filler) == 6:
|
||||
# filler * 2
|
||||
#frame = frame + filler
|
||||
#checkframe = len(frame) % modem.bytes_per_frame * 2
|
||||
#logging.info("CHECKFRAME: " + str(checkframe))
|
||||
#logging.info("FRAME LENGTH: " + str(len(frame)))
|
||||
|
||||
# Pull frame into a datalist to work as a simple buffer
|
||||
data_list = [frame[i:i+modem.bytes_per_frame*2] for i in range(0, len(frame), modem.bytes_per_frame*2)] # PACK DATAFRAME TO A LIST WHICH IS AS BIG AS THE FRAME SIZE OF FREEDV MODE
|
||||
|
||||
#data_list.append(b'0x00')
|
||||
|
||||
|
||||
length = len(data_list) # GET LENGTH OF DATA LIST
|
||||
|
||||
# Loop through data list for every item and modulate it
|
||||
for i in range(length): # LOOP THROUGH DATA LIST
|
||||
#crc = Helpers.crc16(data_list[i])
|
||||
#logging.info(hex(crc))
|
||||
logging.info(data_list[i])
|
||||
modulated_data = modem.Modulate(data_list[i])
|
||||
#logging.info(bytes(modulated_data))
|
||||
audio.Play(modulated_data)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class RX():
|
||||
|
||||
def ReceiveAudio():
|
||||
|
||||
audio = sound.Audio.Record()
|
||||
frame = freedv.FreeDV.Demodulate(audio)
|
||||
logging.info(frame)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
69
freedv.py
Normal file
69
freedv.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 11 16:58:35 2020
|
||||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
import pathlib
|
||||
|
||||
import logging
|
||||
import sound
|
||||
|
||||
|
||||
|
||||
class FreeDV():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
libname = pathlib.Path().absolute() / "libcodec2.so"
|
||||
self.c_lib = ctypes.CDLL(libname)
|
||||
|
||||
self.audio = sound.Audio()
|
||||
|
||||
|
||||
self.freedv = self.c_lib.freedv_open(3)
|
||||
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
|
||||
|
||||
|
||||
logging.info("FreeDV Initialized")
|
||||
|
||||
|
||||
# MODULATION-OUT OBJECT
|
||||
def ModulationOut(self):
|
||||
return (c_short * self.c_lib.freedv_get_n_nom_modem_samples(self.freedv))
|
||||
|
||||
# MODULATION-IN OBJECT
|
||||
def ModulationIn(self):
|
||||
return (c_short * self.c_lib.freedv_get_n_nom_modem_samples(self.freedv))
|
||||
|
||||
# DataFrame
|
||||
def DataFrame(self):
|
||||
return (ctypes.c_short * self.bytes_per_frame)
|
||||
|
||||
# GET DATA AND MODULATE IT
|
||||
def Modulate(self,data_out):
|
||||
|
||||
mod_out = self.ModulationOut()() # new modulation object and get pointer to it
|
||||
|
||||
data = (ctypes.c_short * self.bytes_per_frame).from_buffer_copy(data_out)
|
||||
#self.freedv_rawdatapreambletx(self.freedv, mod_out) # SEND PREAMBLE
|
||||
self.c_lib.freedv_rawdatatx(self.freedv,mod_out,data) # SEND DATA
|
||||
#logging.info(bytes(mod_out))
|
||||
return mod_out
|
||||
|
||||
|
||||
# DEMODULATE DATA AND RETURN IT
|
||||
def Demodulate(self,modulation_in):
|
||||
|
||||
mod_in = self.ModulationIn()() # new modulation object and get pointer to it
|
||||
data_in = self.DataFrame()()
|
||||
self.c_lib.freedv_rawdatarx(self.freedv, data_in, mod_in)
|
||||
|
||||
return data_in
|
||||
|
81
sound.py
Normal file
81
sound.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 11 17:47:32 2020
|
||||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
|
||||
import pyaudio
|
||||
import audioop
|
||||
import logging
|
||||
|
||||
|
||||
class Audio():
|
||||
|
||||
def __init__(self,
|
||||
defaultFrames = 1024 * 8,
|
||||
audio_input_device=2,
|
||||
audio_output_device=0,
|
||||
tx_sample_state = None,
|
||||
rx_sample_state = None,
|
||||
audio_sample_rate=48000,
|
||||
modem_sample_rate=8000,
|
||||
frames_per_buffer=1024,
|
||||
audio_channels=1,
|
||||
#format = pyaudio.paInt16,
|
||||
stream = None,
|
||||
):
|
||||
|
||||
self.p = pyaudio.PyAudio()
|
||||
self.defaultFrames = defaultFrames
|
||||
self.audio_input_device = audio_input_device
|
||||
self.audio_output_device = audio_output_device
|
||||
self.tx_sample_state = tx_sample_state
|
||||
self.rx_sample_state = rx_sample_state
|
||||
self.audio_sample_rate = audio_sample_rate
|
||||
self.modem_sample_rate = modem_sample_rate
|
||||
self.frames_per_buffer = frames_per_buffer
|
||||
self.audio_channels = audio_channels
|
||||
self.format = pyaudio.paInt16
|
||||
self.stream = None
|
||||
|
||||
logging.info("AUDIO Initialized")
|
||||
|
||||
|
||||
# PLAY MODULATED AUDIO
|
||||
def Play(self, modulation):
|
||||
|
||||
stream_tx = self.p.open(format=self.format,
|
||||
channels=self.audio_channels,
|
||||
rate=self.audio_sample_rate,
|
||||
frames_per_buffer=self.frames_per_buffer,
|
||||
output=True,
|
||||
output_device_index=self.audio_output_device,
|
||||
)
|
||||
|
||||
audio = audioop.ratecv(modulation,2,1,self.modem_sample_rate, self.audio_sample_rate, self.tx_sample_state)
|
||||
stream_tx.write(audio[0])
|
||||
stream_tx.close()
|
||||
#self.p.terminate()
|
||||
|
||||
|
||||
# RECORD AUDIO
|
||||
def Record(self):
|
||||
|
||||
stream_rx = self.p.open(format=self.format,
|
||||
channels=self.audio_channels,
|
||||
rate=self.audio_sample_rate,
|
||||
frames_per_buffer=self.frames_per_buffer, #modem.get_n_max_modem_samples()
|
||||
input=True,
|
||||
input_device_index=self.audio_input_device,
|
||||
)
|
||||
|
||||
#audio = audioop.ratecv(modulation,2,1,modem_sample_rate, audio_sample_rate, tx_sample_state)
|
||||
#stream.read(audio[0])
|
||||
data = stream_rx.read(self.defaultFrames)
|
||||
data = audioop.ratecv(data,2,1,self.audio_sample_rate, self.modem_sample_rate, self.rx_sample_state)
|
||||
#stream_rx.close()
|
||||
#self.p.terminate()
|
||||
return data
|
34
tnc.py
Normal file
34
tnc.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Fri Dec 11 20:06:55 2020
|
||||
|
||||
@author: DJ2LS
|
||||
"""
|
||||
|
||||
import logging
|
||||
import socketserver
|
||||
import freedv
|
||||
import commands
|
||||
|
||||
class MyTCPHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
|
||||
|
||||
def handle(self):
|
||||
# self.request is the TCP socket connected to the client
|
||||
self.data = self.request.recv(1024).strip()
|
||||
print("{} wrote:".format(self.client_address[0]))
|
||||
print(self.data)
|
||||
# just send back the same data, but upper-cased
|
||||
self.request.sendall(self.data.upper())
|
||||
|
||||
if self.data == b'TEST':
|
||||
logging.info("DER TEST KLAPPT! HIER KOMMT DER COMMAND PARSER HIN!")
|
||||
|
||||
# BROADCAST PARSER ###########################################################
|
||||
#if self.data == b'BC':
|
||||
if self.data.startswith(b'BC:'):
|
||||
data = self.data.split(b'BC:')
|
||||
commands.TX.Broadcast(bytes(data[1]),bytes(data[1]))
|
||||
#commands.TX.Broadcast(data,data)
|
Loading…
Reference in a new issue