mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge pull request #28 from DJ2LS/TNC-signalling
switching to signalling mode as default
This commit is contained in:
commit
302cff8b23
13 changed files with 872 additions and 311 deletions
95
README.md
95
README.md
|
@ -2,22 +2,18 @@
|
|||
## FreeDV- Just Another TNC Experiment
|
||||
My first attempt to learn more about FreeDV and how to create a TNC which gets data from a TCP/IP socket
|
||||
|
||||
## ToDo
|
||||
|
||||
- [x] ARQ: Stop-And-Wait
|
||||
- [x] ARQ: Go-Back-N
|
||||
- [x] ARQ: Selective repeating of lost arq frames
|
||||
- [x] ARQ: Dynamic number of frames per burst
|
||||
- [ ] ARQ: Set frames per burst automatically by channel quality
|
||||
- [x] SOCKET: Run commands via TCP/IP socket
|
||||
- [ ] TRX: Control radio via hamlib
|
||||
- [ ] MODE: Beacon
|
||||
- [ ] MODE: Broadcast
|
||||
- [ ] MODE: ARQ AX25
|
||||
- [ ] MODE: Gear shifting ARQ
|
||||
- [ ] TNC: CLI GUI for basic settings
|
||||
- [ ] TNC: Multicore support
|
||||
- [ ] MODEM: Sample rate conversion
|
||||
## Credits
|
||||
|
||||
David Rowe and the FreeDV team for developing the modem and libraries
|
||||
FreeDV Codec 2 : https://github.com/drowe67/codec2
|
||||
|
||||
|
||||
This software has been heavily inspired by https://github.com/xssfox/freedv-tnc/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Setup
|
||||
Install FreeDV-Socket-TNC directly to home folder and compile codec2 automatically
|
||||
|
@ -30,73 +26,26 @@ chmod +x ~/install_socket_tnc.sh
|
|||
|
||||
## Usage main program
|
||||
```
|
||||
./main.py --port 3000 --tx 1 --rx 1 --mode 12
|
||||
./main.py --port 3000 --tx 1 --rx 1
|
||||
```
|
||||
|
||||
## Usage TCP/IP socket client
|
||||
## Usage testclient
|
||||
```
|
||||
python3 readfromsocket.py --port 3000 --data "GET:RX_BUFFER:0
|
||||
./socketclient.py --port 3000 --data "BC: hello"
|
||||
```
|
||||
|
||||
|
||||
## Socket Commands
|
||||
|
||||
#### SOCKETTEST
|
||||
Message for testing purposes which repeats:
|
||||
Send a simple broadcast
|
||||
```
|
||||
SOCKETTEST
|
||||
BC:<DATA>
|
||||
```
|
||||
"WELL DONE! YOU ARE ABLE TO COMMUNICATE WITH THE TNC"
|
||||
|
||||
|
||||
#### TRANSMIT ARQ MESSAGE 'HELLO!'
|
||||
Send an ARQ like frame which will ask the receiver for acknowledgement
|
||||
```
|
||||
ARQ:HELLO!
|
||||
ACK:<DATA>
|
||||
```
|
||||
|
||||
#### SET NEW CALLSIGN
|
||||
```
|
||||
SET:MYCALLSIGN:AA1AA
|
||||
```
|
||||
|
||||
#### GET CALLSIGN
|
||||
```
|
||||
GET:MYCALLSIGN
|
||||
```
|
||||
|
||||
#### GET CALLSIGN CRC8
|
||||
```
|
||||
GET:MYCALLSIGN_CRC8
|
||||
```
|
||||
|
||||
#### GET DX CALLSIGN
|
||||
```
|
||||
GET:DXCALLSIGN
|
||||
```
|
||||
|
||||
#### GET ARQ STATE
|
||||
```
|
||||
GET:ARQ_STATE
|
||||
```
|
||||
|
||||
#### GET RX BUFFER LENGTH / SIZE
|
||||
```
|
||||
GET:RX_BUFFER_LENGTH
|
||||
```
|
||||
|
||||
#### GET RX BUFFER
|
||||
```
|
||||
GET:RX_BUFFER:POSITION
|
||||
```
|
||||
Position = 0 --> Latest Data
|
||||
Position 1-N --> Buffer positions
|
||||
|
||||
#### DELETE RX BUFFER
|
||||
```
|
||||
DEL:RX_BUFFER
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Other stuff
|
||||
|
||||
|
@ -114,9 +63,3 @@ sudo modprobe snd-aloop index=1,2 enable=1,1 pcm_substreams=1,1 id=CHAT1,CHAT2
|
|||
./main.py --port 3001 --tx 2 --rx 2
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
David Rowe and the FreeDV team for developing the modem and libraries
|
||||
FreeDV Codec 2 : https://github.com/drowe67/codec2
|
||||
|
||||
This software has been inspired by https://github.com/xssfox/freedv-tnc/
|
|
@ -10,6 +10,8 @@ import logging
|
|||
import threading
|
||||
import time
|
||||
from random import randrange
|
||||
import asyncio
|
||||
import trio
|
||||
|
||||
import static
|
||||
import modem
|
||||
|
@ -18,15 +20,20 @@ import helpers
|
|||
|
||||
|
||||
|
||||
def data_received(data_in):
|
||||
|
||||
static.TNC_STATE = b'BUSY'
|
||||
#############################################################################################################
|
||||
# ARQ DATA HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
|
||||
def arq_data_received(data_in):
|
||||
|
||||
static.TNC_STATE = 'BUSY'
|
||||
|
||||
static.ARQ_N_FRAME = int.from_bytes(bytes(data_in[:1]), "big") - 10 #get number of burst frame
|
||||
static.ARQ_N_RX_FRAMES_PER_BURSTS = int.from_bytes(bytes(data_in[1:2]), "big") #get number of bursts from received frame
|
||||
static.ARQ_RX_N_CURRENT_ARQ_FRAME = int.from_bytes(bytes(data_in[2:4]), "big") #get current number of total frames
|
||||
static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = int.from_bytes(bytes(data_in[4:6]), "big") # get get total number of frames
|
||||
|
||||
static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = int.from_bytes(bytes(data_in[4:6]), "big") # get get total number of frames
|
||||
|
||||
logging.debug("----------------------------------------------------------------")
|
||||
logging.debug("ARQ_N_FRAME: " + str(static.ARQ_N_FRAME))
|
||||
|
@ -35,14 +42,11 @@ def data_received(data_in):
|
|||
logging.debug("ARQ_N_ARQ_FRAMES_PER_DATA_FRAME: " + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME))
|
||||
logging.debug("----------------------------------------------------------------")
|
||||
|
||||
|
||||
arq_percent_burst = int((static.ARQ_N_FRAME / static.ARQ_N_RX_FRAMES_PER_BURSTS)*100)
|
||||
arq_percent_frame = int(((static.ARQ_RX_N_CURRENT_ARQ_FRAME)/static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME)*100)
|
||||
|
||||
logging.log(24, "ARQ | RX | ARQ FRAME [" + str(static.ARQ_N_FRAME) + "/" + str(static.ARQ_N_RX_FRAMES_PER_BURSTS) + "] [" + str(arq_percent_burst).zfill(3) + "%] --- TOTAL [" + str(static.ARQ_RX_N_CURRENT_ARQ_FRAME) + "/" + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) + "] [" + str(arq_percent_frame).zfill(3) + "%]" )
|
||||
|
||||
|
||||
|
||||
logging.log(24, "ARQ | RX | " + str(static.ARQ_DATA_CHANNEL_MODE) + " | F:[" + str(static.ARQ_N_FRAME) + "/" + str(static.ARQ_N_RX_FRAMES_PER_BURSTS) + "] [" + str(arq_percent_burst).zfill(3) + "%] T:[" + str(static.ARQ_RX_N_CURRENT_ARQ_FRAME) + "/" + str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) + "] [" + str(arq_percent_frame).zfill(3) + "%] [BER."+str(static.BER)+"]" )
|
||||
|
||||
#allocate ARQ_RX_FRAME_BUFFER as a list with "None" if not already done. This should be done only once per burst!
|
||||
# here we will save the N frame of a data frame to N list position so we can explicit search for it
|
||||
# delete frame buffer if first frame to make sure the buffer is cleared and no junks of a old frame is remaining
|
||||
|
@ -73,19 +77,23 @@ def data_received(data_in):
|
|||
static.ARQ_RX_BURST_BUFFER.insert(i,None)
|
||||
|
||||
static.ARQ_RX_BURST_BUFFER[static.ARQ_N_FRAME] = bytes(data_in)
|
||||
|
||||
|
||||
|
||||
# - ------------------------- ARQ BURST CHECKER
|
||||
# run only if we recieved all ARQ FRAMES per ARQ BURST
|
||||
if static.ARQ_RX_BURST_BUFFER.count(None) == 1: #count nones
|
||||
logging.info("ARQ | TX | BURST ACK")
|
||||
|
||||
#BUILDING ACK FRAME FOR BURST -----------------------------------------------
|
||||
ack_payload = b'BURST_ACK'
|
||||
ack_payload = b'ACK'
|
||||
ack_frame = b'<' + ack_payload # < = 60
|
||||
|
||||
#TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
|
||||
modem.transmit_arq_ack(ack_frame)
|
||||
modem.transmit_signalling(ack_frame)
|
||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
||||
#TRANSMIT_ARQ_ACK_THREAD = threading.Thread(target=modem.transmit_arq_ack, args=[ack_frame], name="TRANSMIT_ARQ_BURST")
|
||||
#TRANSMIT_ARQ_ACK_THREAD.start()
|
||||
#while static.ARQ_STATE == 'SENDING_ACK':
|
||||
# pass
|
||||
|
||||
#clear burst buffer
|
||||
static.ARQ_RX_BURST_BUFFER = []
|
||||
|
@ -107,23 +115,22 @@ def data_received(data_in):
|
|||
frame_number = frame_number.to_bytes(2, byteorder='big')
|
||||
missing_frames += frame_number
|
||||
|
||||
logging.warning("ARQ | TX | RPT ARQ FRAMES [" + str(missing_frames) + "]")
|
||||
logging.warning("ARQ | TX | RPT ARQ FRAMES [" + str(missing_frames) + "] [BER."+str(static.BER)+"]")
|
||||
|
||||
#BUILDING RPT FRAME FOR BURST -----------------------------------------------
|
||||
rpt_payload = missing_frames
|
||||
rpt_frame = b'>' + rpt_payload #> = 63
|
||||
rpt_frame = b'>' + rpt_payload #> = 63 --> 62?!?!?!?!
|
||||
|
||||
#TRANSMIT RPT FRAME FOR BURST-----------------------------------------------
|
||||
modem.transmit_arq_ack(rpt_frame)
|
||||
|
||||
|
||||
modem.transmit_signalling(rpt_frame)
|
||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
||||
|
||||
# ---------------------------- FRAME MACHINE
|
||||
# --------------- IF LIST NOT CONTAINS "None" stick everything together
|
||||
complete_data_frame = bytearray()
|
||||
#print("static.ARQ_RX_FRAME_BUFFER.count(None)" + str(static.ARQ_RX_FRAME_BUFFER.count(None)))
|
||||
if static.ARQ_RX_FRAME_BUFFER.count(None) == 1: ## 1 because position 0 of list will alaways be None in our case
|
||||
#print("DECODING FRAME!")
|
||||
logging.debug("DECODING FRAME!")
|
||||
for frame in range(1,len(static.ARQ_RX_FRAME_BUFFER)):
|
||||
raw_arq_frame = static.ARQ_RX_FRAME_BUFFER[frame]
|
||||
arq_frame_payload = raw_arq_frame[8:]
|
||||
|
@ -135,18 +142,23 @@ def data_received(data_in):
|
|||
|
||||
arq_frame_payload = arq_frame_payload.split(static.FRAME_BOF)
|
||||
arq_frame_payload = arq_frame_payload[1]
|
||||
|
||||
logging.debug("BOF")
|
||||
|
||||
# -------- DETECT IF WE RECEIVED A FRAME FOOTER THEN SAVE DATA TO GLOBALS
|
||||
if arq_frame_payload.rstrip(b'\x00').endswith(static.FRAME_EOF):
|
||||
# we need to check for at least one xFF. Sometimes we have only one xFF, because the second one is in the next frame
|
||||
if arq_frame_payload.rstrip(b'\x00').endswith(static.FRAME_EOF) or arq_frame_payload.rstrip(b'\x00').endswith(static.FRAME_EOF[:-1]):
|
||||
static.ARQ_FRAME_EOF_RECEIVED = True
|
||||
|
||||
arq_frame_payload = arq_frame_payload.split(static.FRAME_EOF)
|
||||
arq_frame_payload = arq_frame_payload[0]
|
||||
|
||||
|
||||
if arq_frame_payload.rstrip(b'\x00').endswith(static.FRAME_EOF[:-1]):
|
||||
arq_frame_payload = arq_frame_payload.split(static.FRAME_EOF[:-1])
|
||||
arq_frame_payload = arq_frame_payload[0]
|
||||
else:
|
||||
arq_frame_payload = arq_frame_payload.split(static.FRAME_EOF)
|
||||
arq_frame_payload = arq_frame_payload[0]
|
||||
logging.debug("EOF")
|
||||
|
||||
# --------- AFTER WE SEPARATED BOF AND EOF, STICK EVERYTHING TOGETHER
|
||||
complete_data_frame = complete_data_frame + arq_frame_payload
|
||||
|
||||
logging.debug(complete_data_frame)
|
||||
|
||||
#check if Begin of Frame BOF and End of Frame EOF are received, then start calculating CRC and sticking everything together
|
||||
if static.ARQ_FRAME_BOF_RECEIVED == True and static.ARQ_FRAME_EOF_RECEIVED == True:
|
||||
|
@ -155,8 +167,7 @@ def data_received(data_in):
|
|||
|
||||
#IF THE FRAME PAYLOAD CRC IS EQUAL TO THE FRAME CRC WHICH IS KNOWN FROM THE HEADER --> SUCCESS
|
||||
if frame_payload_crc == static.FRAME_CRC:
|
||||
#logging.info("ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED! - TIME TO PARTY")
|
||||
logging.log(25,"ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED! :-)")
|
||||
logging.log(25,"ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED! :-) ")
|
||||
|
||||
#append received frame to RX_BUFFER
|
||||
static.RX_BUFFER.append(complete_data_frame)
|
||||
|
@ -167,33 +178,50 @@ def data_received(data_in):
|
|||
|
||||
#TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
|
||||
time.sleep(1) #0.5
|
||||
logging.info("ARQ | TX | ARQ DATA FRAME ACK [" + str(static.FRAME_CRC.hex()) +"]")
|
||||
logging.info("ARQ | TX | ARQ DATA FRAME ACK [" + str(static.FRAME_CRC.hex()) +"] [BER."+str(static.BER)+"]")
|
||||
|
||||
modem.transmit_arq_ack(ack_frame)
|
||||
|
||||
modem.transmit_signalling(ack_frame)
|
||||
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
# clearing buffers and resetting counters
|
||||
static.ARQ_RX_BURST_BUFFER = []
|
||||
static.ARQ_RX_FRAME_BUFFER = []
|
||||
static.ARQ_FRAME_BOF_RECEIVED = False
|
||||
static.ARQ_FRAME_EOF_RECEIVED = False
|
||||
static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME = 0
|
||||
static.TNC_STATE = b'IDLE'
|
||||
|
||||
#print("----------------------------------------------------------------")
|
||||
#print(static.RX_BUFFER[-1])
|
||||
#print("----------------------------------------------------------------")
|
||||
static.TNC_STATE = 'IDLE'
|
||||
static.ARQ_SEND_KEEP_ALIVE = True
|
||||
static.ARQ_READY_FOR_DATA = False
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]<< >>["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
|
||||
else:
|
||||
print("ARQ_FRAME_BOF_RECEIVED " + str(static.ARQ_FRAME_BOF_RECEIVED))
|
||||
print("ARQ_FRAME_EOF_RECEIVED " + str(static.ARQ_FRAME_EOF_RECEIVED))
|
||||
logging.error("ARQ | RX | DATA FRAME NOT SUCESSFULLY RECEIVED!")
|
||||
static.TNC_STATE = b'IDLE'
|
||||
|
||||
static.ARQ_STATE = 'IDLE'
|
||||
static.ARQ_SEND_KEEP_ALIVE = True
|
||||
static.ARQ_READY_FOR_DATA = False
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]<< >>["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
|
||||
|
||||
async def arq_transmit(data_out):
|
||||
# we need to set payload per frame manually at this point. maybe we can do this more dynmic.
|
||||
if static.ARQ_DATA_CHANNEL_MODE == 10:
|
||||
payload_per_frame = 512-2
|
||||
elif static.ARQ_DATA_CHANNEL_MODE == 11:
|
||||
payload_per_frame = 256-2
|
||||
elif static.ARQ_DATA_CHANNEL_MODE == 12:
|
||||
payload_per_frame = 128-2
|
||||
elif static.ARQ_DATA_CHANNEL_MODE == 14:
|
||||
payload_per_frame = 16-2
|
||||
else:
|
||||
payload_per_frame = 16-2
|
||||
|
||||
static.ARQ_PAYLOAD_PER_FRAME = payload_per_frame - 8
|
||||
|
||||
def transmit(data_out):
|
||||
#print("static.ARQ_DATA_PAYLOAD_PER_FRAME " + str(static.FREEDV_DATA_PAYLOAD_PER_FRAME))
|
||||
#print("static.ARQ_PAYLOAD_PER_FRAME " + str(static.ARQ_PAYLOAD_PER_FRAME))
|
||||
|
||||
|
||||
static.ARQ_PAYLOAD_PER_FRAME = static.FREEDV_DATA_PAYLOAD_PER_FRAME - 8
|
||||
frame_header_length = 6 #4
|
||||
|
||||
n_arq_frames_per_data_frame = (len(data_out)+frame_header_length) // static.ARQ_PAYLOAD_PER_FRAME + ((len(data_out)+frame_header_length) % static.ARQ_PAYLOAD_PER_FRAME > 0)
|
||||
|
@ -208,10 +236,9 @@ def transmit(data_out):
|
|||
static.TX_BUFFER = [data_out[i:i+static.ARQ_PAYLOAD_PER_FRAME] for i in range(0, len(data_out), static.ARQ_PAYLOAD_PER_FRAME)]
|
||||
static.TX_BUFFER_SIZE = len(static.TX_BUFFER)
|
||||
|
||||
logging.info("ARQ | TX | DATA FRAME --- BYTES: " + str(len(data_out)) + " ARQ FRAMES: " + str(static.TX_BUFFER_SIZE))
|
||||
logging.info("ARQ | TX | M:" + str(static.ARQ_DATA_CHANNEL_MODE) + " | DATA FRAME --- BYTES: " + str(len(data_out)) + " ARQ FRAMES: " + str(static.TX_BUFFER_SIZE))
|
||||
|
||||
# --------------------------------------------- THIS IS THE MAIN LOOP-----------------------------------------------------------------
|
||||
|
||||
static.ARQ_N_SENT_FRAMES = 0 # SET N SENT FRAMES TO 0 FOR A NEW SENDING CYCLE
|
||||
while static.ARQ_N_SENT_FRAMES <= static.TX_BUFFER_SIZE:
|
||||
|
||||
|
@ -238,25 +265,37 @@ def transmit(data_out):
|
|||
for static.TX_N_RETRIES in range(static.TX_N_MAX_RETRIES):
|
||||
|
||||
if static.ARQ_N_SENT_FRAMES + 1 <= static.TX_BUFFER_SIZE:
|
||||
logging.log(24, "ARQ | TX | F:[" + str(static.ARQ_N_SENT_FRAMES+1) + "-" + str(static.ARQ_N_SENT_FRAMES + static.ARQ_TX_N_FRAMES_PER_BURST) + "] | T:[" + str(static.ARQ_N_SENT_FRAMES) + "/" + str(static.TX_BUFFER_SIZE) + "] [" + str(int(static.ARQ_N_SENT_FRAMES/(static.TX_BUFFER_SIZE)*100)).zfill(3) + "%] | A:[" + str(static.TX_N_RETRIES+1) + "/" + str(static.TX_N_MAX_RETRIES) + "]")
|
||||
logging.log(24, "ARQ | TX | M:" + str(static.ARQ_DATA_CHANNEL_MODE) + " | F:[" + str(static.ARQ_N_SENT_FRAMES+1) + "-" + str(static.ARQ_N_SENT_FRAMES + static.ARQ_TX_N_FRAMES_PER_BURST) + "] | T:[" + str(static.ARQ_N_SENT_FRAMES) + "/" + str(static.TX_BUFFER_SIZE) + "] [" + str(int(static.ARQ_N_SENT_FRAMES/(static.TX_BUFFER_SIZE)*100)).zfill(3) + "%] | A:[" + str(static.TX_N_RETRIES+1) + "/" + str(static.TX_N_MAX_RETRIES) + "] [BER."+str(static.BER)+"]")
|
||||
|
||||
|
||||
# lets start a thread to transmit nonblocking
|
||||
TRANSMIT_ARQ_BURST_THREAD = threading.Thread(target=modem.transmit_arq_burst, name="TRANSMIT_ARQ_BURST")
|
||||
TRANSMIT_ARQ_BURST_THREAD.start()
|
||||
|
||||
#TRANSMIT_ARQ_BURST_THREAD = threading.Thread(target=modem.transmit_arq_burst, name="TRANSMIT_ARQ_BURST")
|
||||
#TRANSMIT_ARQ_BURST_THREAD.start()
|
||||
#asyncio.run(modem.transmit_arq_burst())
|
||||
await modem.transmit_arq_burst()
|
||||
# lets wait during sending. After sending is finished we will continue
|
||||
while static.ARQ_STATE == 'SENDING_DATA':
|
||||
while static.CHANNEL_STATE == 'SENDING_DATA':
|
||||
time.sleep(0.01)
|
||||
|
||||
# --------------------------- START TIMER FOR WAITING FOR ACK ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1
|
||||
|
||||
logging.debug("ARQ | RX | WAITING FOR BURST ACK")
|
||||
static.ARQ_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
|
||||
helpers.arq_reset_timeout(False)
|
||||
helpers.arq_reset_ack(False)
|
||||
|
||||
#print(static.ARQ_RX_ACK_TIMEOUT)
|
||||
#print("timeout......?!?")
|
||||
#asyncio.ensure_future(helpers.set_variable_after_timeout())
|
||||
##################task = asyncio.create_task(helpers.set_after_timeout())
|
||||
#async with trio.open_nursery() as nursery:
|
||||
# nursery.start_soon(helpers.set_after_timeout())
|
||||
|
||||
|
||||
#print("TIMEOUT glaube gestartet...")
|
||||
#print(task)
|
||||
#print(static.ARQ_RX_ACK_TIMEOUT)
|
||||
|
||||
acktimer = threading.Timer(static.ARQ_RX_ACK_TIMEOUT_SECONDS, helpers.arq_ack_timeout)
|
||||
acktimer.start()
|
||||
|
||||
|
@ -278,15 +317,14 @@ def transmit(data_out):
|
|||
logging.warning("ARQ | RX | REQUEST FOR REPEATING FRAMES: " + str(static.ARQ_RPT_FRAMES))
|
||||
logging.warning("ARQ | TX | SENDING REQUESTED FRAMES: " + str(static.ARQ_RPT_FRAMES))
|
||||
|
||||
TRANSMIT_ARQ_BURST_THREAD = threading.Thread(target=modem.transmit_arq_burst, name="TRANSMIT_ARQ_BURST")
|
||||
TRANSMIT_ARQ_BURST_THREAD.start()
|
||||
|
||||
#TRANSMIT_ARQ_BURST_THREAD = threading.Thread(target=modem.transmit_arq_burst, name="TRANSMIT_ARQ_BURST")
|
||||
#TRANSMIT_ARQ_BURST_THREAD.start()
|
||||
#asyncio.run(modem.transmit_arq_burst())
|
||||
await modem.transmit_arq_burst()
|
||||
# lets wait during sending. After sending is finished we will continue
|
||||
while static.ARQ_STATE == 'SENDING_DATA':
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
static.ARQ_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
|
||||
helpers.arq_reset_timeout(False)
|
||||
helpers.arq_reset_ack(False)
|
||||
|
@ -356,7 +394,7 @@ def transmit(data_out):
|
|||
|
||||
frametimer = threading.Timer(static.ARQ_RX_FRAME_TIMEOUT_SECONDS, helpers.arq_frame_timeout)
|
||||
frametimer.start()
|
||||
static.ARQ_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
|
||||
# wait for frame ACK if we processed the last frame/burst
|
||||
while static.ARQ_FRAME_ACK_RECEIVED == False and static.ARQ_RX_FRAME_TIMEOUT == False and static.ARQ_N_SENT_FRAMES == static.TX_BUFFER_SIZE:
|
||||
|
@ -367,16 +405,21 @@ def transmit(data_out):
|
|||
|
||||
# ----------- if no ACK received and out of retries.....stop frame sending
|
||||
if static.ARQ_ACK_RECEIVED == False and static.ARQ_FRAME_ACK_RECEIVED == False and static.ARQ_RX_ACK_TIMEOUT == True:
|
||||
logging.error("ARQ | TX | NO BURST OR FRAME ACK RECEIVED | DATA SHOULD BE RESEND!")
|
||||
logging.error("ARQ | TX | NO ACK RECEIVED | DATA SHOULD BE RESEND!")
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
logging.error("------------------------------------------------------")
|
||||
break
|
||||
|
||||
#-------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT AND WE GOT A FRAME ACK
|
||||
elif static.ARQ_N_SENT_FRAMES == static.TX_BUFFER_SIZE and static.ARQ_FRAME_ACK_RECEIVED == True:
|
||||
logging.log(25,"ARQ | RX | FRAME ACK RECEIVED - DATA TRANSMITTED! :-)")
|
||||
logging.log(25,"------------------------------------------------------")
|
||||
|
||||
break
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
break
|
||||
|
||||
elif static.ARQ_FRAME_ACK_RECEIVED == False and static.ARQ_RX_FRAME_TIMEOUT == True:
|
||||
logging.error("ARQ | TX | NO FRAME ACK RECEIVED")
|
||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
||||
break
|
||||
|
||||
else:
|
||||
logging.debug("NO MATCHING RULE AT THE END")
|
||||
|
@ -396,13 +439,16 @@ def transmit(data_out):
|
|||
|
||||
logging.info("ARQ | TX | BUFFER EMPTY")
|
||||
helpers.arq_reset_frame_machine()
|
||||
await asyncio.sleep(2)
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]<< >>["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
arq_transmit_keep_alive()
|
||||
|
||||
|
||||
|
||||
# BURST MACHINE TO DEFINE N BURSTS PER FRAME ---> LATER WE CAN USE CHANNEL MESSUREMENT TO SET FRAMES PER BURST
|
||||
def get_n_frames_per_burst():
|
||||
#n_frames_per_burst = randrange(1,10)
|
||||
n_frames_per_burst = 5
|
||||
n_frames_per_burst = 1
|
||||
return n_frames_per_burst
|
||||
|
||||
|
||||
|
@ -427,4 +473,222 @@ def burst_rpt_received(data_in):
|
|||
if not missing_area[i:i+2].endswith(b'\x00\x00'):
|
||||
missing = missing_area[i:i+2]
|
||||
static.ARQ_RPT_FRAMES.insert(0,missing)
|
||||
|
||||
#############################################################################################################
|
||||
# ARQ CONNECT HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
async def arq_connect():
|
||||
static.ARQ_STATE = 'CONNECTING'
|
||||
logging.info("CONN ["+ str(static.MYCALLSIGN, 'utf-8') + "]-> <-["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
frame_type = bytes([220])
|
||||
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = frame_type
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
connection_frame[3:9] = static.MYCALLSIGN # we need the full CALLSIGN, if we are doing a connect without ping and cq
|
||||
#connection_frame[12:13] = bytes([static.ARQ_DATA_CHANNEL_MODE])
|
||||
#connection_frame[13:14] = bytes([static.ARQ_READY_FOR_DATA])
|
||||
#print(connection_frame)
|
||||
|
||||
modem.transmit_signalling(connection_frame)
|
||||
|
||||
def arq_received_connect(data_in):
|
||||
static.ARQ_STATE = 'CONNECTING'
|
||||
|
||||
static.DXCALLSIGN = bytes(data_in[3:9]).rstrip(b'\x00')
|
||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
|
||||
#static.FREEDV_DATA_MODE = int.from_bytes(bytes(data_in[12:13]), "big")
|
||||
|
||||
logging.info("CONN ["+ str(static.MYCALLSIGN, 'utf-8') + "]-> <-["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
|
||||
frame_type = bytes([221])
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = frame_type
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
#connection_frame[12:13] = bytes([static.FREEDV_DATA_MODE])
|
||||
|
||||
#send ACK for connect
|
||||
modem.transmit_signalling(connection_frame)
|
||||
|
||||
def arq_transmit_keep_alive():
|
||||
frame_type = bytes([221])
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = frame_type
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
modem.transmit_signalling(connection_frame)
|
||||
|
||||
|
||||
def arq_received_connect_keep_alive(data_in):
|
||||
if static.ARQ_SEND_KEEP_ALIVE == True and (static.ARQ_STATE == 'CONNECTING' or static.ARQ_STATE == 'CONNECTED'):
|
||||
logging.info("CONN ["+ str(static.MYCALLSIGN, 'utf-8') + "] >|< ["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.ARQ_STATE = 'CONNECTED'
|
||||
|
||||
frame_type = bytes([221])
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = frame_type
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
connection_frame[12:13] = bytes([static.ARQ_DATA_CHANNEL_MODE])
|
||||
connection_frame[13:14] = bytes([0])
|
||||
|
||||
#lets wait a second before sending
|
||||
acktimer = threading.Timer(1.0, modem.transmit_signalling, args=[connection_frame])
|
||||
acktimer.start()
|
||||
else:
|
||||
pass
|
||||
#print("keep alive = False")
|
||||
#############################################################################################################
|
||||
# ARQ DATA CHANNEL HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
|
||||
async def arq_open_data_channel():
|
||||
# we need to wait until the last keep alive has been sent.
|
||||
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]>> <<["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.ARQ_SEND_KEEP_ALIVE = False
|
||||
static.ARQ_DATA_CHANNEL_MODE = 12
|
||||
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
#print("wir warten 2 sekunden...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = bytes([225])
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
connection_frame[12:13] = bytes([static.ARQ_DATA_CHANNEL_MODE])
|
||||
#connection_frame[13:14] = bytes([225])
|
||||
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
modem.transmit_signalling(connection_frame)
|
||||
|
||||
|
||||
|
||||
def arq_received_data_channel_opener(data_in):
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]>> <<["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.ARQ_SEND_KEEP_ALIVE = False
|
||||
static.ARQ_DATA_CHANNEL_MODE = int.from_bytes(bytes(data_in[12:13]), "big")
|
||||
#static.ARQ_READY_FOR_DATA = int.from_bytes(bytes(data_in[13:14]), "big")
|
||||
|
||||
connection_frame = bytearray(14)
|
||||
connection_frame[:1] = bytes([226])
|
||||
connection_frame[1:2] = static.DXCALLSIGN_CRC8
|
||||
connection_frame[2:3] = static.MYCALLSIGN_CRC8
|
||||
connection_frame[12:13] = bytes([static.ARQ_DATA_CHANNEL_MODE])
|
||||
#connection_frame[13:14] = bytes([226])
|
||||
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
modem.transmit_signalling(connection_frame)
|
||||
#print("waiting for data....")
|
||||
static.CHANNEL_STATE = 'RECEIVING_DATA'
|
||||
# einen timeout benötigen wir auch noch....
|
||||
# und ab hier geht es dann in den "RECEIVING_DATA" mode....
|
||||
|
||||
def arq_received_channel_is_open(data_in):
|
||||
static.ARQ_SEND_KEEP_ALIVE == False
|
||||
|
||||
if static.ARQ_DATA_CHANNEL_MODE == int.from_bytes(bytes(data_in[12:13]), "big"):
|
||||
logging.info("DATA ["+ str(static.MYCALLSIGN, 'utf-8') + "]>>|<<["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
time.sleep(1)
|
||||
static.ARQ_READY_FOR_DATA = True
|
||||
#static.CHANNEL_STATE = 'RECEIVING_DATA':
|
||||
|
||||
|
||||
#############################################################################################################
|
||||
# DISCONNECT HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
async def arq_disconnect():
|
||||
|
||||
# we need to create a "force ignore all" so we don't receive frames any more... Then we don't need a timer
|
||||
static.ARQ_SEND_KEEP_ALIVE == False
|
||||
static.ARQ_STATE = 'DISCONNECTING'
|
||||
logging.info("DISC ["+ str(static.MYCALLSIGN, 'utf-8') + "] <-> ["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
frame_type = bytes([222])
|
||||
disconnection_frame = frame_type + static.MYCALLSIGN
|
||||
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
|
||||
await asyncio.sleep(5)
|
||||
modem.transmit_signalling(disconnection_frame)
|
||||
|
||||
logging.info("DISC ["+ str(static.MYCALLSIGN, 'utf-8') + "]< X >["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.ARQ_STATE = 'IDLE'
|
||||
static.DXCALLSIGN = b''
|
||||
static.DXCALLSIGN_CRC8 = b''
|
||||
|
||||
def arq_disconnect_received(data_in):
|
||||
static.ARQ_STATE = 'DISCONNECTED'
|
||||
logging.info("DISC ["+ str(static.MYCALLSIGN, 'utf-8') + "]< X >["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.ARQ_STATE = 'DISCONNECTED'
|
||||
static.TNC_STATE = 'IDLE'
|
||||
static.DXCALLSIGN = b''
|
||||
static.DXCALLSIGN_CRC8 = b''
|
||||
|
||||
|
||||
|
||||
#############################################################################################################
|
||||
# PING HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
def transmit_ping(callsign):
|
||||
static.DXCALLSIGN = bytes(callsign, 'utf-8')
|
||||
logging.info("PING ["+ str(static.MYCALLSIGN, 'utf-8') + "] >>> [" + str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
frame_type = bytes([210])
|
||||
ping_payload = b'PING'
|
||||
ping_frame = frame_type + ping_payload
|
||||
|
||||
# wait while sending....
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
modem.transmit_signalling(ping_frame)
|
||||
|
||||
def received_ping(data_in):
|
||||
|
||||
logging.info("PING ["+ str(static.MYCALLSIGN, 'utf-8') + "] <<< ["+ str(static.DXCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
frame_type = bytes([211])
|
||||
ping_payload = b'PING_ACK'
|
||||
ping_frame = frame_type + static.MYCALLSIGN + ping_payload
|
||||
# wait while sending....
|
||||
while static.CHANNEL_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
modem.transmit_signalling(ping_frame)
|
||||
|
||||
def received_ping_ack(data_in):
|
||||
|
||||
dxcallsign = data_in[1:6]
|
||||
static.DXCALLSIGN = bytes(dxcallsign)
|
||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
|
||||
logging.info("PING [" + str(static.DXCALLSIGN, 'utf-8') + "] >|< [" + str(static.MYCALLSIGN, 'utf-8') + "] [BER."+str(static.BER)+"]")
|
||||
static.TNC_STATE = 'IDLE'
|
||||
|
||||
#############################################################################################################
|
||||
# BROADCAST HANDLER
|
||||
#############################################################################################################
|
||||
|
||||
async def transmit_cq():
|
||||
logging.info("CQ CQ CQ")
|
||||
frame_type = bytes([200])
|
||||
cq_frame = frame_type + static.MYCALLSIGN
|
||||
modem.transmit_signalling(cq_frame)
|
||||
|
||||
|
||||
async def transmit_beacon():
|
||||
logging.info("BEACON")
|
||||
frame_type = bytes([230])
|
||||
print(frame_type)
|
||||
beacon_frame = frame_type + static.MYCALLSIGN
|
||||
while static.TNC_STATE == 'BEACON':
|
||||
await asyncio.sleep(60)
|
||||
modem.transmit_signalling(beacon_frame)
|
||||
|
16
fec.py
Normal file
16
fec.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import static
|
||||
import modem
|
||||
#modem = modem.RF()
|
||||
import helpers
|
||||
|
||||
|
||||
|
||||
def transmit_cq():
|
||||
cq_frame = b'CQCQCQ'
|
||||
modem.RF.transmit_signalling(cq_frame)
|
||||
pass
|
||||
|
||||
|
132
hamlib.py
Normal file
132
hamlib.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
# Change this path to match your "make install" path
|
||||
sys.path.append('/usr/local/lib/python3.8/site-packages')
|
||||
|
||||
## Uncomment to run this script from an in-tree build (or adjust to the
|
||||
## build directory) without installing the bindings.
|
||||
#sys.path.append ('.')
|
||||
#sys.path.append ('.libs')
|
||||
|
||||
import Hamlib
|
||||
|
||||
def StartUp():
|
||||
"""Simple script to test the Hamlib.py module with Python3."""
|
||||
|
||||
print("%s: Python %s; %s\n" \
|
||||
% (sys.argv[0], sys.version.split()[0], Hamlib.cvar.hamlib_version))
|
||||
|
||||
Hamlib.rig_set_debug(Hamlib.RIG_DEBUG_NONE)
|
||||
|
||||
# Init RIG_MODEL_DUMMY
|
||||
my_rig = Hamlib.Rig(Hamlib.RIG_MODEL_DUMMY)
|
||||
my_rig.set_conf("rig_pathname", "/dev/Rig")
|
||||
my_rig.set_conf("retry", "5")
|
||||
|
||||
my_rig.open ()
|
||||
|
||||
|
||||
print("SET PTT------------------------------------------")
|
||||
|
||||
#Supported types are ‘RIG’ (CAT command), ‘DTR’, ‘RTS’, ‘PARALLEL’, ‘NONE’, overriding PTT type defined in the rig's backend.
|
||||
#Some side effects of this command are that when type is set to DTR, read PTT state comes from the Hamlib frontend, not read from the radio. When set to NONE, PTT state cannot be read or set even if rig backend supports reading/setting PTT status from the rig.
|
||||
|
||||
my_rig.set_ptt(Hamlib.RIG_PTT_SERIAL_DTR,1)
|
||||
print(my_rig.get_ptt())
|
||||
|
||||
rpath = my_rig.get_conf("rig_pathname")
|
||||
retry = my_rig.get_conf("retry")
|
||||
|
||||
print("status(str):\t\t%s" % Hamlib.rigerror(my_rig.error_status))
|
||||
print("get_conf:\t\tpath = %s, retry = %s" \
|
||||
% (rpath, retry))
|
||||
|
||||
my_rig.set_freq(Hamlib.RIG_VFO_B, 5700000000)
|
||||
my_rig.set_vfo(Hamlib.RIG_VFO_B)
|
||||
|
||||
print("freq:\t\t\t%s" % my_rig.get_freq())
|
||||
|
||||
my_rig.set_freq(Hamlib.RIG_VFO_A, 145550000)
|
||||
(mode, width) = my_rig.get_mode()
|
||||
|
||||
print("mode:\t\t\t%s\nbandwidth:\t\t%s" % (Hamlib.rig_strrmode(mode), width))
|
||||
|
||||
my_rig.set_mode(Hamlib.RIG_MODE_CW)
|
||||
(mode, width) = my_rig.get_mode()
|
||||
|
||||
print("mode:\t\t\t%s\nbandwidth:\t\t%s" % (Hamlib.rig_strrmode(mode), width))
|
||||
|
||||
print("Backend copyright:\t%s" % my_rig.caps.copyright)
|
||||
print("Model:\t\t\t%s" % my_rig.caps.model_name)
|
||||
print("Manufacturer:\t\t%s" % my_rig.caps.mfg_name)
|
||||
print("Backend version:\t%s" % my_rig.caps.version)
|
||||
print("Backend status:\t\t%s" % Hamlib.rig_strstatus(my_rig.caps.status))
|
||||
print("Rig info:\t\t%s" % my_rig.get_info())
|
||||
|
||||
my_rig.set_level("VOXDELAY", 1)
|
||||
|
||||
print("VOX delay:\t\t%s" % my_rig.get_level_i("VOXDELAY"))
|
||||
|
||||
my_rig.set_level(Hamlib.RIG_LEVEL_VOXDELAY, 5)
|
||||
|
||||
print("VOX delay:\t\t%s" % my_rig.get_level_i(Hamlib.RIG_LEVEL_VOXDELAY))
|
||||
|
||||
af = 12.34
|
||||
|
||||
print("Setting AF to %0.2f...." % (af))
|
||||
|
||||
my_rig.set_level("AF", af)
|
||||
|
||||
print("status:\t\t\t%s - %s" % (my_rig.error_status,
|
||||
Hamlib.rigerror(my_rig.error_status)))
|
||||
|
||||
print("AF level:\t\t%0.2f" % my_rig.get_level_f(Hamlib.RIG_LEVEL_AF))
|
||||
print("strength:\t\t%s" % my_rig.get_level_i(Hamlib.RIG_LEVEL_STRENGTH))
|
||||
print("status:\t\t\t%s" % my_rig.error_status)
|
||||
print("status(str):\t\t%s" % Hamlib.rigerror(my_rig.error_status))
|
||||
|
||||
chan = Hamlib.channel(Hamlib.RIG_VFO_B)
|
||||
my_rig.get_channel(chan,1)
|
||||
|
||||
print("get_channel status:\t%s" % my_rig.error_status)
|
||||
print("VFO:\t\t\t%s, %s" % (Hamlib.rig_strvfo(chan.vfo), chan.freq))
|
||||
print("Attenuators:\t\t%s" % my_rig.caps.attenuator)
|
||||
print("\nSending Morse, '73'")
|
||||
|
||||
my_rig.send_morse(Hamlib.RIG_VFO_A, "73")
|
||||
my_rig.close()
|
||||
|
||||
print("\nSome static functions:")
|
||||
|
||||
err, lon1, lat1 = Hamlib.locator2longlat("IN98XC")
|
||||
err, lon2, lat2 = Hamlib.locator2longlat("DM33DX")
|
||||
err, loc1 = Hamlib.longlat2locator(lon1, lat1, 3)
|
||||
err, loc2 = Hamlib.longlat2locator(lon2, lat2, 3)
|
||||
|
||||
print("Loc1:\t\tIN98XC -> %9.4f, %9.4f -> %s" % (lon1, lat1, loc1))
|
||||
print("Loc2:\t\tDM33DX -> %9.4f, %9.4f -> %s" % (lon2, lat2, loc2))
|
||||
|
||||
err, dist, az = Hamlib.qrb(lon1, lat1, lon2, lat2)
|
||||
longpath = Hamlib.distance_long_path(dist)
|
||||
|
||||
print("Distance:\t%.3f km, azimuth %.2f, long path:\t%.3f km" \
|
||||
% (dist, az, longpath))
|
||||
|
||||
# dec2dms expects values from 180 to -180
|
||||
# sw is 1 when deg is negative (west or south) as 0 cannot be signed
|
||||
err, deg1, mins1, sec1, sw1 = Hamlib.dec2dms(lon1)
|
||||
err, deg2, mins2, sec2, sw2 = Hamlib.dec2dms(lat1)
|
||||
|
||||
lon3 = Hamlib.dms2dec(deg1, mins1, sec1, sw1)
|
||||
lat3 = Hamlib.dms2dec(deg2, mins2, sec2, sw2)
|
||||
|
||||
print('Longitude:\t%4.4f, %4d° %2d\' %2d" %1s\trecoded: %9.4f' \
|
||||
% (lon1, deg1, mins1, sec1, ('W' if sw1 else 'E'), lon3))
|
||||
|
||||
print('Latitude:\t%4.4f, %4d° %2d\' %2d" %1s\trecoded: %9.4f' \
|
||||
% (lat1, deg2, mins2, sec2, ('S' if sw2 else 'N'), lat3))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
StartUp()
|
47
helpers.py
47
helpers.py
|
@ -11,6 +11,9 @@ import threading
|
|||
import logging
|
||||
import crcengine
|
||||
import pyaudio
|
||||
import asyncio
|
||||
|
||||
import data_handler
|
||||
|
||||
import static
|
||||
|
||||
|
@ -29,19 +32,36 @@ def get_crc_16(data):
|
|||
crc_data = crc_algorithm(data)
|
||||
crc_data = crc_data.to_bytes(2, byteorder='big')
|
||||
return crc_data
|
||||
|
||||
async def set_after_timeout():
|
||||
while True:
|
||||
logging.info("HALLO?!?")
|
||||
time.sleep(1)
|
||||
print("HALLOIOIOIOIOIOI")
|
||||
static.ARQ_RX_ACK_TIMEOUT = True
|
||||
await asyncio.sleep(1.1)
|
||||
#await asyncio.sleep(timeout)
|
||||
#vars()[variable] = value
|
||||
|
||||
|
||||
|
||||
def arq_disconnect_timeout():
|
||||
static.ARQ_WAIT_FOR_DISCONNECT = True
|
||||
logging.debug("ARQ_WAIT_FOR_DISCONNECT")
|
||||
|
||||
|
||||
def arq_ack_timeout():
|
||||
if static.ARQ_STATE == 'RECEIVING_SIGNALLING':
|
||||
if static.CHANNEL_STATE == 'RECEIVING_SIGNALLING':
|
||||
static.ARQ_RX_ACK_TIMEOUT = True
|
||||
logging.debug("ARQ_RX_ACK_TIMEOUT")
|
||||
|
||||
def arq_rpt_timeout():
|
||||
if static.ARQ_STATE == 'RECEIVING_SIGNALLING':
|
||||
if static.CHANNEL_STATE == 'RECEIVING_SIGNALLING':
|
||||
static.ARQ_RX_RPT_TIMEOUT = True
|
||||
logging.debug("ARQ_RX_RPT_TIMEOUT")
|
||||
|
||||
def arq_frame_timeout():
|
||||
if static.ARQ_STATE == 'RECEIVING_SIGNALLING':
|
||||
if static.CHANNEL_STATE == 'RECEIVING_SIGNALLING':
|
||||
static.ARQ_RX_FRAME_TIMEOUT = True
|
||||
logging.debug("ARQ_RX_FRAME_TIMEOUT")
|
||||
|
||||
|
@ -61,9 +81,16 @@ def arq_reset_frame_machine():
|
|||
static.TX_N_RETRIES = 0
|
||||
static.ARQ_N_SENT_FRAMES = 0
|
||||
static.ARQ_TX_N_FRAMES_PER_BURST = 0
|
||||
static.TNC_STATE = b'IDLE'
|
||||
|
||||
static.TNC_STATE = b'IDLE'
|
||||
static.ARQ_SEND_KEEP_ALIVE = True
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.ARQ_READY_FOR_DATA = False
|
||||
|
||||
#start sending keep alive after some seconds
|
||||
#acktimer = threading.Timer(3.0, data_handler.arq_connect)
|
||||
#acktimer.start()
|
||||
#await asyncio.sleep(2)
|
||||
#modem.transmit_arq_connect()
|
||||
def setup_logging():
|
||||
|
||||
logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%H:%M:%S', level=logging.INFO)
|
||||
|
@ -86,13 +113,3 @@ def setup_logging():
|
|||
#'ERROR' : 31, # red
|
||||
#'CRITICAL': 41, # white on red bg
|
||||
|
||||
|
||||
|
||||
def list_audio_devices():
|
||||
p = pyaudio.PyAudio()
|
||||
devices = []
|
||||
for x in range(0, p.get_device_count()):
|
||||
devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}")
|
||||
|
||||
for line in devices:
|
||||
print(line)
|
||||
|
|
17
main.py
17
main.py
|
@ -12,25 +12,16 @@ import argparse
|
|||
import logging
|
||||
import threading
|
||||
|
||||
|
||||
import static
|
||||
import helpers
|
||||
|
||||
def client(ip, port, message):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.connect((ip, port))
|
||||
sock.sendall(bytes(message, 'ascii'))
|
||||
response = str(sock.recv(1024), 'ascii')
|
||||
print("Received: {}".format(response))
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# config logging
|
||||
helpers.setup_logging()
|
||||
|
||||
# list audio devices
|
||||
helpers.list_audio_devices()
|
||||
|
||||
|
||||
#--------------------------------------------GET PARAMETER INPUTS
|
||||
|
@ -38,17 +29,17 @@ if __name__ == '__main__':
|
|||
parser.add_argument('--rx', dest="audio_input_device", default=0, help="sound card for listening.", type=int)
|
||||
parser.add_argument('--tx', dest="audio_output_device", default=0, help="sound card for transmitting.", type=int)
|
||||
parser.add_argument('--port', dest="socket_port", default=3000, help="Set the port, the socket is listening on.", type=int)
|
||||
parser.add_argument('--mode', dest="freedv_data_mode", default=12, help="Set the mode.", type=int)
|
||||
#parser.add_argument('--mode', dest="freedv_data_mode", default=12, help="Set the mode.", type=int)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
static.FREEDV_DATA_MODE = args.freedv_data_mode
|
||||
#static.FREEDV_DATA_MODE = args.freedv_data_mode
|
||||
static.AUDIO_INPUT_DEVICE = args.audio_input_device
|
||||
static.AUDIO_OUTPUT_DEVICE = args.audio_output_device
|
||||
static.PORT = args.socket_port
|
||||
|
||||
#--------------------------------------------START CMD SERVER
|
||||
import sock # we need to wait until we got all parameters from argparse
|
||||
import sock # we need to wait until we got all parameters from argparse first before loading sock
|
||||
|
||||
cmd_server_thread = threading.Thread(target=sock.start_cmd_socket, name="cmd server")
|
||||
cmd_server_thread.start()
|
||||
|
|
268
modem.py
268
modem.py
|
@ -11,6 +11,7 @@ from ctypes import *
|
|||
import pathlib
|
||||
import pyaudio
|
||||
import audioop
|
||||
import asyncio
|
||||
#import sys
|
||||
import logging
|
||||
import time
|
||||
|
@ -18,17 +19,12 @@ import threading
|
|||
|
||||
import helpers
|
||||
import static
|
||||
import arq
|
||||
import data_handler
|
||||
|
||||
import Hamlib
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class RF():
|
||||
|
||||
def __init__(self):
|
||||
|
@ -59,9 +55,17 @@ class RF():
|
|||
output_device_index=static.AUDIO_OUTPUT_DEVICE, #static.AUDIO_OUTPUT_DEVICE
|
||||
)
|
||||
#--------------------------------------------START DECODER THREAD
|
||||
FREEDV_DECODER_THREAD = threading.Thread(target=self.receive, args=[static.FREEDV_DATA_MODE,static.FREEDV_SIGNALLING_MODE], name="FREEDV_DECODER_THREAD")
|
||||
FREEDV_DECODER_THREAD.start()
|
||||
FREEDV_DECODER_THREAD_10 = threading.Thread(target=self.receive, args=[10], name="FREEDV_DECODER_THREAD")
|
||||
FREEDV_DECODER_THREAD_10.start()
|
||||
|
||||
FREEDV_DECODER_THREAD_11 = threading.Thread(target=self.receive, args=[11], name="FREEDV_DECODER_THREAD")
|
||||
FREEDV_DECODER_THREAD_11.start()
|
||||
|
||||
FREEDV_DECODER_THREAD_12 = threading.Thread(target=self.receive, args=[12], name="FREEDV_DECODER_THREAD")
|
||||
FREEDV_DECODER_THREAD_12.start()
|
||||
|
||||
FREEDV_DECODER_THREAD_14 = threading.Thread(target=self.receive, args=[static.FREEDV_SIGNALLING_MODE], name="FREEDV_DECODER_THREAD")
|
||||
FREEDV_DECODER_THREAD_14.start()
|
||||
|
||||
|
||||
#--------------------------------------------CONFIGURE HAMLIB
|
||||
|
@ -93,9 +97,13 @@ class RF():
|
|||
self.my_rig.set_ptt(self.hamlib_ptt_type,0)
|
||||
|
||||
#--------------------------------------------------------------------------------------------------------
|
||||
def transmit_arq_ack(self,ack_buffer):
|
||||
def transmit_signalling(self,ack_buffer):
|
||||
#print(ack_buffer)
|
||||
static.ARQ_STATE = 'SENDING_ACK'
|
||||
#static.ARQ_STATE = 'SENDING_ACK'
|
||||
|
||||
state_before_transmit = static.CHANNEL_STATE
|
||||
static.CHANNEL_STATE = 'SENDING_SIGNALLING'
|
||||
|
||||
static.PTT_STATE = True
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type,1)
|
||||
|
||||
|
@ -106,10 +114,11 @@ class RF():
|
|||
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) #get n_tx_modem_samples which defines the size of the modulation object
|
||||
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
||||
|
||||
mod_out = ctypes.c_short * n_tx_modem_samples
|
||||
mod_out = mod_out()
|
||||
mod_out_preamble = ctypes.c_short * (n_tx_modem_samples) #*2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples #*2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = mod_out_preamble()
|
||||
|
||||
buffer = bytearray(payload_per_frame) # use this if CRC16 checksum is required ( DATA1-3)
|
||||
|
@ -120,11 +129,7 @@ class RF():
|
|||
buffer += crc # append crc16 to buffer
|
||||
data = (ctypes.c_ubyte * bytes_per_frame).from_buffer_copy(buffer)
|
||||
|
||||
preamble_bytes = self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
#print(n_tx_modem_samples)
|
||||
#print(preamble_bytes)
|
||||
#print(len(mod_out_preamble))
|
||||
|
||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble)
|
||||
self.c_lib.freedv_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer
|
||||
txbuffer = bytearray()
|
||||
txbuffer += bytes(mod_out_preamble)
|
||||
|
@ -137,15 +142,18 @@ class RF():
|
|||
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type,0)
|
||||
static.PTT_STATE = False
|
||||
|
||||
static.ARQ_STATE = 'RECEIVING_DATA'
|
||||
|
||||
static.CHANNEL_STATE = state_before_transmit
|
||||
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
#static.ARQ_STATE = 'RECEIVING_DATA'
|
||||
#--------------------------------------------------------------------------------------------------------
|
||||
# GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT
|
||||
def transmit_arq_burst(self):
|
||||
async def transmit_arq_burst(self):
|
||||
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type,1)
|
||||
static.PTT_STATE = True
|
||||
static.ARQ_STATE = 'SENDING_DATA'
|
||||
state_before_transmit = static.CHANNEL_STATE
|
||||
static.CHANNEL_STATE = 'SENDING_DATA'
|
||||
|
||||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
freedv = self.c_lib.freedv_open(static.FREEDV_DATA_MODE)
|
||||
|
@ -154,17 +162,15 @@ class RF():
|
|||
|
||||
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
|
||||
n_tx_preamble_modem_samples = self.c_lib.freedv_get_n_tx_preamble_modem_samples(freedv)
|
||||
|
||||
mod_out = ctypes.c_short * n_tx_modem_samples
|
||||
mod_out = mod_out()
|
||||
mod_out_preamble = ctypes.c_short * (3520) #*2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = ctypes.c_short * n_tx_preamble_modem_samples #*2 #1760 for mode 10,11,12 #4000 for mode 9
|
||||
mod_out_preamble = mod_out_preamble()
|
||||
|
||||
preamble = self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble);
|
||||
#print(n_tx_modem_samples)
|
||||
#print(preamble)
|
||||
#print(len(mod_out_preamble))
|
||||
|
||||
self.c_lib.freedv_rawdatapreambletx(freedv, mod_out_preamble);
|
||||
|
||||
txbuffer = bytearray()
|
||||
txbuffer += bytes(mod_out_preamble)
|
||||
|
||||
|
@ -246,155 +252,199 @@ class RF():
|
|||
|
||||
# -------------- transmit audio
|
||||
self.stream_tx.write(bytes(txbuffer))
|
||||
static.ARQ_STATE = 'IDLE'
|
||||
#static.ARQ_STATE = 'RECEIVING_SIGNALLING'
|
||||
#static.ARQ_STATE = 'IDLE'
|
||||
#static.CHANNEL_STATE = state_before_transmit
|
||||
static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
static.PTT_STATE = False
|
||||
self.my_rig.set_ptt(self.hamlib_ptt_type,0)
|
||||
#--------------------------------------------------------------------------------------------------------
|
||||
def receive(self,data_mode,signalling_mode):
|
||||
|
||||
def receive(self,mode):
|
||||
force = True
|
||||
|
||||
self.c_lib.freedv_open.restype = ctypes.POINTER(ctypes.c_ubyte)
|
||||
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)
|
||||
|
||||
if mode == static.FREEDV_SIGNALLING_MODE:
|
||||
static.FREEDV_SIGNALLING_BYTES_PER_FRAME = bytes_per_frame
|
||||
static.FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = bytes_per_frame - 2
|
||||
|
||||
self.c_lib.freedv_set_frames_per_burst(freedv, 1);
|
||||
|
||||
freedv_data = self.c_lib.freedv_open(data_mode)
|
||||
freedv_signalling = self.c_lib.freedv_open(signalling_mode)
|
||||
elif mode == static.ARQ_DATA_CHANNEL_MODE:
|
||||
static.FREEDV_DATA_BYTES_PER_FRAME = bytes_per_frame
|
||||
static.FREEDV_DATA_PAYLOAD_PER_FRAME = bytes_per_frame - 2
|
||||
|
||||
self.c_lib.freedv_set_frames_per_burst(freedv, 0);
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
bytes_out = (ctypes.c_ubyte * bytes_per_frame)
|
||||
bytes_out = bytes_out() #get pointer to bytes_out
|
||||
|
||||
static.FREEDV_DATA_BYTES_PER_FRAME = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv_data)/8)
|
||||
static.FREEDV_DATA_PAYLOAD_PER_FRAME = static.FREEDV_DATA_BYTES_PER_FRAME -2
|
||||
static.FREEDV_SIGNALLING_BYTES_PER_FRAME = int(self.c_lib.freedv_get_bits_per_modem_frame(freedv_signalling)/8)
|
||||
static.FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = static.FREEDV_SIGNALLING_BYTES_PER_FRAME -2
|
||||
|
||||
data_bytes_out = (ctypes.c_ubyte * static.FREEDV_DATA_BYTES_PER_FRAME)
|
||||
data_bytes_out = data_bytes_out() #get pointer to bytes_out
|
||||
|
||||
signalling_bytes_out = (ctypes.c_ubyte * static.FREEDV_SIGNALLING_BYTES_PER_FRAME)
|
||||
signalling_bytes_out = signalling_bytes_out() #get pointer to bytes_out
|
||||
|
||||
self.c_lib.freedv_set_frames_per_burst(freedv_data, 0);
|
||||
self.c_lib.freedv_set_frames_per_burst(freedv_signalling, 1);
|
||||
|
||||
# with this we can interrupt receiving
|
||||
while static.FREEDV_RECEIVE == True:
|
||||
time.sleep(0.01)
|
||||
time.sleep(0.05)
|
||||
|
||||
# stuck in sync counter
|
||||
stuck_in_sync_counter = 0
|
||||
stuck_in_sync_10_counter = 0
|
||||
#
|
||||
|
||||
while static.ARQ_STATE == 'RECEIVING_DATA':
|
||||
|
||||
# here we do a buffer cleanup before returning to demod loop
|
||||
dummy_mod = bytes(self.c_lib.freedv_nin(freedv))
|
||||
self.c_lib.freedv_rawdatarx(freedv, bytes_out, dummy_mod)
|
||||
|
||||
#demod loop
|
||||
while (static.CHANNEL_STATE == 'RECEIVING_DATA' and static.ARQ_DATA_CHANNEL_MODE == mode) or (static.CHANNEL_STATE == 'RECEIVING_SIGNALLING' and static.FREEDV_SIGNALLING_MODE == mode):
|
||||
time.sleep(0.01)
|
||||
# refresh vars, so the correct parameters of the used mode are set
|
||||
static.FREEDV_DATA_BYTES_PER_FRAME = bytes_per_frame
|
||||
static.FREEDV_DATA_PAYLOAD_PER_FRAME = bytes_per_frame - 2
|
||||
|
||||
nin = self.c_lib.freedv_nin(freedv_data)
|
||||
nin = self.c_lib.freedv_nin(freedv)
|
||||
#nin = int(nin*(static.AUDIO_SAMPLE_RATE_RX/static.MODEM_SAMPLE_RATE))
|
||||
|
||||
data_in = self.stream_rx.read(nin, exception_on_overflow = False)
|
||||
#print(audioop.rms(data_in, 2))
|
||||
|
||||
#self.c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), data_bytes_out, data_in] # check if really neccessary
|
||||
nbytes = self.c_lib.freedv_rawdatarx(freedv_data, data_bytes_out, data_in) # demodulate audio
|
||||
logging.debug(self.c_lib.freedv_get_rx_status(freedv_data))
|
||||
nbytes = self.c_lib.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio
|
||||
#logging.debug(self.c_lib.freedv_get_rx_status(freedv))
|
||||
#print("listening-" + str(mode) + "-" + str(self.c_lib.freedv_get_rx_status(freedv)))
|
||||
|
||||
#-------------STUCK IN SYNC DETECTOR
|
||||
stuck_in_sync_counter += 1
|
||||
if self.c_lib.freedv_get_rx_status(freedv_data) == 10:
|
||||
if self.c_lib.freedv_get_rx_status(freedv) == 10:
|
||||
stuck_in_sync_10_counter += 1
|
||||
|
||||
|
||||
if stuck_in_sync_counter == 33 and self.c_lib.freedv_get_rx_status(freedv_data) == 10:
|
||||
if stuck_in_sync_counter == 33 and self.c_lib.freedv_get_rx_status(freedv) == 10:
|
||||
logging.critical("stuck in sync #1")
|
||||
self.c_lib.freedv_set_sync(freedv_data, 0) #FORCE UNSYNC
|
||||
self.c_lib.freedv_set_sync(freedv, 0) #FORCE UNSYNC
|
||||
stuck_in_sync_counter = 0
|
||||
stuck_in_sync_10_counter = 0
|
||||
|
||||
if stuck_in_sync_counter >= 66 and stuck_in_sync_10_counter >= 2:
|
||||
logging.critical("stuck in sync #2")
|
||||
self.c_lib.freedv_set_sync(freedv_data, 0) #FORCE UNSYNC
|
||||
self.c_lib.freedv_set_sync(freedv, 0) #FORCE UNSYNC
|
||||
stuck_in_sync_counter = 0
|
||||
stuck_in_sync_10_counter = 0
|
||||
#-----------------------------------
|
||||
|
||||
|
||||
if nbytes == static.FREEDV_DATA_BYTES_PER_FRAME:
|
||||
rxstatus = self.c_lib.freedv_get_rx_status(freedv_data)
|
||||
logging.debug("DATA-" + str(rxstatus))
|
||||
|
||||
|
||||
if nbytes == bytes_per_frame:##########################################################FREEDV_DATA_BYTES_PER_FRAME
|
||||
self.calculate_ber(freedv)
|
||||
|
||||
# counter reset for stuck in sync counter
|
||||
stuck_in_sync_counter = 0
|
||||
stuck_in_sync_10_counter = 0
|
||||
#
|
||||
|
||||
# CHECK IF FRAMETYPE IS BETWEEN 10 and 50 ------------------------
|
||||
frametype = int.from_bytes(bytes(data_bytes_out[:1]), "big")
|
||||
frametype = int.from_bytes(bytes(bytes_out[:1]), "big")
|
||||
frame = frametype - 10
|
||||
n_frames_per_burst = int.from_bytes(bytes(data_bytes_out[1:2]), "big")
|
||||
n_frames_per_burst = int.from_bytes(bytes(bytes_out[1:2]), "big")
|
||||
|
||||
#self.c_lib.freedv_set_frames_per_burst(freedv_data, n_frames_per_burst);
|
||||
|
||||
if 50 >= frametype >= 10:
|
||||
if frame != 3 or force == True:
|
||||
arq.data_received(bytes(data_bytes_out[:-2])) #send payload data to arq checker without CRC16
|
||||
|
||||
data_handler.arq_data_received(bytes(bytes_out[:-2])) #send payload data to arq checker without CRC16
|
||||
|
||||
#print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None)))
|
||||
if static.ARQ_RX_BURST_BUFFER.count(None) <= 1:
|
||||
logging.debug("FULL BURST BUFFER ---> UNSYNC")
|
||||
self.c_lib.freedv_set_sync(freedv_data, 0)
|
||||
self.c_lib.freedv_set_sync(freedv, 0)
|
||||
|
||||
else:
|
||||
logging.critical("---------------------------SIMULATED MISSING FRAME")
|
||||
force = True
|
||||
else:
|
||||
logging.info("MODE: " + str(data_mode) + " DATA: " + str(bytes(data_bytes_out)))
|
||||
|
||||
|
||||
# DO UNSYNC AFTER LAST BURST by checking the frame numbers agains the total frames per burst
|
||||
if frame == n_frames_per_burst:
|
||||
logging.debug("LAST FRAME ---> UNSYNC")
|
||||
self.c_lib.freedv_set_sync(freedv_data, 0) #FORCE UNSYNC
|
||||
|
||||
|
||||
#while static.ARQ_STATE == 'IDLE' or static.ARQ_STATE == 'RECEIVING_SIGNALLING':
|
||||
while static.ARQ_STATE == 'RECEIVING_SIGNALLING':
|
||||
time.sleep(0.01)
|
||||
|
||||
nin = self.c_lib.freedv_nin(freedv_signalling)
|
||||
#nin = int(nin*(static.AUDIO_SAMPLE_RATE_RX/static.MODEM_SAMPLE_RATE))
|
||||
|
||||
data_in = self.stream_rx.read(nin, exception_on_overflow = False)
|
||||
|
||||
#self.c_lib.freedv_rawdatarx.argtype = [ctypes.POINTER(ctypes.c_ubyte), signalling_bytes_out, data_in] # check if really neccessary
|
||||
nbytes = self.c_lib.freedv_rawdatarx(freedv_signalling, signalling_bytes_out, data_in) # demodulate audio
|
||||
|
||||
# CHECK IF FRAME CONTAINS ACK------------------------
|
||||
|
||||
if nbytes == static.FREEDV_SIGNALLING_BYTES_PER_FRAME:
|
||||
#self.c_lib.freedv_set_sync(freedv_signalling, 0)
|
||||
frametype = int.from_bytes(bytes(signalling_bytes_out[:1]), "big")
|
||||
|
||||
# BURST ACK
|
||||
if frametype == 60:
|
||||
elif frametype == 60:
|
||||
logging.debug("ACK RECEIVED....")
|
||||
arq.burst_ack_received()
|
||||
data_handler.burst_ack_received()
|
||||
|
||||
# FRAME ACK
|
||||
elif frametype == 61:
|
||||
logging.debug("FRAME ACK RECEIVED....")
|
||||
arq.frame_ack_received()
|
||||
data_handler.frame_ack_received()
|
||||
|
||||
# FRAME RPT
|
||||
elif frametype == 62:
|
||||
logging.debug("REPEAT REQUEST RECEIVED....")
|
||||
arq.burst_rpt_received(signalling_bytes_out[:-2])
|
||||
data_handler.burst_rpt_received(bytes_out[:-2])
|
||||
|
||||
# CQ FRAME
|
||||
elif frametype == 200:
|
||||
logging.info("CQ RECEIVED....")
|
||||
|
||||
# PING FRAME
|
||||
elif frametype == 210:
|
||||
logging.debug("PING RECEIVED....")
|
||||
data_handler.received_ping(bytes_out[:-2])
|
||||
|
||||
# PING ACK
|
||||
elif frametype == 211:
|
||||
logging.debug("PING ACK RECEIVED....")
|
||||
data_handler.received_ping_ack(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT
|
||||
elif frametype == 220:
|
||||
logging.debug("ARQ CONNECT RECEIVED....")
|
||||
data_handler.arq_received_connect(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 221:
|
||||
logging.debug("ARQ CONNECT ACK RECEIVED / KEEP ALIVE....")
|
||||
data_handler.arq_received_connect_keep_alive(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 222:
|
||||
logging.debug("ARQ DISCONNECT RECEIVED")
|
||||
data_handler.arq_disconnect_received(bytes_out[:-2])
|
||||
|
||||
# ARQ FILE TRANSFER RECEIVED!
|
||||
elif frametype == 225:
|
||||
logging.debug("ARQ arq_received_data_channel_opener RECEIVED")
|
||||
data_handler.arq_received_data_channel_opener(bytes_out[:-2])
|
||||
|
||||
# ARQ CHANNEL IS OPENED
|
||||
elif frametype == 226:
|
||||
logging.debug("ARQ arq_received_channel_is_open RECEIVED")
|
||||
data_handler.arq_received_channel_is_open(bytes_out[:-2])
|
||||
|
||||
# ARQ CONNECT ACK / KEEP ALIVE
|
||||
elif frametype == 230:
|
||||
logging.debug("BEACON RECEIVED")
|
||||
|
||||
else:
|
||||
logging.debug("OTHER FRAME: " + str(signalling_bytes_out[:-2]))
|
||||
logging.info("OTHER FRAME: " + str(bytes_out[:-2]))
|
||||
print(frametype)
|
||||
|
||||
|
||||
rxstatus = self.c_lib.freedv_get_rx_status(freedv_signalling)
|
||||
logging.debug("ACK-" + str(rxstatus))
|
||||
# DO UNSYNC AFTER LAST BURST by checking the frame nums agains the total frames per burst
|
||||
if frame == n_frames_per_burst:
|
||||
logging.debug("LAST FRAME ---> UNSYNC")
|
||||
self.c_lib.freedv_set_sync(freedv, 0) #FORCE UNSYNC
|
||||
|
||||
rxstatus = self.c_lib.freedv_get_rx_status(freedv)
|
||||
#logging.info("DATA-" + str(mode) + " " +str(rxstatus))
|
||||
if rxstatus == 10:
|
||||
#self.c_lib.freedv_set_sync(freedv_signalling, 0) #FORCE UNSYNC
|
||||
print("SIGNALLING -SYNC 10- Trigger")
|
||||
#if nbytes == static.FREEDV_SIGNALLING_BYTES_PER_FRAME or rxstatus == 10:
|
||||
# self.c_lib.freedv_set_sync(freedv_signalling, 0) #FORCE UNSYNC
|
||||
|
||||
self.c_lib.freedv_set_sync(freedv, 0) #FORCE UNSYNC
|
||||
logging.warning("MODEM | SYNC 10 TRIGGER | M:" + str(mode))
|
||||
self.calculate_ber(freedv)
|
||||
|
||||
|
||||
def calculate_ber(self,freedv):
|
||||
Tbits = self.c_lib.freedv_get_total_bits(freedv)
|
||||
Terrs = self.c_lib.freedv_get_total_bit_errors(freedv)
|
||||
if Tbits != 0:
|
||||
ber = (Terrs/Tbits)*100
|
||||
static.BER = int(ber)
|
||||
|
||||
self.c_lib.freedv_set_total_bit_errors(freedv,0)
|
||||
self.c_lib.freedv_set_total_bits(freedv,0)
|
||||
|
||||
|
|
113
sock.py
113
sock.py
|
@ -12,45 +12,121 @@ import logging
|
|||
import time
|
||||
|
||||
import static
|
||||
import arq
|
||||
import data_handler
|
||||
import helpers
|
||||
import fec
|
||||
|
||||
import asyncio
|
||||
|
||||
class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
|
||||
encoding = 'utf-8'
|
||||
data = str(self.request.recv(1024), 'utf-8')
|
||||
#data = str(self.request.recv(1024), 'utf-8')
|
||||
|
||||
data = bytes()
|
||||
while True:
|
||||
chunk = self.request.recv(8192)#.strip()
|
||||
data += chunk
|
||||
if chunk.endswith(b'\n'):
|
||||
break
|
||||
data = data[:-1] # remove b'\n'
|
||||
data = str(data, 'utf-8')
|
||||
|
||||
# SOCKETTEST
|
||||
# SOCKETTEST ---------------------------------------------------
|
||||
if data == 'SOCKETTEST':
|
||||
cur_thread = threading.current_thread()
|
||||
response = bytes("WELL DONE! YOU ARE ABLE TO COMMUNICATE WITH THE TNC", encoding)
|
||||
self.request.sendall(response)
|
||||
|
||||
# TRANSMIT ARQ MESSAGE
|
||||
if data.startswith('ARQ:') and static.TNC_STATE == b'IDLE':
|
||||
logging.info("CMD | NEW ARQ DATA")
|
||||
static.TNC_STATE = b'BUSY'
|
||||
arqdata = data.split('ARQ:')
|
||||
data_out = bytes(arqdata[1], 'utf-8')
|
||||
|
||||
# CQ CQ CQ -----------------------------------------------------
|
||||
if data == 'CQCQCQ':
|
||||
for i in range(0,3):
|
||||
data_handler.transmit_cq()
|
||||
self.request.sendall(bytes("CALLING CQ"))
|
||||
while static.ARQ_STATE == 'SENDING_SIGNALLING':
|
||||
time.sleep(0.1)
|
||||
pass
|
||||
|
||||
TRANSMIT_ARQ = threading.Thread(target=arq.transmit, args=[data_out], name="TRANSMIT_ARQ")
|
||||
TRANSMIT_ARQ.start()
|
||||
|
||||
# PING ----------------------------------------------------------
|
||||
if data.startswith('PING:'):
|
||||
#send ping frame and wait for ACK
|
||||
pingcommand = data.split('PING:')
|
||||
dxcallsign = pingcommand[1]
|
||||
data_handler.transmit_ping(dxcallsign)
|
||||
|
||||
|
||||
# ARQ CONNECT TO CALLSIGN ----------------------------------------
|
||||
if data.startswith('ARQ:CONNECT:'):
|
||||
arqconnectcommand = data.split('ARQ:CONNECT:')
|
||||
dxcallsign = arqconnectcommand[1]
|
||||
static.DXCALLSIGN = bytes(dxcallsign, 'utf-8')
|
||||
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
|
||||
|
||||
if static.ARQ_STATE == 'CONNECTED':
|
||||
# here we could disconnect
|
||||
pass
|
||||
|
||||
if static.TNC_STATE == 'IDLE':
|
||||
# here we send an "CONNECT FRAME
|
||||
|
||||
#ARQ_CONNECT_THREAD = threading.Thread(target=data_handler.arq_connect, name="ARQ_CONNECT")
|
||||
#ARQ_CONNECT_THREAD.start()
|
||||
asyncio.run(data_handler.arq_connect())
|
||||
self.request.sendall(bytes("CONNECTING", encoding))
|
||||
#data_handler.arq_connect()
|
||||
# ARQ DISCONNECT FROM CALLSIGN ----------------------------------------
|
||||
if data == 'ARQ:DISCONNECT':
|
||||
|
||||
#ARQ_DISCONNECT_THREAD = threading.Thread(target=data_handler.arq_disconnect, name="ARQ_DISCONNECT")
|
||||
#ARQ_DISCONNECT_THREAD.start()
|
||||
asyncio.run(data_handler.arq_disconnect())
|
||||
self.request.sendall(bytes("DISCONNECTING", encoding))
|
||||
#data_handler.arq_disconnect()
|
||||
|
||||
|
||||
# TRANSMIT ARQ MESSAGE ------------------------------------------
|
||||
# wen need to change the TNC_STATE to "CONNECTE" and need to make sure we have a valid callsign and callsign crc8 of the DX station
|
||||
#print(static.ARQ_STATE)
|
||||
if data.startswith('ARQ:DATA') and static.ARQ_STATE == 'CONNECTED':
|
||||
static.ARQ_READY_FOR_DATA = False
|
||||
logging.info("CMD | NEW ARQ DATA")
|
||||
self.request.sendall(b'SENDIN ARQ DATA')
|
||||
asyncio.run(data_handler.arq_open_data_channel())
|
||||
#data_handler.arq_open_data_channel()
|
||||
|
||||
#wait until we set the data mode
|
||||
# here we need a timeout as well!!!
|
||||
while static.ARQ_READY_FOR_DATA == False:
|
||||
time.sleep(0.01)
|
||||
|
||||
if static.ARQ_READY_FOR_DATA == True:
|
||||
#logging.info("CMD | SENDING ARQ DATA")
|
||||
static.TNC_STATE = 'BUSY'
|
||||
arqdata = data.split('ARQ:')
|
||||
data_out = bytes(arqdata[1], 'utf-8')
|
||||
|
||||
asyncio.run(data_handler.arq_transmit(data_out))
|
||||
|
||||
#data_handler.arq_transmit(data_out)
|
||||
#TRANSMIT_ARQ = threading.Thread(target=data_handler.transmit, args=[data_out], name="TRANSMIT_ARQ")
|
||||
#TRANSMIT_ARQ.start()
|
||||
|
||||
|
||||
|
||||
# SETTINGS AND STATUS
|
||||
# SETTINGS AND STATUS ---------------------------------------------
|
||||
if data.startswith('SET:MYCALLSIGN:'):
|
||||
data = data.split('SET:MYCALLSIGN:')
|
||||
if bytes(data[1], encoding) == b'':
|
||||
callsign = data.split('SET:MYCALLSIGN:')
|
||||
if bytes(callsign[1], encoding) == b'':
|
||||
self.request.sendall(b'INVALID CALLSIGN')
|
||||
else:
|
||||
static.MYCALLSIGN = bytes(data[1], encoding)
|
||||
static.MYCALLSIGN = bytes(callsign[1], encoding)
|
||||
static.MYCALLSIGN_CRC8 = helpers.get_crc_8(static.MYCALLSIGN)
|
||||
self.request.sendall(static.MYCALLSIGN)
|
||||
logging.info("CMD | MYCALLSIGN: " + str(static.MYCALLSIGN))
|
||||
|
||||
|
||||
|
||||
if data == 'GET:MYCALLSIGN':
|
||||
self.request.sendall(bytes(static.MYCALLSIGN, encoding))
|
||||
|
@ -66,9 +142,6 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
|
|||
|
||||
if data == 'GET:PTT_STATE':
|
||||
self.request.sendall(bytes(str(static.PTT_STATE), encoding))
|
||||
|
||||
|
||||
|
||||
|
||||
# ARQ
|
||||
if data == 'GET:ARQ_STATE':
|
||||
|
|
44
static.py
44
static.py
|
@ -16,9 +16,9 @@ DXCALLSIGN_CRC8 = b'A'
|
|||
MYGRID = b''
|
||||
|
||||
|
||||
TNC_STATE = b'IDLE'
|
||||
|
||||
PTT_STATE = False
|
||||
|
||||
|
||||
|
||||
#---------------------------------
|
||||
|
||||
|
@ -51,7 +51,7 @@ PORT = 3000
|
|||
#PTT control through CM108 GPIO pin
|
||||
|
||||
HAMLIB_PTT_TYPE = 'RIG_PTT_NONE'
|
||||
|
||||
PTT_STATE = False
|
||||
|
||||
|
||||
|
||||
|
@ -62,13 +62,15 @@ HAMLIB_PTT_TYPE = 'RIG_PTT_NONE'
|
|||
# FreeDV Defaults
|
||||
FREEDV_RECEIVE = True
|
||||
|
||||
FREEDV_DATA_MODE = 10
|
||||
FREEDV_DATA_MODE = 12
|
||||
FREEDV_SIGNALLING_MODE = 14
|
||||
|
||||
FREEDV_DATA_BYTES_PER_FRAME = 0
|
||||
FREEDV_DATA_PAYLOAD_PER_FRAME = 0
|
||||
FREEDV_SIGNALLING_BYTES_PER_FRAME = 0
|
||||
FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = 0
|
||||
|
||||
BER = 0
|
||||
#---------------------------------
|
||||
|
||||
#Audio Defaults
|
||||
|
@ -85,7 +87,7 @@ AUDIO_CHANNELS = 1
|
|||
#---------------------------------
|
||||
|
||||
#ARQ DEFAULTS
|
||||
TX_N_MAX_RETRIES = 10
|
||||
TX_N_MAX_RETRIES = 5
|
||||
TX_N_RETRIES = 0
|
||||
|
||||
ARQ_TX_N_FRAMES_PER_BURST = 0
|
||||
|
@ -141,10 +143,34 @@ ARQ_N_SENT_FRAMES = 0 #counter for already sent frames
|
|||
# RECEIVING_SIGNALLING
|
||||
# SENDING_ACK
|
||||
# ACK_RECEIVED
|
||||
#
|
||||
#
|
||||
#
|
||||
ARQ_STATE = 'RECEIVING_DATA'
|
||||
|
||||
# CONNECTED
|
||||
# DISCONNECTED
|
||||
# CONNECTING
|
||||
# DISCONNECTING
|
||||
ARQ_STATE = 'IDLE'
|
||||
|
||||
# RECEIVING_SIGNALLING
|
||||
# RECEIVING_DATA_10
|
||||
# RECEIVING_DATA_11
|
||||
# RECEIVING_DATA_12
|
||||
CHANNEL_STATE = 'RECEIVING_SIGNALLING'
|
||||
|
||||
# IDLE
|
||||
# BUSY
|
||||
TNC_STATE = 'IDLE'
|
||||
|
||||
# MODE FOR SENDING AN RECEIVING DATA DURING ARQ SESSION
|
||||
# 0 = NOT WAITING FOR DATA
|
||||
# 1 = TELL DX STATION WE WANT TO SEND DATA
|
||||
# 2 = DX STATION IS READY FOR DATA
|
||||
# 3 = DX STATION SAID, THEY ARE READY FOR DATA
|
||||
ARQ_READY_FOR_DATA = False
|
||||
ARQ_DATA_CHANNEL_MODE = 12
|
||||
|
||||
# SEND KEEP ALIVE ONLY IF WE WANT
|
||||
ARQ_SEND_KEEP_ALIVE = True
|
||||
#ARQ_WAIT_FOR_DISCONNECT = False
|
||||
|
||||
# ------- TX BUFFER
|
||||
TX_BUFFER_SIZE = 0
|
||||
|
|
23
tools/init_and_send.sh
Normal file
23
tools/init_and_send.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
for i in {1..5}
|
||||
do
|
||||
echo "Welcome $i times"
|
||||
done
|
||||
|
||||
python3 readfromsocket.py --port 3002 --data "SET:MYCALLSIGN:DJ2LS"
|
||||
python3 readfromsocket.py --port 3000 --data "SET:MYCALLSIGN:DH3WO"
|
||||
sleep 3
|
||||
#python3 readfromsocket.py --port 3002 --data "CQCQCQ"
|
||||
#sleep 5
|
||||
python3 readfromsocket.py --port 3002 --data "PING:DH3WO"
|
||||
sleep 5
|
||||
python3 readfromsocket.py --port 3002 --data "ARQ:CONNECT:DH3WO"
|
||||
#sleep 1
|
||||
python3 readfromsocket.py --port 3000 --data "GET:ARQ_STATE"
|
||||
sleep 5
|
||||
echo "ACHTUNG DATEI"
|
||||
python3 socketclient.py --port 3002 --random 100
|
||||
|
||||
|
||||
sleep 10
|
||||
python3 readfromsocket.py --port 3000 --data "ARQ:DISCONNECT"
|
||||
echo "ende..."
|
24
tools/list_audio_devices.py
Normal file
24
tools/list_audio_devices.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pyaudio
|
||||
|
||||
|
||||
def list_audio_devices():
|
||||
p = pyaudio.PyAudio()
|
||||
devices = []
|
||||
print("--------------------------------------------------------------------")
|
||||
for x in range(0, p.get_device_count()):
|
||||
devices.append(f"{x} - {p.get_device_info_by_index(x)['name']}")
|
||||
|
||||
for line in devices:
|
||||
print(line)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
list_audio_devices()
|
|
@ -24,12 +24,14 @@ args = parser.parse_args()
|
|||
ip, port = "localhost", args.socket_port
|
||||
message = args.data
|
||||
|
||||
print(len(b'\n'))
|
||||
|
||||
while True:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
print(ip)
|
||||
print(port)
|
||||
sock.connect((ip, port))
|
||||
sock.sendall(bytes(message, 'utf-8'))
|
||||
sock.sendall(bytes(message, 'utf-8') + b'\n')
|
||||
response = str(sock.recv(1024), 'utf-8')
|
||||
print("Received: {}".format(response))
|
||||
print("CMD: {}".format(response))
|
||||
False
|
||||
break
|
|
@ -43,7 +43,7 @@ args = parser.parse_args()
|
|||
|
||||
|
||||
data = create_string(args.datalength)
|
||||
data = bytes("ARQ:" + "" + data + "" + "\n", "utf-8")
|
||||
data = bytes("ARQ:DATA:" + "" + data + "" + "\n", "utf-8")
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue