FreeDATA/tnc/data_handler.py

1052 lines
46 KiB
Python
Raw Normal View History

2021-02-24 13:22:28 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Dec 27 20:43:40 2020
@author: DJ2LS
"""
import sys
2021-11-18 18:40:22 +00:00
import logging, structlog, log_handler
2021-02-24 13:22:28 +00:00
import threading
import time
from random import randrange
2021-02-28 16:28:07 +00:00
import asyncio
import ujson as json
2021-02-24 13:22:28 +00:00
import static
import modem
import helpers
2021-03-12 13:14:36 +00:00
modem = modem.RF()
2021-02-24 13:22:28 +00:00
2021-09-26 15:51:11 +00:00
'''
Author: DJ2LS
Description:
data_handler is a module like file, which handles all the ARQ related parts.
Because of the fact, that we need to use it from both directions,
socket.py and modem.py ( TX and RX ), I was not able, to move it to a class system, yet.
Global variables are needed, because we need to save our ack state for example, which needs to
be accessable by several functions.
If we want to use global varialbes within a multithreaded environment,
2021-09-26 15:51:11 +00:00
we need to declare every needed variable in every function, so the threading module can
detect and use them.
From time to time I try to reduce the amount of application wide variables within static. module
and moving them to module wide globals
2021-09-26 15:51:11 +00:00
'''
# MODULE GLOBALS
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_READY_FOR_DATA = False # Indicator if we are ready for sending or receiving data
DATA_CHANNEL_LAST_RECEIVED = 0.0 # time of last "live sign" of a frame
DATA_CHANNEL_MODE = 0 # mode for data channel
BURST_ACK_RECEIVED = False # if we received an acknowledge frame for a burst
DATA_FRAME_ACK_RECEIVED = False # if we received an acknowledge frame for a data frame
RPT_REQUEST_RECEIVED = False # if we received an request for repeater frames
RPT_REQUEST_BUFFER = [] # requested frames, saved in a list
RX_START_OF_TRANSMISSION = 0 # time of transmission start
# ################################################
2021-02-24 15:47:52 +00:00
# ARQ DATA HANDLER
2021-09-26 15:51:11 +00:00
# ################################################
def arq_data_received(data_in, bytes_per_frame):
# we neeed to declare our global variables, so the thread has access to them
global RX_START_OF_TRANSMISSION
global DATA_CHANNEL_LAST_RECEIVED
global DATA_CHANNEL_READY_FOR_DATA
2021-09-26 15:51:11 +00:00
# only process data if we are in ARQ and BUSY state else return to quit
if static.ARQ_STATE != 'DATA' and static.TNC_STATE != 'BUSY':
return
# these vars will be overwritten during processing data
RX_FRAME_BOF_RECEIVED = False # here we save, if we received a "beginn of (data)frame"
RX_FRAME_EOF_RECEIVED = False # here we save, if we received a "end of (data)frame"
DATA_FRAME_BOF = b'\xAA\xAA' # 2 bytes for the BOF End of File indicator in a data frame
DATA_FRAME_EOF = b'\xFF\xFF' # 2 bytes for the EOF End of File indicator in a data frame
RX_PAYLOAD_PER_MODEM_FRAME = bytes_per_frame - 2 # payload per moden frame
RX_PAYLOAD_PER_ARQ_FRAME = RX_PAYLOAD_PER_MODEM_FRAME - 8 # payload per arq frame
2021-02-24 13:22:28 +00:00
2021-03-12 13:14:36 +00:00
static.TNC_STATE = 'BUSY'
2021-09-26 15:51:11 +00:00
static.ARQ_STATE = 'DATA'
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
2021-11-07 19:31:26 +00:00
# get some important data from the frame
2021-09-26 15:51:11 +00:00
RX_N_FRAME_OF_BURST = int.from_bytes(bytes(data_in[:1]), "big") - 10 # get number of burst frame
RX_N_FRAMES_PER_BURST = int.from_bytes(bytes(data_in[1:2]), "big") # get number of bursts from received frame
RX_N_FRAME_OF_DATA_FRAME = int.from_bytes(bytes(data_in[2:4]), "big") # get current number of total frames
RX_N_FRAMES_PER_DATA_FRAME = int.from_bytes(bytes(data_in[4:6]), "big") # get total number of frames
static.TOTAL_BYTES = RX_N_FRAMES_PER_DATA_FRAME * RX_PAYLOAD_PER_ARQ_FRAME # calculate total bytes
2021-11-19 16:30:17 +00:00
##arq_percent_burst = int((RX_N_FRAME_OF_BURST / RX_N_FRAMES_PER_BURST) * 100)
#arq_percent_frame = int(((RX_N_FRAME_OF_DATA_FRAME) / RX_N_FRAMES_PER_DATA_FRAME) * 100)
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
static.INFO.append("ARQ;RECEIVING")
2021-11-19 16:30:17 +00:00
frame_progress = str(RX_N_FRAME_OF_BURST) + "/" + str(RX_N_FRAMES_PER_BURST)
total_frame_progress = str(RX_N_FRAME_OF_DATA_FRAME) + "/" + str(RX_N_FRAMES_PER_DATA_FRAME)
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
structlog.get_logger("structlog").info("[TNC] ARQ | RX | DATA FRAME", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress)
2021-09-26 15:51:11 +00:00
# allocate ARQ_static.RX_FRAME_BUFFER as a list with "None" if not already done. This should be done only once per burst!
2021-03-12 13:14:36 +00:00
# here we will save the N frame of a data frame to N list position so we can explicit search for it
2021-03-12 13:14:36 +00:00
# delete frame buffer if first frame to make sure the buffer is cleared and no junks of a old frame is remaining
# normally this shouldn't appear, since we are doing a buffer cleanup after every frame processing
# but better doing this, to avoid problems caused by old chunks in data
if RX_N_FRAME_OF_DATA_FRAME == 1:
static.RX_FRAME_BUFFER = []
#
# # we set the start of transmission - 7 seconds, which is more or less the transfer time for the first frame
# RX_START_OF_TRANSMISSION = time.time() - 7
# calculate_transfer_rate()
2021-09-11 07:21:22 +00:00
#try appending data to frame buffer
2021-03-12 13:14:36 +00:00
try:
2021-09-26 15:51:11 +00:00
static.RX_FRAME_BUFFER[RX_N_FRAME_OF_DATA_FRAME] = bytes(data_in)
2021-09-11 07:21:22 +00:00
2021-03-12 13:14:36 +00:00
except IndexError:
# we are receiving new data, so we are doing a cleanup first
2021-09-26 15:51:11 +00:00
static.RX_FRAME_BUFFER = []
# set the start of transmission - 7 seconds,
# which is more or less the transfer time for the first frame
RX_START_OF_TRANSMISSION = time.time() - 6
2021-09-26 15:51:11 +00:00
for i in range(0, RX_N_FRAMES_PER_DATA_FRAME + 1):
static.RX_FRAME_BUFFER.insert(i, None)
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
static.RX_FRAME_BUFFER[RX_N_FRAME_OF_DATA_FRAME] = bytes(data_in)
2021-09-11 07:21:22 +00:00
#if RX_N_FRAME_OF_BURST == 1:
# static.ARQ_START_OF_BURST = time.time() - 6
2021-09-11 07:21:22 +00:00
# try appending data to burst buffer
2021-03-12 13:14:36 +00:00
try:
2021-09-26 15:51:11 +00:00
static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = bytes(data_in)
2021-09-11 07:21:22 +00:00
2021-03-12 13:14:36 +00:00
except IndexError:
2021-09-26 15:51:11 +00:00
static.RX_BURST_BUFFER = []
2021-03-17 10:22:06 +00:00
2021-09-26 15:51:11 +00:00
for i in range(0, RX_N_FRAMES_PER_BURST + 1):
static.RX_BURST_BUFFER.insert(i, None)
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
static.RX_BURST_BUFFER[RX_N_FRAME_OF_BURST] = bytes(data_in)
2021-03-12 13:14:36 +00:00
# - ------------------------- ARQ BURST CHECKER
# run only if we recieved all ARQ FRAMES per ARQ BURST
# and we didnt receive the last burst of a data frame
# if we received the last burst of a data frame, we can directly send a frame ack to
# improve transfer rate
if static.RX_BURST_BUFFER.count(None) == 1 and RX_N_FRAMES_PER_DATA_FRAME != RX_N_FRAME_OF_DATA_FRAME : # count nones
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING BURST ACK")
2021-03-12 13:14:36 +00:00
# BUILDING ACK FRAME FOR BURST -----------------------------------------------
ack_frame = bytearray(14)
ack_frame[:1] = bytes([60])
ack_frame[1:2] = static.DXCALLSIGN_CRC8
ack_frame[2:3] = static.MYCALLSIGN_CRC8
2021-03-12 13:14:36 +00:00
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
#helpers.wait(0.3)
txbuffer = [ack_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
#static.CHANNEL_STATE = 'RECEIVING_DATA'
2021-03-12 13:14:36 +00:00
# clear burst buffer
2021-09-26 15:51:11 +00:00
static.RX_BURST_BUFFER = []
2021-03-12 13:14:36 +00:00
# if decoded N frames are unequal to expected frames per burst
2021-09-26 15:51:11 +00:00
elif RX_N_FRAME_OF_BURST == RX_N_FRAMES_PER_BURST and static.RX_BURST_BUFFER.count(None) != 1:
2021-03-12 13:14:36 +00:00
# --------------- CHECK WHICH BURST FRAMES WE ARE MISSING -------------------------------------------
missing_frames = b''
2021-09-26 15:51:11 +00:00
for burstnumber in range(1, len(static.RX_BURST_BUFFER)):
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
if static.RX_BURST_BUFFER[burstnumber] == None:
logging.debug("RX_N_FRAME_OF_DATA_FRAME" + str(RX_N_FRAME_OF_DATA_FRAME))
logging.debug("ARQ_N_RX_FRAMES_PER_BURSTS" + str(RX_N_FRAMES_PER_BURST))
2021-03-12 13:14:36 +00:00
frame_number = burstnumber
frame_number = frame_number.to_bytes(2, byteorder='big')
missing_frames += frame_number
structlog.get_logger("structlog").warning("[TNC] ARQ | RX | RPT FRAMES", snr=static.SNR, frames=missing_frames)
2021-03-12 13:14:36 +00:00
# BUILDING RPT FRAME FOR BURST -----------------------------------------------
2021-09-26 15:51:11 +00:00
rpt_frame = bytearray(14)
rpt_frame[:1] = bytes([62])
rpt_frame[1:2] = static.DXCALLSIGN_CRC8
rpt_frame[2:3] = static.MYCALLSIGN_CRC8
rpt_frame[3:9] = missing_frames
2021-03-12 13:14:36 +00:00
# TRANSMIT RPT FRAME FOR BURST-----------------------------------------------
txbuffer = [rpt_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
#while not modem.transmit_signalling(rpt_frame, 1):
# time.sleep(0.01)
#static.CHANNEL_STATE = 'RECEIVING_DATA'
2021-03-12 13:14:36 +00:00
# ---------------------------- FRAME MACHINE
# --------------- IF LIST NOT CONTAINS "None" stick everything together
complete_data_frame = bytearray()
2021-09-26 15:51:11 +00:00
if static.RX_FRAME_BUFFER.count(None) == 1: # 1 because position 0 of list will alaways be None in our case
#logging.debug("DECODING FRAME!")
2021-09-26 15:51:11 +00:00
for frame in range(1, len(static.RX_FRAME_BUFFER)):
raw_arq_frame = static.RX_FRAME_BUFFER[frame]
2021-03-12 13:14:36 +00:00
arq_frame_payload = raw_arq_frame[8:]
# -------- DETECT IF WE RECEIVED A FRAME HEADER THEN SAVE DATA TO GLOBALS
2021-09-26 15:51:11 +00:00
if arq_frame_payload[2:4].startswith(DATA_FRAME_BOF):
data_frame_crc = arq_frame_payload[:2]
RX_FRAME_BOF_RECEIVED = True
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_BOF)
2021-03-12 13:14:36 +00:00
arq_frame_payload = arq_frame_payload[1]
#logging.debug("BOF")
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
2021-03-12 13:14:36 +00:00
# -------- DETECT IF WE RECEIVED A FRAME FOOTER THEN SAVE DATA TO GLOBALS
# we need to check for at least one xFF. Sometimes we have only one xFF, because the second one is in the next frame
2021-09-26 15:51:11 +00:00
if arq_frame_payload.rstrip(b'\x00').endswith(DATA_FRAME_EOF) or arq_frame_payload.rstrip(b'\x00').endswith(DATA_FRAME_EOF[:-1]):
RX_FRAME_EOF_RECEIVED = True
if arq_frame_payload.rstrip(b'\x00').endswith(DATA_FRAME_EOF[:-1]):
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_EOF[:-1])
2021-03-12 13:14:36 +00:00
arq_frame_payload = arq_frame_payload[0]
else:
2021-09-26 15:51:11 +00:00
arq_frame_payload = arq_frame_payload.split(DATA_FRAME_EOF)
2021-03-12 13:14:36 +00:00
arq_frame_payload = arq_frame_payload[0]
#logging.debug("EOF")
2021-03-12 13:14:36 +00:00
# --------- 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
2021-09-26 15:51:11 +00:00
if RX_FRAME_BOF_RECEIVED and RX_FRAME_EOF_RECEIVED:
2021-03-12 13:14:36 +00:00
frame_payload_crc = helpers.get_crc_16(complete_data_frame)
# IF THE FRAME PAYLOAD CRC IS EQUAL TO THE FRAME CRC WHICH IS KNOWN FROM THE HEADER --> SUCCESS
2021-09-26 15:51:11 +00:00
if frame_payload_crc == data_frame_crc:
static.INFO.append("ARQ;RECEIVING;SUCCESS")
structlog.get_logger("structlog").info("[TNC] ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED")
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
# decode to utf-8 string
complete_data_frame = complete_data_frame.decode("utf-8")
# decode json objects from data frame to inspect if we received a file or message
rawdata = json.loads(complete_data_frame)
2021-08-16 17:41:20 +00:00
# if datatype is a file, we append to RX_BUFFER, which contains files only
if rawdata["datatype"] == "file":
#logging.debug("RECEIVED FILE --> MOVING DATA TO RX BUFFER")
static.RX_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
# if datatype is a file, we append to RX_MSG_BUFFER, which contains messages only
if rawdata["datatype"] == "message":
static.RX_MSG_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), complete_data_frame])
#logging.debug("RECEIVED MESSAGE --> MOVING DATA TO MESSAGE BUFFER")
2021-03-12 13:14:36 +00:00
# BUILDING ACK FRAME FOR DATA FRAME -----------------------------------------------
2021-09-26 15:51:11 +00:00
ack_frame = bytearray(14)
ack_frame[:1] = bytes([61])
ack_frame[1:2] = static.DXCALLSIGN_CRC8
ack_frame[2:3] = static.MYCALLSIGN_CRC8
2021-03-12 13:14:36 +00:00
# TRANSMIT ACK FRAME FOR BURST-----------------------------------------------
structlog.get_logger("structlog").info("[TNC] ARQ | RX | SENDING DATA FRAME ACK", snr=static.SNR, crc=data_frame_crc.hex())
# since simultaneous decoding it seems, we don't have to wait anymore
# however, we will wait a little bit for easier ptt debugging
# possibly we can remove this later
helpers.wait(0.5)
txbuffer = [ack_frame]
modem.transmit(mode=14, repeats=2, repeat_delay=250, frames=txbuffer)
#while not modem.transmit_signalling(ack_frame, 3):
# time.sleep(0.01)
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
#arq_reset_frame_machine()
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = 'IDLE'
DATA_CHANNEL_READY_FOR_DATA = False
static.RX_BURST_BUFFER = []
static.RX_FRAME_BUFFER = []
structlog.get_logger("structlog").info("[TNC] DATACHANNEL [" + str(static.MYCALLSIGN, 'utf-8') + "]<< >>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
2021-03-12 13:14:36 +00:00
else:
2021-11-18 18:40:22 +00:00
structlog.get_logger("structlog").debug("[TNC] ARQ: ", ARQ_FRAME_BOF_RECEIVED=RX_FRAME_BOF_RECEIVED, ARQ_FRAME_EOF_RECEIVED=RX_FRAME_EOF_RECEIVED )
calculate_transfer_rate_rx(RX_N_FRAMES_PER_DATA_FRAME, RX_N_FRAME_OF_DATA_FRAME, RX_START_OF_TRANSMISSION, RX_PAYLOAD_PER_ARQ_FRAME)
static.INFO.append("ARQ;RECEIVING;FAILED")
structlog.get_logger("structlog").warning("[TNC] ARQ | RX | DATA FRAME NOT SUCESSFULLY RECEIVED!")
# STATE CLEANUP
#arq_reset_frame_machine()
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = 'IDLE'
DATA_CHANNEL_READY_FOR_DATA = False
static.RX_BURST_BUFFER = []
static.RX_FRAME_BUFFER = []
structlog.get_logger("structlog").info("[TNC] DATACHANNEL [" + str(static.MYCALLSIGN, 'utf-8') + "]<<X>>[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
2021-09-26 15:51:11 +00:00
2021-02-24 13:22:28 +00:00
def arq_transmit(data_out, mode, n_frames_per_burst):
2021-09-26 15:51:11 +00:00
global RPT_REQUEST_BUFFER
global DATA_FRAME_ACK_RECEIVED
global RPT_REQUEST_RECEIVED
global BURST_ACK_RECEIVED
#global TX_START_OF_TRANSMISSION
global DATA_CHANNEL_READY_FOR_DATA
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_MODE = mode
DATA_FRAME_BOF = b'\xAA\xAA' # 2 bytes for the BOF End of File indicator in a data frame
DATA_FRAME_EOF = b'\xFF\xFF' # 2 bytes for the EOF End of File indicator in a data frame
TX_N_SENT_FRAMES = 0 # already sent frames per data frame
TX_N_RETRIES_PER_BURST = 0 # retries we already sent data
TX_N_MAX_RETRIES_PER_BURST = 5 # max amount of retries we sent before frame is lost
TX_N_FRAMES_PER_BURST = n_frames_per_burst # amount of n frames per burst
TX_BUFFER = [] # our buffer for appending new data
2021-09-26 15:51:11 +00:00
2021-11-07 19:31:26 +00:00
# TIMEOUTS
BURST_ACK_TIMEOUT_SECONDS = 10.0 # timeout for burst acknowledges
DATA_FRAME_ACK_TIMEOUT_SECONDS = 10.0 # timeout for data frame acknowledges
RPT_ACK_TIMEOUT_SECONDS = 10.0 # timeout for rpt frame acknowledges
2021-03-12 13:14:36 +00:00
# we need to set payload per frame manually at this point. maybe we can do this more dynmic.
2021-09-26 15:51:11 +00:00
if DATA_CHANNEL_MODE == 10:
2021-03-12 13:14:36 +00:00
payload_per_frame = 512 - 2
2021-09-26 15:51:11 +00:00
#elif DATA_CHANNEL_MODE == 11:
# payload_per_frame = 258 - 2
elif DATA_CHANNEL_MODE == 12:
2021-03-12 13:14:36 +00:00
payload_per_frame = 128 - 2
2021-09-26 15:51:11 +00:00
elif DATA_CHANNEL_MODE == 14:
2021-03-12 13:14:36 +00:00
payload_per_frame = 16 - 2
else:
payload_per_frame = 16 - 2
2021-09-26 15:51:11 +00:00
TX_START_OF_TRANSMISSION = time.time()
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
TX_PAYLOAD_PER_ARQ_FRAME = payload_per_frame - 8
frame_header_length = 6
2021-03-12 13:14:36 +00:00
#n_arq_frames_per_data_frame = (len(data_out) + frame_header_length) // TX_PAYLOAD_PER_ARQ_FRAME + ((len(data_out) + frame_header_length) % TX_PAYLOAD_PER_ARQ_FRAME > 0)
2021-03-12 13:14:36 +00:00
frame_payload_crc = helpers.get_crc_16(data_out)
# This is the total frame with frame header, which will be send
2021-09-26 15:51:11 +00:00
data_out = frame_payload_crc + DATA_FRAME_BOF + data_out + DATA_FRAME_EOF
2021-03-12 13:14:36 +00:00
# 2 2 N 2
2021-09-11 07:21:22 +00:00
# save len of data_out to TOTAL_BYTES for our statistics
static.TOTAL_BYTES = len(data_out)
2021-03-12 13:14:36 +00:00
# --------------------------------------------- LETS CREATE A BUFFER BY SPLITTING THE FILES INTO PEACES
# https://newbedev.com/how-to-split-a-byte-string-into-separate-bytes-in-python
TX_BUFFER = [data_out[i:i + TX_PAYLOAD_PER_ARQ_FRAME] for i in range(0, len(data_out), TX_PAYLOAD_PER_ARQ_FRAME)]
TX_BUFFER_SIZE = len(TX_BUFFER)
static.INFO.append("ARQ;TRANSMITTING")
2021-03-12 13:14:36 +00:00
structlog.get_logger("structlog").info("[TNC] DATACHANNEL", mode=DATA_CHANNEL_MODE, bytes=len(data_out), frames=TX_BUFFER_SIZE)
2021-11-18 18:40:22 +00:00
2021-09-26 15:51:11 +00:00
# ----------------------- THIS IS THE MAIN LOOP-----------------------------------------------------------------
TX_N_SENT_FRAMES = 0 # SET N SENT FRAMES TO 0 FOR A NEW SENDING CYCLE
while TX_N_SENT_FRAMES <= TX_BUFFER_SIZE and static.ARQ_STATE == 'DATA':
2021-03-12 13:14:36 +00:00
# ----------- CREATE FRAME TOTAL PAYLOAD TO BE ABLE TO CREATE CRC FOR IT
try: # DETECT IF LAST BURST TO PREVENT INDEX ERROR OF BUFFER
for i in range(TX_N_FRAMES_PER_BURST): # Loop through TX_BUFFER LIST
len(TX_BUFFER[TX_N_SENT_FRAMES + i]) # we calculate the length to trigger a list index error
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
except IndexError: # IF LAST BURST DETECTED BUILD CRC WITH LESS FRAMES AND SET TX_N_FRAMES_PER_BURST TO VALUE OF REST!
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
if TX_N_SENT_FRAMES == 0 and (TX_N_FRAMES_PER_BURST > TX_BUFFER_SIZE): # WE CANT DO MODULO 0 > CHECK IF FIRST FRAME == LAST FRAME
TX_N_FRAMES_PER_BURST = TX_BUFFER_SIZE
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
elif TX_N_SENT_FRAMES == 1 and (TX_N_FRAMES_PER_BURST > TX_BUFFER_SIZE): # MODULO 1 WILL ALWAYS BE 0 --> THIS FIXES IT
TX_N_FRAMES_PER_BURST = TX_BUFFER_SIZE - TX_N_SENT_FRAMES
2021-03-12 13:14:36 +00:00
2021-02-28 14:24:14 +00:00
else:
2021-09-26 15:51:11 +00:00
TX_N_FRAMES_PER_BURST = (TX_BUFFER_SIZE % TX_N_SENT_FRAMES)
2021-03-12 13:14:36 +00:00
# --------------------------------------------- N ATTEMPTS TO SEND BURSTS IF ACK RECEPTION FAILS
2021-09-26 15:51:11 +00:00
for TX_N_RETRIES_PER_BURST in range(TX_N_MAX_RETRIES_PER_BURST):
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
if TX_N_SENT_FRAMES + 1 <= TX_BUFFER_SIZE:
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
frame_progress = str(TX_N_SENT_FRAMES + 1) + "-" + str(TX_N_SENT_FRAMES + TX_N_FRAMES_PER_BURST)
total_frame_progress = str(TX_N_SENT_FRAMES) + "/" + str(TX_BUFFER_SIZE)
transmission_percent = str(static.ARQ_TRANSMISSION_PERCENT).zfill(3)
transmission_attempts = str(TX_N_RETRIES_PER_BURST + 1) + "/" + str(TX_N_MAX_RETRIES_PER_BURST)
structlog.get_logger("structlog").info("[TNC] ARQ | TX | DATA", mode=DATA_CHANNEL_MODE, frames=frame_progress, percent=transmission_percent, frames_total=total_frame_progress, attempt=transmission_attempts)
2021-03-12 13:14:36 +00:00
# lets refresh all timers and ack states before sending a new frame
2021-09-26 15:51:11 +00:00
arq_reset_ack(False)
2021-09-26 15:51:11 +00:00
# ---------------------------BUILD ARQ BURST ---------------------------------------------------------------------
tempbuffer = []
# we need to optimize this and doing frame building like the other frames with explicit possition
# instead of just appending byte data
2021-09-26 15:51:11 +00:00
for n in range(0, TX_N_FRAMES_PER_BURST):
frame_type = 10 + n + 1
frame_type = bytes([frame_type])
payload_data = bytes(TX_BUFFER[TX_N_SENT_FRAMES + n])
2021-09-26 15:51:11 +00:00
n_current_arq_frame = TX_N_SENT_FRAMES + n + 1
n_current_arq_frame = n_current_arq_frame.to_bytes(2, byteorder='big')
n_total_arq_frame = len(TX_BUFFER)
2021-09-26 15:51:11 +00:00
#static.ARQ_TX_N_TOTAL_ARQ_FRAMES = n_total_arq_frame
arqframe = frame_type + \
bytes([TX_N_FRAMES_PER_BURST]) + \
n_current_arq_frame + \
n_total_arq_frame.to_bytes(2, byteorder='big') + \
static.DXCALLSIGN_CRC8 + \
static.MYCALLSIGN_CRC8 + \
payload_data
2021-09-26 15:51:11 +00:00
tempbuffer.append(arqframe)
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
#while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, tempbuffer):
# time.sleep(0.01)
## lets wait during sending. After sending is finished we will continue
#while static.CHANNEL_STATE == 'SENDING_DATA':
# time.sleep(0.01)
2021-03-12 13:14:36 +00:00
# --------------------------- START TIMER FOR WAITING FOR ACK ---> IF TIMEOUT REACHED, ACK_TIMEOUT = 1
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | WAITING FOR BURST ACK")
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
burstacktimeout = time.time() + BURST_ACK_TIMEOUT_SECONDS
# --------------------------- WHILE TIMEOUT NOT REACHED AND NO ACK RECEIVED AND IN ARQ STATE--> LISTEN
while not BURST_ACK_RECEIVED and not RPT_REQUEST_RECEIVED and not DATA_FRAME_ACK_RECEIVED and time.time() < burstacktimeout and static.ARQ_STATE == 'DATA':
2021-03-12 13:14:36 +00:00
time.sleep(0.01) # lets reduce CPU load a little bit
logging.debug("WAITING FOR BURST ACK..")
2021-03-12 13:14:36 +00:00
# HERE WE PROCESS DATA IF WE RECEIVED ACK/RPT FRAMES OR NOT WHILE WE ARE IN ARQ STATE
# IF WE ARE NOT IN ARQ STATE, WE STOPPED THE TRANSMISSION
if RPT_REQUEST_RECEIVED and static.ARQ_STATE == 'DATA':
2021-09-26 15:51:11 +00:00
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | REQUEST FOR REPEATING FRAMES: ",buffer=RPT_REQUEST_BUFFER)
2021-11-18 18:40:22 +00:00
structlog.get_logger("structlog").debug("[TNC] ARQ | TX | SENDING REQUESTED FRAMES: ",buffer=RPT_REQUEST_BUFFER)
2021-09-26 15:51:11 +00:00
# --------- BUILD RPT FRAME --------------
tempbuffer = []
for n in range(0, len(RPT_REQUEST_BUFFER)):
# we need to optimize this and doing frame building like the other frames with explicit possition
# instead of just appending byte data
2021-09-26 15:51:11 +00:00
missing_frame = int.from_bytes(RPT_REQUEST_BUFFER[n], "big")
frame_type = 10 + missing_frame # static.ARQ_TX_N_FRAMES_PER_BURST
frame_type = bytes([frame_type])
try:
payload_data = bytes(TX_BUFFER[TX_N_SENT_FRAMES + missing_frame - 1])
2021-09-26 15:51:11 +00:00
except:
2021-11-18 18:40:22 +00:00
structlog.get_logger("structlog").warning("[TNC] ARQ :modem buffer selection problem with ARQ RPT frames")
2021-09-26 15:51:11 +00:00
n_current_arq_frame = TX_N_SENT_FRAMES + missing_frame
n_current_arq_frame = n_current_arq_frame.to_bytes(2, byteorder='big')
2021-03-12 13:14:36 +00:00
n_total_arq_frame = len(TX_BUFFER)
2021-09-26 15:51:11 +00:00
arqframe = frame_type + \
bytes([TX_N_FRAMES_PER_BURST]) + \
n_current_arq_frame + \
n_total_arq_frame.to_bytes(2, byteorder='big') + \
static.DXCALLSIGN_CRC8 + \
static.MYCALLSIGN_CRC8 + \
payload_data
tempbuffer.append(arqframe)
modem.transmit(mode=DATA_CHANNEL_MODE, repeats=1, repeat_delay=0, frames=tempbuffer)
#while not modem.transmit_arq_burst(DATA_CHANNEL_MODE, tempbuffer):
# time.sleep(0.01)
2021-09-26 15:51:11 +00:00
2021-03-12 13:14:36 +00:00
# lets wait during sending. After sending is finished we will continue
#while static.ARQ_STATE == 'SENDING_DATA':
# time.sleep(0.01)
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
arq_reset_ack(False)
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
rpttimeout = time.time() + RPT_ACK_TIMEOUT_SECONDS
2021-03-12 13:14:36 +00:00
while not BURST_ACK_RECEIVED and not DATA_FRAME_ACK_RECEIVED and static.ARQ_STATE == 'DATA' and time.time() < rpttimeout:
2021-03-12 13:14:36 +00:00
time.sleep(0.01) # lets reduce CPU load a little bit
2021-09-26 15:51:11 +00:00
if BURST_ACK_RECEIVED:
2021-11-18 18:40:22 +00:00
structlog.get_logger("structlog").info("[TNC] ARQ : ACK after repeat")
2021-09-26 15:51:11 +00:00
arq_reset_ack(True)
RPT_REQUEST_BUFFER = []
TX_N_SENT_FRAMES = TX_N_SENT_FRAMES + TX_N_FRAMES_PER_BURST
2021-03-12 13:14:36 +00:00
if time.time() > rpttimeout and not BURST_ACK_RECEIVED:
2021-11-18 18:40:22 +00:00
structlog.get_logger("structlog").warning("[TNC] ARQ : Burst lost...")
2021-09-26 15:51:11 +00:00
arq_reset_ack(False)
RPT_REQUEST_BUFFER = []
# the order of ACK check is important! speciall the FRAME ACK after RPT needs to be checked really early!
2021-03-19 11:06:12 +00:00
# --------------- BREAK LOOP IF FRAME ACK HAS BEEN RECEIVED EARLIER AS EXPECTED
elif DATA_FRAME_ACK_RECEIVED and static.ARQ_STATE == 'DATA':
2021-03-19 11:06:12 +00:00
logging.info("ARQ | RX | EARLY FRAME ACK RECEIVED #2")
2021-09-26 15:51:11 +00:00
TX_N_SENT_FRAMES = TX_N_SENT_FRAMES + TX_N_FRAMES_PER_BURST
2021-03-19 11:06:12 +00:00
break
2021-03-12 13:14:36 +00:00
# --------------------------------------------------------------------------------------------------------------
elif not BURST_ACK_RECEIVED and static.ARQ_STATE == 'DATA':
2021-03-12 13:14:36 +00:00
logging.warning("ARQ | RX | ACK TIMEOUT!")
pass # no break here so we can continue with the next try of repeating the burst
2021-03-19 11:06:12 +00:00
2021-03-12 13:14:36 +00:00
# --------------- BREAK LOOP IF ACK HAS BEEN RECEIVED
elif BURST_ACK_RECEIVED and static.ARQ_STATE == 'DATA':
2021-03-12 13:14:36 +00:00
# -----------IF ACK RECEIVED, INCREMENT ITERATOR FOR MAIN LOOP TO PROCEED WITH NEXT FRAMES/BURST
2021-09-26 15:51:11 +00:00
TX_N_SENT_FRAMES = TX_N_SENT_FRAMES + TX_N_FRAMES_PER_BURST
# SET TX ATTEMPTS BACK TO 0
TX_N_RETRIES_PER_BURST = 0
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
logging.info("ARQ | RX | ACK [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
# lets wait a little bit before we are processing the next frame
helpers.wait(0.3)
2021-03-19 11:06:12 +00:00
2021-09-26 15:51:11 +00:00
break
2021-03-12 13:14:36 +00:00
else:
logging.info("--->NO RULE MATCHED OR TRANSMISSION STOPPED!")
2021-09-26 15:51:11 +00:00
print("ARQ_ACK_RECEIVED " + str(BURST_ACK_RECEIVED))
print(f"TX_N_SENT_FRAMES: {TX_N_SENT_FRAMES}")
print(f"TX_BUFFER_SIZE: {TX_BUFFER_SIZE}")
print(f"DATA_FRAME_ACK_RECEIVED: {DATA_FRAME_ACK_RECEIVED}")
2021-03-12 13:14:36 +00:00
break
2021-09-26 15:51:11 +00:00
2021-03-12 13:14:36 +00:00
# --------------------------------WAITING AREA FOR FRAME ACKs
#static.CHANNEL_STATE = 'RECEIVING_SIGNALLING'
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
frameacktimeout = time.time() + DATA_FRAME_ACK_TIMEOUT_SECONDS
2021-03-12 13:14:36 +00:00
# wait for frame ACK if we processed the last frame/burst
print(f"TX_N_SENT_FRAMES: {TX_N_SENT_FRAMES}")
print(f"TX_BUFFER_SIZE: {TX_BUFFER_SIZE}")
print(f"DATA_FRAME_ACK_RECEIVED: {DATA_FRAME_ACK_RECEIVED}")
print(f"{time.time()} {frameacktimeout}")
2021-09-26 15:51:11 +00:00
while not DATA_FRAME_ACK_RECEIVED and time.time() < frameacktimeout and TX_N_SENT_FRAMES == TX_BUFFER_SIZE:
print("kommen wir hier überhaupt an?!?!?!?!?")
2021-03-12 13:14:36 +00:00
time.sleep(0.01) # lets reduce CPU load a little bit
logging.debug("WAITING FOR FRAME ACK")
# ----------- if no ACK received and out of retries.....stop frame sending
2021-09-26 15:51:11 +00:00
if not BURST_ACK_RECEIVED and not DATA_FRAME_ACK_RECEIVED:
2021-03-12 13:14:36 +00:00
logging.error("ARQ | TX | NO ACK RECEIVED | DATA SHOULD BE RESEND!")
static.INFO.append("ARQ;TRANSMITTING;FAILED")
2021-03-12 13:14:36 +00:00
break
# -------------------------BREAK TX BUFFER LOOP IF ALL PACKETS HAVE BEEN SENT AND WE GOT A FRAME ACK
2021-09-26 15:51:11 +00:00
elif TX_N_SENT_FRAMES == TX_BUFFER_SIZE and DATA_FRAME_ACK_RECEIVED:
print(TX_N_SENT_FRAMES)
calculate_transfer_rate_tx(TX_N_SENT_FRAMES, TX_PAYLOAD_PER_ARQ_FRAME, TX_START_OF_TRANSMISSION, TX_BUFFER_SIZE)
static.INFO.append("ARQ;TRANSMITTING;SUCCESS")
logging.log(25, "ARQ | RX | FRAME ACK! - DATA TRANSMITTED! [" + str(static.ARQ_BITS_PER_SECOND) + " bit/s | " + str(static.ARQ_BYTES_PER_MINUTE) + " B/min]")
2021-03-12 13:14:36 +00:00
break
2021-09-26 15:51:11 +00:00
elif not DATA_FRAME_ACK_RECEIVED and time.time() > frameacktimeout:
2021-03-12 13:14:36 +00:00
logging.error("ARQ | TX | NO FRAME ACK RECEIVED")
break
else:
logging.debug("NO MATCHING RULE AT THE END")
# IF TX BUFFER IS EMPTY / ALL FRAMES HAVE BEEN SENT --> HERE WE COULD ADD AN static.VAR for IDLE STATE
2021-09-26 15:51:11 +00:00
#transfer_rates = calculate_transfer_rate()
2021-08-15 10:39:06 +00:00
#logging.info("RATE (DATA/ACK) :[" + str(transfer_rates[0]) + " bit/s | " + str(transfer_rates[1]) + " B/min]")
2021-03-12 13:14:36 +00:00
logging.info("ARQ | TX | BUFFER EMPTY")
# we are doing some cleanup here
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = 'IDLE'
DATA_CHANNEL_READY_FOR_DATA = False
#DATA_CHANNEL_LAST_RECEIVED = 0
#BURST_ACK_RECEIVED = False
#DATA_FRAME_ACK_RECEIVED = False
2021-05-09 15:55:15 +00:00
logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<< >>[" + str(static.DXCALLSIGN, 'utf-8') + "] [SNR:" + str(static.SNR) + "]")
2021-03-12 13:14:36 +00:00
# this should close our thread so we are saving memory...
# https://stackoverflow.com/questions/905189/why-does-sys-exit-not-exit-when-called-inside-a-thread-in-python
sys.exit()
2021-03-17 10:22:06 +00:00
2021-02-24 13:22:28 +00:00
def burst_ack_received():
2021-09-26 15:51:11 +00:00
global BURST_ACK_RECEIVED
global DATA_CHANNEL_LAST_RECEIVED
# only process data if we are in ARQ and BUSY state
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY':
BURST_ACK_RECEIVED = True # Force data loops of TNC to stop and continue with next frame
DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # we need to update our timeout timestamp
2021-02-24 13:22:28 +00:00
def frame_ack_received():
2021-09-26 15:51:11 +00:00
global DATA_FRAME_ACK_RECEIVED
global DATA_CHANNEL_LAST_RECEIVED
# only process data if we are in ARQ and BUSY state
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY':
DATA_FRAME_ACK_RECEIVED = True # Force data loops of TNC to stop and continue with next frame
DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # we need to update our timeout timestamp
2021-03-12 13:14:36 +00:00
2021-02-24 13:22:28 +00:00
def burst_rpt_received(data_in):
2021-09-26 15:51:11 +00:00
global RPT_REQUEST_RECEIVED
global RPT_REQUEST_BUFFER
global DATA_CHANNEL_LAST_RECEIVED
# only process data if we are in ARQ and BUSY state
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY':
RPT_REQUEST_RECEIVED = True
DATA_CHANNEL_LAST_RECEIVED = int(time.time()) # we need to update our timeout timestamp
RPT_REQUEST_BUFFER = []
2021-03-12 13:14:36 +00:00
missing_area = bytes(data_in[3:12]) # 1:9
2021-03-12 13:14:36 +00:00
for i in range(0, 6, 2):
if not missing_area[i:i + 2].endswith(b'\x00\x00'):
missing = missing_area[i:i + 2]
RPT_REQUEST_BUFFER.insert(0, missing)
2021-03-12 13:14:36 +00:00
# ############################################################################################################
2021-02-28 14:24:14 +00:00
# ARQ DATA CHANNEL HANDLER
2021-03-12 13:14:36 +00:00
# ############################################################################################################
2021-02-28 14:24:14 +00:00
2021-09-26 15:51:11 +00:00
def open_dc_and_transmit(data_out, mode, n_frames_per_burst):
global DATA_CHANNEL_READY_FOR_DATA
asyncio.run(arq_open_data_channel(mode))
# wait until data channel is open
2021-09-26 15:51:11 +00:00
while not DATA_CHANNEL_READY_FOR_DATA:
time.sleep(0.01)
2021-07-10 21:56:12 +00:00
# lets wait a little bit so RX station is ready for receiving
#wait_before_data_timer = time.time() + 0.8
#while time.time() < wait_before_data_timer:
# pass
helpers.wait(0.8)
2021-04-17 15:42:25 +00:00
# transmit data
arq_transmit(data_out, mode, n_frames_per_burst)
2021-03-19 10:16:24 +00:00
2021-02-28 14:24:14 +00:00
2021-03-19 10:16:24 +00:00
async def arq_open_data_channel(mode):
global DATA_CHANNEL_READY_FOR_DATA
2021-09-26 15:51:11 +00:00
global DATA_CHANNEL_LAST_RECEIVED
2021-03-19 10:16:24 +00:00
DATA_CHANNEL_MAX_RETRIES = 5 # N attempts for connecting to another station
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_MODE = int(mode)
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
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[3:9] = static.MYCALLSIGN
connection_frame[12:13] = bytes([DATA_CHANNEL_MODE])
2021-11-19 16:47:25 +00:00
2021-09-26 15:51:11 +00:00
while not DATA_CHANNEL_READY_FOR_DATA:
time.sleep(0.01)
for attempt in range(1,DATA_CHANNEL_MAX_RETRIES+1):
static.INFO.append("DATACHANNEL;OPENING")
2021-11-19 16:47:25 +00:00
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]", attempt=str(attempt) + "/" + str(DATA_CHANNEL_MAX_RETRIES))
txbuffer = [connection_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
timeout = time.time() + 3
while time.time() < timeout:
time.sleep(0.01)
# break if data channel is openend
2021-09-26 15:51:11 +00:00
if DATA_CHANNEL_READY_FOR_DATA:
break
2021-09-26 15:51:11 +00:00
if DATA_CHANNEL_READY_FOR_DATA:
2021-03-18 14:29:51 +00:00
break
2021-11-19 16:47:25 +00:00
if not DATA_CHANNEL_READY_FOR_DATA and attempt == DATA_CHANNEL_MAX_RETRIES:
static.INFO.append("DATACHANNEL;FAILED")
structlog.get_logger("structlog").warning("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>X<<[" + str(static.DXCALLSIGN, 'utf-8') + "]")
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = 'IDLE'
sys.exit() # close thread and so connection attempts
2021-03-12 13:14:36 +00:00
2021-02-28 14:24:14 +00:00
def arq_received_data_channel_opener(data_in):
2021-09-26 15:51:11 +00:00
#global DATA_CHANNEL_MODE
2021-09-26 15:51:11 +00:00
global DATA_CHANNEL_LAST_RECEIVED
static.INFO.append("DATACHANNEL;RECEIVEDOPENER")
static.DXCALLSIGN_CRC8 = bytes(data_in[2:3]).rstrip(b'\x00')
static.DXCALLSIGN = bytes(data_in[3:9]).rstrip(b'\x00')
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'DATA-CHANNEL', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
2021-03-16 14:21:58 +00:00
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>> <<[" + str(static.DXCALLSIGN, 'utf-8') + "]")
static.ARQ_STATE = 'DATA'
static.TNC_STATE = 'BUSY'
2021-05-09 15:55:15 +00:00
mode = int.from_bytes(bytes(data_in[12:13]), "big")
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
2021-02-28 14:24:14 +00:00
connection_frame = bytearray(14)
connection_frame[:1] = bytes([226])
connection_frame[1:2] = static.DXCALLSIGN_CRC8
connection_frame[2:3] = static.MYCALLSIGN_CRC8
2021-03-16 14:21:58 +00:00
connection_frame[3:9] = static.MYCALLSIGN
connection_frame[12:13] = bytes([mode])
txbuffer = [connection_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
2021-12-25 16:05:38 +00:00
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, mode=mode)
#static.CHANNEL_STATE = 'RECEIVING_DATA'
# and now we are going to "RECEIVING_DATA" mode....
2021-03-12 13:14:36 +00:00
2021-02-28 14:24:14 +00:00
def arq_received_channel_is_open(data_in):
2021-03-16 14:21:58 +00:00
2021-09-26 15:51:11 +00:00
global DATA_CHANNEL_LAST_RECEIVED
global DATA_CHANNEL_READY_FOR_DATA
global DATA_CHANNEL_MODE
2021-09-26 15:51:11 +00:00
static.INFO.append("DATACHANNEL;OPEN")
2021-03-16 14:21:58 +00:00
static.DXCALLSIGN_CRC8 = bytes(data_in[2:3]).rstrip(b'\x00')
static.DXCALLSIGN = bytes(data_in[3:9]).rstrip(b'\x00')
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'DATA-CHANNEL', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
2021-03-16 14:21:58 +00:00
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
2021-03-12 13:14:36 +00:00
# we are doing a mode check here, but this doesn't seem to be necessary since we have simultaneous decoding
# we are forcing doing a transmission at the moment --> see else statement
2021-09-26 15:51:11 +00:00
if DATA_CHANNEL_MODE == int.from_bytes(bytes(data_in[12:13]), "big"):
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR)
# wait a little bit so other station is ready ( PTT toggle )
print("wait.....")
print(time.time())
helpers.wait(0.5)
print(time.time())
# as soon as we set ARQ_STATE to DATA, transmission starts
static.ARQ_STATE = 'DATA'
2021-09-26 15:51:11 +00:00
DATA_CHANNEL_READY_FOR_DATA = True
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
else:
structlog.get_logger("structlog").info("[TNC] DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]>>|<<[" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR, info="wrong mode rcvd")
helpers.wait(0.5)
# as soon as we set ARQ_STATE to DATA, transmission starts
static.ARQ_STATE = 'DATA'
DATA_CHANNEL_READY_FOR_DATA = True
DATA_CHANNEL_LAST_RECEIVED = int(time.time())
2021-02-28 14:24:14 +00:00
2021-03-12 13:14:36 +00:00
# ############################################################################################################
2021-02-24 15:47:52 +00:00
# PING HANDLER
2021-03-12 13:14:36 +00:00
# ############################################################################################################
def transmit_ping(callsign):
2021-03-11 19:04:31 +00:00
static.DXCALLSIGN = bytes(callsign, 'utf-8').rstrip(b'\x00')
2021-03-09 10:05:59 +00:00
static.DXCALLSIGN_CRC8 = helpers.get_crc_8(static.DXCALLSIGN)
static.INFO.append("PING;SENDING")
structlog.get_logger("structlog").info("[TNC] PING REQ [" + str(static.MYCALLSIGN, 'utf-8') + "] >>> [" + str(static.DXCALLSIGN, 'utf-8') + "]" )
2021-03-12 13:14:36 +00:00
2021-09-26 15:51:11 +00:00
ping_frame = bytearray(14)
ping_frame[:1] = bytes([210])
2021-03-07 15:41:02 +00:00
ping_frame[1:2] = static.DXCALLSIGN_CRC8
ping_frame[2:3] = static.MYCALLSIGN_CRC8
ping_frame[3:9] = static.MYCALLSIGN
2021-02-24 13:22:28 +00:00
txbuffer = [ping_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
2021-03-12 13:14:36 +00:00
def received_ping(data_in, frequency_offset):
2021-02-28 14:24:14 +00:00
2021-03-11 19:04:31 +00:00
static.DXCALLSIGN_CRC8 = bytes(data_in[2:3]).rstrip(b'\x00')
static.DXCALLSIGN = bytes(data_in[3:9]).rstrip(b'\x00')
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'PING', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
static.INFO.append("PING;RECEIVING")
structlog.get_logger("structlog").info("[TNC] PING REQ [" + str(static.MYCALLSIGN, 'utf-8') + "] <<< [" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR )
2021-03-07 15:41:02 +00:00
2021-09-26 15:51:11 +00:00
ping_frame = bytearray(14)
ping_frame[:1] = bytes([211])
2021-03-07 15:41:02 +00:00
ping_frame[1:2] = static.DXCALLSIGN_CRC8
ping_frame[2:3] = static.MYCALLSIGN_CRC8
2021-05-13 19:02:14 +00:00
ping_frame[3:9] = static.MYGRID
ping_frame[9:11] = frequency_offset.to_bytes(2, byteorder='big', signed=True)
txbuffer = [ping_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
2021-03-12 13:14:36 +00:00
2021-02-24 13:22:28 +00:00
def received_ping_ack(data_in):
2021-03-07 15:41:02 +00:00
2021-03-11 19:04:31 +00:00
static.DXCALLSIGN_CRC8 = bytes(data_in[2:3]).rstrip(b'\x00')
2021-05-13 19:02:14 +00:00
static.DXGRID = bytes(data_in[3:9]).rstrip(b'\x00')
2021-09-26 15:51:11 +00:00
helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'PING-ACK', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
2021-05-13 19:02:14 +00:00
static.INFO.append("PING;RECEIVEDACK")
structlog.get_logger("structlog").info("[TNC] PING ACK [" + str(static.MYCALLSIGN, 'utf-8') + "] >|< [" + str(static.DXCALLSIGN, 'utf-8') + "]", snr=static.SNR )
2021-02-24 15:47:52 +00:00
static.TNC_STATE = 'IDLE'
2021-03-12 13:14:36 +00:00
# ############################################################################################################
2021-02-24 15:47:52 +00:00
# BROADCAST HANDLER
2021-03-12 13:14:36 +00:00
# ############################################################################################################
def run_beacon(interval):
try:
structlog.get_logger("structlog").warning("[TNC] Starting beacon!", interval=interval)
while static.BEACON_STATE and static.ARQ_STATE == 'IDLE':
beacon_frame = bytearray(14)
beacon_frame[:1] = bytes([230])
beacon_frame[1:2] = b'\x01'
beacon_frame[2:8] = static.MYCALLSIGN
beacon_frame[8:14] = static.MYGRID
static.INFO.append("BEACON;SENDING")
structlog.get_logger("structlog").info("[TNC] Sending beacon!", interval=interval)
txbuffer = [beacon_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=0, frames=txbuffer)
time.sleep(interval)
except Exception as e:
print(e)
def received_beacon(data_in):
# here we add the received station to the heard stations buffer
dxcallsign = bytes(data_in[2:8]).rstrip(b'\x00')
dxgrid = bytes(data_in[8:14]).rstrip(b'\x00')
static.INFO.append("BEACON;RECEIVING")
structlog.get_logger("structlog").info("[TNC] BEACON RCVD [" + str(dxcallsign, 'utf-8') + "]["+ str(dxgrid, 'utf-8') +"] ", snr=static.SNR)
helpers.add_to_heard_stations(dxcallsign,dxgrid, 'BEACON', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
def transmit_cq():
2021-02-24 13:22:28 +00:00
logging.info("CQ CQ CQ")
static.INFO.append("CQ;SENDING")
2021-09-26 15:51:11 +00:00
cq_frame = bytearray(14)
cq_frame[:1] = bytes([200])
cq_frame[1:2] = b'\x01'
2021-05-13 16:50:56 +00:00
#cq_frame[2:3] = static.MYCALLSIGN_CRC8
#cq_frame[3:9] = static.MYCALLSIGN
2021-09-26 15:51:11 +00:00
cq_frame[2:8] = static.MYCALLSIGN
2021-05-13 16:50:56 +00:00
cq_frame[8:14] = static.MYGRID
2021-05-09 15:55:15 +00:00
txbuffer = [cq_frame]
modem.transmit(mode=14, repeats=1, repeat_delay=1000, frames=txbuffer)
#while not modem.transmit(14, 1, txbuffer):
# pass
2021-09-26 15:51:11 +00:00
2021-03-12 13:14:36 +00:00
2021-03-09 09:00:20 +00:00
def received_cq(data_in):
2021-03-12 13:14:36 +00:00
# here we add the received station to the heard stations buffer
2021-05-13 16:50:56 +00:00
dxcallsign = bytes(data_in[2:8]).rstrip(b'\x00')
dxgrid = bytes(data_in[8:14]).rstrip(b'\x00')
static.INFO.append("CQ;RECEIVING")
structlog.get_logger("structlog").info("[TNC] CQ RCVD [" + str(dxcallsign, 'utf-8') + "]["+ str(dxgrid, 'utf-8') +"] ", snr=static.SNR)
helpers.add_to_heard_stations(dxcallsign,dxgrid, 'CQ CQ CQ', static.SNR, static.FREQ_OFFSET, static.HAMLIB_FREQUENCY)
2021-03-16 14:21:58 +00:00
2021-09-26 15:51:11 +00:00
def arq_reset_ack(state):
"""
Author: DJ2LS
"""
global BURST_ACK_RECEIVED
global RPT_REQUEST_RECEIVED
global DATA_FRAME_ACK_RECEIVED
BURST_ACK_RECEIVED = state
RPT_REQUEST_RECEIVED = state
DATA_FRAME_ACK_RECEIVED = state
2021-03-12 13:14:36 +00:00
def calculate_transfer_rate_rx(rx_n_frames_per_data_frame, rx_n_frame_of_data_frame, rx_start_of_transmission, rx_payload_per_arq_frame):
try:
static.ARQ_TRANSMISSION_PERCENT = int((rx_n_frame_of_data_frame / rx_n_frames_per_data_frame) * 100)
transmissiontime = time.time() - rx_start_of_transmission
receivedbytes = rx_n_frame_of_data_frame * (rx_payload_per_arq_frame-6) # 6 = length of ARQ header
static.ARQ_BITS_PER_SECOND = int((receivedbytes*8) / transmissiontime)
static.ARQ_BYTES_PER_MINUTE = int((receivedbytes) / (transmissiontime/60))
2021-09-26 15:51:11 +00:00
except:
static.ARQ_TRANSMISSION_PERCENT = 0.0
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
2021-09-26 15:51:11 +00:00
return [static.ARQ_BITS_PER_SECOND, \
static.ARQ_BYTES_PER_MINUTE, \
static.ARQ_TRANSMISSION_PERCENT]
2021-09-26 15:51:11 +00:00
def calculate_transfer_rate_tx(tx_n_sent_frames, tx_payload_per_arq_frame, tx_start_of_transmission, tx_buffer_length):
try:
static.ARQ_TRANSMISSION_PERCENT = int((tx_n_sent_frames / tx_buffer_length) * 100)
2021-09-26 15:51:11 +00:00
transmissiontime = time.time() - tx_start_of_transmission
if tx_n_sent_frames > 0:
sendbytes = tx_n_sent_frames * (tx_payload_per_arq_frame-6) #6 = length of ARQ header
2021-09-26 15:51:11 +00:00
static.ARQ_BITS_PER_SECOND = int((sendbytes*8) / transmissiontime)
2021-09-26 15:51:11 +00:00
static.ARQ_BYTES_PER_MINUTE = int((sendbytes) / (transmissiontime/60))
else:
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
except:
2021-09-26 15:51:11 +00:00
static.ARQ_TRANSMISSION_PERCENT = 0.0
static.ARQ_BITS_PER_SECOND = 0
static.ARQ_BYTES_PER_MINUTE = 0
return [static.ARQ_BITS_PER_SECOND, \
static.ARQ_BYTES_PER_MINUTE, \
static.ARQ_TRANSMISSION_PERCENT]
2021-09-26 15:51:11 +00:00
# WATCHDOG FUNCTIONS
def watchdog():
"""
Author: DJ2LS
watchdog master function. Frome here we call the watchdogs
"""
while True:
time.sleep(0.01)
data_channel_keep_alive_watchdog()
def data_channel_keep_alive_watchdog():
"""
Author: DJ2LS
"""
global DATA_CHANNEL_LAST_RECEIVED
# and not static.ARQ_SEND_KEEP_ALIVE:
if static.ARQ_STATE == 'DATA' and static.TNC_STATE == 'BUSY':
time.sleep(0.01)
if DATA_CHANNEL_LAST_RECEIVED + 30 > time.time():
time.sleep(0.01)
#pass
else:
DATA_CHANNEL_LAST_RECEIVED = 0
logging.info("DATA [" + str(static.MYCALLSIGN, 'utf-8') + "]<<T>>[" + str(static.DXCALLSIGN, 'utf-8') + "] [BER." + str(static.BER) + "]")
#arq_reset_frame_machine()
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = 'IDLE'
2021-09-26 15:51:11 +00:00
# START THE THREAD FOR THE TIMEOUT WATCHDOG
WATCHDOG_SERVER_THREAD = threading.Thread(target=watchdog, name="watchdog")
WATCHDOG_SERVER_THREAD.start()