From adfb9d3625b822efef7c6e36673aa5f5240ec17f Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Wed, 24 Feb 2021 14:16:29 +0100 Subject: [PATCH] switching to signalling mode as default necessary for mode gear shifting, ping, cq ... --- README.md | 95 +++++++-------------------------- arq.py | 94 +++++++++++++++++++++++++-------- hamlib.py | 132 ++++++++++++++++++++++++++++++++++++++++++++++ main.py | 7 +-- main.spec | 33 ++++++++++++ modem.py | 57 ++++++++++++++------ readfromsocket.py | 12 +++-- sock.py | 44 +++++++++++++++- static.py | 16 +++--- 9 files changed, 357 insertions(+), 133 deletions(-) create mode 100644 hamlib.py create mode 100644 main.spec diff --git a/README.md b/README.md index a52ca94d..f5e928c2 100644 --- a/README.md +++ b/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: ``` -"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: ``` -#### 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/ \ No newline at end of file diff --git a/arq.py b/arq.py index 9d9050bd..7cabca76 100644 --- a/arq.py +++ b/arq.py @@ -39,7 +39,7 @@ def data_received(data_in): 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 | 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) + "%]" ) @@ -81,11 +81,15 @@ def data_received(data_in): 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) + #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 = [] @@ -111,10 +115,10 @@ def data_received(data_in): #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) @@ -123,7 +127,7 @@ def data_received(data_in): 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 +139,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: @@ -167,9 +176,9 @@ 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.UNCODED_BER)+"]") - modem.transmit_arq_ack(ack_frame) + modem.transmit_signalling(ack_frame) # clearing buffers and resetting counters static.ARQ_RX_BURST_BUFFER = [] @@ -367,7 +376,7 @@ 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!") logging.error("------------------------------------------------------") break @@ -375,8 +384,11 @@ def transmit(data_out): 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 + break + + elif static.ARQ_FRAME_ACK_RECEIVED == False and static.ARQ_RX_FRAME_TIMEOUT == True: + logging.error("ARQ | TX | NO FRAME ACK RECEIVED") + break else: logging.debug("NO MATCHING RULE AT THE END") @@ -401,8 +413,8 @@ def transmit(data_out): # 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 = randrange(1,10) + #n_frames_per_burst = 1 return n_frames_per_burst @@ -428,3 +440,43 @@ def burst_rpt_received(data_in): missing = missing_area[i:i+2] static.ARQ_RPT_FRAMES.insert(0,missing) + + + +def transmit_ping(callsign): + static.DXCALLSIGN = bytes(callsign, 'utf-8') + logging.info("PING ["+ str(static.MYCALLSIGN, 'utf-8') + "] > ["+ callsign + "]") + + frame_type = bytes([2]) + ping_payload = b'PING' + + ping_frame = frame_type + ping_payload + + TRANSMIT_PING_THREAD = threading.Thread(target=modem.transmit_signalling, args=[ping_frame], name="TRANSMIT_ARQ") + TRANSMIT_PING_THREAD.start() + +def received_ping(data_in): + logging.info("TX PING ACK") + + frame_type = bytes([3]) + ping_payload = b'PING_ACK' + + ping_frame = frame_type + ping_payload + + TRANSMIT_PING_THREAD = threading.Thread(target=modem.transmit_signalling, args=[ping_frame], name="TRANSMIT_ARQ") + TRANSMIT_PING_THREAD.start() + + + +def received_ping_ack(data_in): + logging.info("PING ACK") + + +def transmit_cq(): + logging.info("CQ CQ CQ") + frame_type = bytes([1]) + print(frame_type) + cq_frame = frame_type + static.MYCALLSIGN + modem.transmit_signalling(cq_frame) + + diff --git a/hamlib.py b/hamlib.py new file mode 100644 index 00000000..224386a7 --- /dev/null +++ b/hamlib.py @@ -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() diff --git a/main.py b/main.py index c81c5dbe..cb09fe6c 100644 --- a/main.py +++ b/main.py @@ -16,12 +16,7 @@ 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__': diff --git a/main.spec b/main.spec new file mode 100644 index 00000000..919bb515 --- /dev/null +++ b/main.spec @@ -0,0 +1,33 @@ +# -*- mode: python ; coding: utf-8 -*- + +block_cipher = None + + +a = Analysis(['main.py'], + pathex=['/home/parallels/FreeDV-JATE'], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='main', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True ) diff --git a/modem.py b/modem.py index 890411a6..28bd2f54 100644 --- a/modem.py +++ b/modem.py @@ -93,9 +93,10 @@ 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' + static.ARQ_STATE = 'SENDING_SIGNALLING' static.PTT_STATE = True self.my_rig.set_ptt(self.hamlib_ptt_type,1) @@ -121,9 +122,6 @@ class RF(): 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_rawdatatx(freedv,mod_out,data) # modulate DATA and safe it into mod_out pointer txbuffer = bytearray() @@ -137,8 +135,9 @@ class RF(): self.my_rig.set_ptt(self.hamlib_ptt_type,0) static.PTT_STATE = False - - static.ARQ_STATE = 'RECEIVING_DATA' + + static.ARQ_STATE = 'RECEIVING_SIGNALLING' + #static.ARQ_STATE = 'RECEIVING_DATA' #-------------------------------------------------------------------------------------------------------- # GET ARQ BURST FRAME VOM BUFFER AND MODULATE IT def transmit_arq_burst(self): @@ -161,10 +160,7 @@ class RF(): 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)) - + txbuffer = bytearray() txbuffer += bytes(mod_out_preamble) @@ -246,8 +242,8 @@ class RF(): # -------------- transmit audio self.stream_tx.write(bytes(txbuffer)) - static.ARQ_STATE = 'IDLE' - #static.ARQ_STATE = 'RECEIVING_SIGNALLING' + #static.ARQ_STATE = 'IDLE' + static.ARQ_STATE = 'RECEIVING_SIGNALLING' static.PTT_STATE = False self.my_rig.set_ptt(self.hamlib_ptt_type,0) #-------------------------------------------------------------------------------------------------------- @@ -290,7 +286,6 @@ class RF(): 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)) @@ -313,8 +308,14 @@ class RF(): stuck_in_sync_counter = 0 stuck_in_sync_10_counter = 0 #----------------------------------- - - + + # get bit errors + Tbits = self.c_lib.freedv_get_total_bits(freedv_data) + Terrs = self.c_lib.freedv_get_total_bit_errors(freedv_data) + if Tbits != 0: + static.UNCODED_BER = Terrs/Tbits + + if nbytes == static.FREEDV_DATA_BYTES_PER_FRAME: rxstatus = self.c_lib.freedv_get_rx_status(freedv_data) logging.debug("DATA-" + str(rxstatus)) @@ -333,6 +334,7 @@ class RF(): 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 #print("static.ARQ_RX_BURST_BUFFER.count(None) " + str(static.ARQ_RX_BURST_BUFFER.count(None))) @@ -349,6 +351,12 @@ class RF(): # DO UNSYNC AFTER LAST BURST by checking the frame numbers agains the total frames per burst if frame == n_frames_per_burst: + + + #reset bit error counters + self.c_lib.freedv_set_total_bit_errors(freedv_data,0) + self.c_lib.freedv_set_total_bits(freedv_data,0) + logging.debug("LAST FRAME ---> UNSYNC") self.c_lib.freedv_set_sync(freedv_data, 0) #FORCE UNSYNC @@ -386,8 +394,23 @@ class RF(): logging.debug("REPEAT REQUEST RECEIVED....") arq.burst_rpt_received(signalling_bytes_out[:-2]) + # CQ FRAME + elif frametype == 1: + logging.info("CQ RECEIVED....") + + # PING FRAME + elif frametype == 2: + logging.debug("PING RECEIVED....") + arq.received_ping(signalling_bytes_out[:-2]) + + # PING ACK + elif frametype == 3: + logging.debug("PING ACK RECEIVED....") + arq.received_ping_ack(signalling_bytes_out[:-2]) + else: - logging.debug("OTHER FRAME: " + str(signalling_bytes_out[:-2])) + logging.info("OTHER FRAME: " + str(signalling_bytes_out[:-2])) + print(frametype) rxstatus = self.c_lib.freedv_get_rx_status(freedv_signalling) diff --git a/readfromsocket.py b/readfromsocket.py index ca8b525b..9b63a427 100644 --- a/readfromsocket.py +++ b/readfromsocket.py @@ -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 diff --git a/sock.py b/sock.py index 8ab8ce40..d2f54efa 100644 --- a/sock.py +++ b/sock.py @@ -14,21 +14,63 @@ import time import static import arq import helpers +import fec + 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 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) + + # CQ CQ CQ + if data == 'CQCQCQ': + for i in range(0,3): + arq.transmit_cq() + while static.ARQ_STATE == 'SENDING_SIGNALLING': + time.sleep(0.1) + pass + + + # PING + if data.startswith('PING:'): + #send ping frame and wait for ACK + pingcommand = data.split('PING:') + dxcallsign = pingcommand[1] + arq.transmit_ping(dxcallsign) + + + # ARQ CONNECT TO CALLSIGN + if data.startswith('ARQ:CONNECT:'): + if static.TNC_STATE == b'CONNECTED': + # here we should disconnect + pass + + if static.TNC_STATE == b'IDLE': + # here we send an "CONNECT FRAME + pass + + + # 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 if data.startswith('ARQ:') and static.TNC_STATE == b'IDLE': logging.info("CMD | NEW ARQ DATA") static.TNC_STATE = b'BUSY' diff --git a/static.py b/static.py index 51357037..7dba9d7b 100644 --- a/static.py +++ b/static.py @@ -18,7 +18,7 @@ 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 @@ -69,6 +69,8 @@ FREEDV_DATA_BYTES_PER_FRAME = 0 FREEDV_DATA_PAYLOAD_PER_FRAME = 0 FREEDV_SIGNALLING_BYTES_PER_FRAME = 0 FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = 0 + +UNCODED_BER = 1 #--------------------------------- #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,10 @@ ARQ_N_SENT_FRAMES = 0 #counter for already sent frames # RECEIVING_SIGNALLING # SENDING_ACK # ACK_RECEIVED -# -# -# -ARQ_STATE = 'RECEIVING_DATA' +# CONNECTED +# DISCONNECTED +# DISCONNECTING +ARQ_STATE = 'RECEIVING_SIGNALLING' # ------- TX BUFFER TX_BUFFER_SIZE = 0