Merge pull request #97 from DJ2LS/ls-hamlib-test

hamlib tests and optimization
Thanks to @frspin the problems with hamlib ptt seem to be solved.
I also added a small test program for doing ctypes experiments with hamlib native api access so the thoughts are not lost.
we also keep rigctl.py in the code as a fallback and for further tests and ideas
This commit is contained in:
DJ2LS 2022-01-05 12:03:20 +01:00 committed by GitHub
commit de6cea866a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 308 additions and 2628 deletions

127
test/hamlib-test.py Normal file
View file

@ -0,0 +1,127 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ctypes
from ctypes import *
import pathlib
from enum import Enum
class DEBUGLEVEL(Enum):
RIG_DEBUG_NONE = 0
RIG_DEBUG_BUG = 1
RIG_DEBUG_ERR = 2
RIG_DEBUG_WARN = 3
RIG_DEBUG_VERBOSE = 4
RIG_DEBUG_TRACE = 5
RIG_DEBUG_CACHE = 6
class RETCODE(Enum):
RIG_OK = 0
RIG_EINVAL = 1
RIG_ECONF = 2
RIG_ENOMEM = 3
RIG_ENIMPL = 4
RIG_ETIMEOUT = 5
RIG_EIO = 6
RIG_EINTERNAL = 7
RIG_EPROTO = 8
RIG_ERJCTED = 9
RIG_ETRUNC = 10
RIG_ENAVAIL = 11
RIG_ENTARGET = 12
RIG_BUSERROR = 13
RIG_BUSBUSY = 14
RIG_EARG = 15
RIG_EVFO = 16
RIG_EDOM = 17
libname = pathlib.Path("../tnc/lib/hamlib/linux/libhamlib.so")
hamlib = ctypes.CDLL(libname)
class SERIAL(ctypes.Structure):
_fields_ = [
("data_bits", ctypes.c_int),
("stop_bits", ctypes.c_int),
("rate", ctypes.c_int),
("parity", ctypes.c_int),
("handshake", ctypes.c_void_p),
]
class PARM(ctypes.Structure):
_fields_ = [
("serial", SERIAL),
]
class TYPE(ctypes.Structure):
_fields_ = [
("rig", ctypes.c_void_p),
]
class MYPORT(ctypes.Structure):
_fields_ = [
("pathname", ctypes.c_char),
("model", ctypes.c_int),
("parm", PARM),
("type", TYPE),
]
hamlib.rig_set_debug(9) #6
myrig_model = 3085 #3085 = ICOM 6 = DUMMY
myport = MYPORT()
myport.parm.serial.data_bits = 7
myport.parm.serial.stop_bits = 2
myport.parm.serial.rate = 9600
rig = hamlib.rig_init(myrig_model)
retcode = hamlib.rig_set_parm(rig, 'stop_bits', 5)
print(retcode)
'''
parameter = create_string_buffer(16)
retcode = hamlib.rig_get_parm(rig, 0, parameter)
print(retcode)
print(bytes(parameter))
'''
# attempt to access global vars. Maybe we can access structures as well?
# https://github.com/Hamlib/Hamlib/blob/f5b229f9dc4b4364d2f40e0b0b415e92c9a371ce/src/rig.c#L95
hamlib_version = ctypes.cast(hamlib.hamlib_version, ctypes.POINTER(ctypes.c_char*21))
print(hamlib_version.contents.value)
'''
retcode = hamlib.rig_has_get_parm(rig, 7)
print(retcode)
'''
'''
retcode = hamlib.rig_open(rig)
print(retcode)
hamlib.rig_close(rig)
'''
#riginfo = create_string_buffer(1024)
#retcode = hamlib.rig_get_rig_info(rig, riginfo, 1024);
'''
char riginfo[1024];
retcode = rig_get_rig_info(rig, riginfo, sizeof(riginfo));
'''

View file

@ -20,9 +20,9 @@ import serial.tools.list_ports
import static
import crcengine
import re
import rig
import logging, structlog, log_handler
log_handler.setup_logging("daemon")
# get python version, which is needed later for determining installation path
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
@ -197,7 +197,14 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler):
options.append(stop_bits)
options.append('--handshake')
options.append(handshake)
if HAMLIB_USE_RIGCTL:
options.append('--rigctl')
# try running tnc from binary, else run from source
# this helps running the tnc in a developer environment
@ -351,11 +358,19 @@ if __name__ == '__main__':
# --------------------------------------------GET PARAMETER INPUTS
PARSER = argparse.ArgumentParser(description='Simons TEST TNC')
PARSER.add_argument('--port', dest="socket_port",default=3001, help="Socket port", type=int)
PARSER.add_argument('--rigctl', dest="hamlib_use_rigctl",action="store_true", default=False, help="force using of rigctl")
ARGS = PARSER.parse_args()
PORT = ARGS.socket_port
HAMLIB_USE_RIGCTL = ARGS.hamlib_use_rigctl
if HAMLIB_USE_RIGCTL:
structlog.get_logger("structlog").warning("using rigctl....")
import rigctl as rig
else:
structlog.get_logger("structlog").warning("using rig.......")
import rig
# --------------------------------------------START CMD SERVER
DAEMON_THREAD = threading.Thread(target=start_daemon, name="daemon")
DAEMON_THREAD.start()

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
# Hamlib
## Linux
## Last updated: 02.09.21

BIN
tnc/lib/hamlib/linux/libhamlib.so Executable file

Binary file not shown.

View file

@ -36,9 +36,8 @@ if __name__ == '__main__':
PARSER.add_argument('--data_bits', dest="hamlib_data_bits", default="8", help="Hamlib data bits", type=str)
PARSER.add_argument('--stop_bits', dest="hamlib_stop_bits", default="1", help="Hamlib stop bits", type=str)
PARSER.add_argument('--handshake', dest="hamlib_handshake", default="None", help="Hamlib handshake", type=str)
PARSER.add_argument('--rigctl', dest="hamlib_use_rigctl", action="store_true", default=False, help="force using of rigctl")
ARGS = PARSER.parse_args()
@ -52,7 +51,9 @@ if __name__ == '__main__':
static.HAMLIB_SERIAL_SPEED = ARGS.hamlib_serialspeed
static.HAMLIB_DATA_BITS = ARGS.hamlib_data_bits
static.HAMLIB_STOP_BITS = ARGS.hamlib_stop_bits
static.HAMLIB_HANDSHAKE = ARGS.hamlib_handshake
static.HAMLIB_HANDSHAKE = ARGS.hamlib_handshake
static.HAMLIB_USE_RIGCTL = ARGS.hamlib_use_rigctl
print(ARGS.hamlib_use_rigctl)
# we need to wait until we got all parameters from argparse first before we can load the other modules
import sock

View file

@ -22,7 +22,14 @@ import data_handler
import re
import queue
import codec2
import rig
print(static.HAMLIB_USE_RIGCTL)
if static.HAMLIB_USE_RIGCTL:
structlog.get_logger("structlog").warning("using rigctl....")
import rigctl as rig
else:
structlog.get_logger("structlog").warning("using rig.......")
import rig
# option for testing miniaudio instead of audioop for sample rate conversion
#import miniaudio

View file

@ -4,6 +4,7 @@ import sys
import re
import logging, structlog, log_handler
import atexit
import subprocess
# try importing hamlib
@ -29,9 +30,23 @@ try:
else:
structlog.get_logger("structlog").warning("[TNC] Hamlib outdated", found=hamlib_version, recommend=min_hamlib_version)
except Exception as e:
structlog.get_logger("structlog").critical("[TNC] Hamlib not found", error=e)
structlog.get_logger("structlog").warning("[TNC] Python Hamlib binding not found", error=e)
try:
structlog.get_logger("structlog").warning("[TNC] Trying to open rigctl", error=e)
rigctl = subprocess.Popen("rigctl -V",shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
hamlib_version = rigctl.stdout.readline()
hamlib_version = hamlib_version.split(' ')
print(hamlib_version[0])
print(hamlib_version[1])
print(hamlib_version[2])
if hamlib_version[1] == 'Hamlib':
rigctl = True
print(hamlib_version)
else:
rigctl = False
raise Exception
except Exception as e:
structlog.get_logger("structlog").critical("[TNC] HAMLIB NOT INSTALLED", error=e)
class radio:
def __init__(self):
@ -50,13 +65,13 @@ class radio:
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake):
self.devicename = devicename
self.deviceport = deviceport
self.deviceport = str(deviceport)
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = hamlib_ptt_type
self.pttport = pttport
self.data_bits = data_bits
self.stop_bits = stop_bits
self.handshake = handshake
self.hamlib_ptt_type = str(hamlib_ptt_type)
self.pttport = str(pttport)
self.data_bits = str(data_bits)
self.stop_bits = str(stop_bits)
self.handshake = str(handshake)
# try to init hamlib
@ -66,6 +81,7 @@ class radio:
# get devicenumber by looking for deviceobject in Hamlib module
try:
self.devicenumber = int(getattr(Hamlib, self.devicename))
print(self.devicenumber)
except:
structlog.get_logger("structlog").error("[DMN] Hamlib: rig not supported...")
self.devicenumber = 0
@ -80,6 +96,16 @@ class radio:
self.my_rig.set_conf("data_bits", self.data_bits)
self.my_rig.set_conf("ptt_pathname", self.pttport)
print(self.my_rig.get_conf("rig_pathname"))
print(self.my_rig.get_conf("retry"))
print(self.my_rig.get_conf("serial_speed"))
print(self.my_rig.get_conf("serial_handshake"))
print(self.my_rig.get_conf("stop_bits"))
print(self.my_rig.get_conf("data_bits"))
print(self.my_rig.get_conf("ptt_pathname"))
if self.hamlib_ptt_type == 'RIG':
self.hamlib_ptt_type = Hamlib.RIG_PTT_RIG
@ -159,17 +185,18 @@ class radio:
(hamlib_mode, bandwith) = self.my_rig.get_mode()
return bandwith
def set_mode(self, mode):
return 0
# not needed yet beacuse of some possible problems
#def set_mode(self, mode):
# return 0
def get_ptt(self):
return self.my_rig.get_ptt()
def set_ptt(self, state):
if state:
self.my_rig.set_ptt(self.hamlib_ptt_type, 1)
self.my_rig.set_ptt(Hamlib.RIG_VFO_CURR, 1)
else:
self.my_rig.set_ptt(self.hamlib_ptt_type, 0)
self.my_rig.set_ptt(Hamlib.RIG_VFO_CURR, 0)
return state
def close_rig(self):

109
tnc/rigctl.py Normal file
View file

@ -0,0 +1,109 @@
#!/usr/bin/env python3
# Franco Spinelli, IW2DHW
#
# versione mia di rig.py per gestire Ft897D tramite rigctl e senza
# fare alcun riferimento alla configurazione
#
# e' una pezza clamorosa ma serve per poter provare on-air il modem
#
import subprocess
#
import sys
import re
import logging, structlog, log_handler
import atexit
import time
# for rig_model -> rig_number only
class radio:
def __init__(self):
self.devicename = ''
self.devicenumber = ''
self.deviceport = ''
self.serialspeed = ''
self.hamlib_ptt_type = ''
self.my_rig = ''
self.pttport = ''
self.data_bits = ''
self.stop_bits = ''
self.handshake = ''
def open_rig(self, devicename, deviceport, hamlib_ptt_type, serialspeed, pttport, data_bits, stop_bits, handshake):
self.devicename = devicename
self.deviceport = deviceport
self.serialspeed = str(serialspeed) # we need to ensure this is a str, otherwise set_conf functions are crashing
self.hamlib_ptt_type = hamlib_ptt_type
self.pttport = pttport
self.data_bits = data_bits
self.stop_bits = stop_bits
self.handshake = handshake
# get devicenumber by looking for deviceobject in Hamlib module
try:
import Hamlib
self.devicenumber = int(getattr(Hamlib, self.devicename))
except:
if int(self.devicename):
self.devicenumber = int(self.devicename)
else:
self.devicenumber = 6 #dummy
structlog.get_logger("structlog").warning("[TNC] RADIO NOT FOUND USING DUMMY!", error=e)
print(self.devicenumber, self.deviceport, self.serialspeed)
self.cmd = 'rigctl -m %d -r %s -s %d ' % (int(self.devicenumber), self.deviceport, int(self.serialspeed))
# eseguo semplicemente rigctl con il solo comando T 1 o T 0 per
# il set e t per il get
# set ptt to false if ptt is stuck for some reason
self.set_ptt(False)
return True
def get_frequency(self):
cmd = self.cmd + ' f'
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
time.sleep(0.5)
freq = sw_proc.communicate()[0]
#print('get_frequency', freq, sw_proc.communicate())
return int(freq)
def get_mode(self):
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
#return Hamlib.rig_strrmode(hamlib_mode)
return 'PKTUSB'
def get_bandwith(self):
#(hamlib_mode, bandwith) = self.my_rig.get_mode()
bandwith = 2700
return bandwith
def set_mode(self, mode):
# non usata
return 0
def get_ptt(self):
cmd = self.cmd + ' t'
sw_proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
time.sleep(0.5)
status = sw_proc.communicate()[0]
return status
def set_ptt(self, state):
cmd = self.cmd + ' T '
print('set_ptt', state)
if state:
cmd = cmd + '1'
else:
cmd = cmd + '0'
print('set_ptt', cmd)
sw_proc = subprocess.Popen(cmd, shell=True, text=True)
return state
def close_rig(self):
#self.my_rig.close()
return

View file

@ -338,8 +338,7 @@ def start_cmd_socket():
structlog.get_logger("structlog").info("[TNC] Starting TCP/IP socket", port=static.PORT)
# https://stackoverflow.com/a/16641793
socketserver.TCPServer.allow_reuse_address = True
cmdserver = ThreadedTCPServer(
(static.HOST, static.PORT), ThreadedTCPRequestHandler)
cmdserver = ThreadedTCPServer((static.HOST, static.PORT), ThreadedTCPRequestHandler)
server_thread = threading.Thread(target=cmdserver.serve_forever)
server_thread.daemon = True
server_thread.start()

View file

@ -44,6 +44,7 @@ HAMLIB_PTT_PORT = '/dev/ttyUSB0'
HAMLIB_STOP_BITS = '1'
HAMLIB_DATA_BITS = '8'
HAMLIB_HANDSHAKE = 'None'
HAMLIB_USE_RIGCTL = False
HAMLIB_FREQUENCY = 0
HAMLIB_MODE = ''