first commit

This commit is contained in:
2022-08-24 08:41:00 +02:00
commit 5765dbd675
2497 changed files with 2244854 additions and 0 deletions
@@ -0,0 +1,225 @@
"""
This module contains experimental code for using the (extend) UHSDR API
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""
from __future__ import print_function
__author__ = "DB4PLE"
__copyright__ = "Copyright 2018, UHSDR project"
__credits__ = ["DB4PLE"]
__license__ = "GPLv3"
__status__ = "Prototype"
import sys
import os
class CatCmdFt817:
"""
List of used/supported FT817 CAT command codes
This list includes the officially known FT817 codes (including the "undocumented" ones)
"""
READ_EEPROM = 0xBB
WRITE_EEPROM = 0xBC
PTT_STATE = 0xF7
class CatCmd(CatCmdFt817):
"""
This list extends the FT817 by the special UHSDR codes implemented only in the UHSDR dialect
of FT817 CAT (which must be different from the FT817 ones)
"""
UHSDR_ID = 0x42
"""
this will return the bytes ['U', 'H' , 'S', 'D', 'R' ] and is used to identify an UHSDR with high enough firmware level
"""
class UhsdrConfigIndex:
"""
this is a completely incomplete list of config value indicies as used in the UHSDR firmware
we list only the absolutely necessary ids here for the moment (those must never change in different firmware versions, would break this code)
"""
VER_MAJOR = 176
VER_MINOR = 310
VER_BUILD = 171
NUMBER_OF_ENTRIES = 407
def eprint(*args, **kwargs):
"""
a small function to print to stderr, used for error and logging messages
"""
print(*args, file=sys.stderr, **kwargs)
class catSerial:
"""
Low Level FT817 CAT protocol handling on a serial communication
"""
def __init__(self, comObj):
self.comObj = comObj
def sendCommand(self, command):
bytesWritten = self.comObj.write(command)
return bytesWritten == 5
def readResponse(self,count):
response = self.comObj.read(count)
return (len(response) == count,response)
class catCommands:
"""
CAT API: Here we have direct access to CAT API ations, each logical API function has its direct counterpart in this
class
We do not implement any extra control logic in here, just the call of the API function and returning the response
This may be enriched to have all availabl CAT API functions, right now it is just what we need now
"""
def __init__(self, catObj):
self.catObj = catObj
def execute(self, cmd, count):
if self.catObj.sendCommand(cmd):
ok,res = self.catObj.readResponse(count)
return ok,bytearray(res)
else:
return (False,bytearray([]))
def readEEPROM(self, addr):
cmd = bytearray([ (addr & 0xff00)>>8,addr & 0xff, 0x00, 0x00, CatCmd.READ_EEPROM])
ok,res = self.execute(cmd,2)
if ok:
return res[1] * 256 + res[0]
else:
return ok
def readUHSDR(self):
cmd = bytearray([ 0x00, 0x00 , 0x00, 0x00, CatCmd.UHSDR_ID])
ok,res = self.execute(cmd,5)
return res == bytearray("UHSDR", 'utf-8')
def readPttState(self):
cmd = bytearray([ 0x00, 0x00 , 0x00, 0x00, CatCmd.PTT_STATE])
ok,res = self.execute(cmd,5)
return res
def writeEEPROM(self, addr, value16bit):
cmd = bytearray([ (addr & 0xff00)>>8,addr & 0xff, (value16bit & 0xff) >> 0, (value16bit & 0xff00) >> 8, CatCmd.WRITE_EEPROM])
ok,res = self.execute(cmd,1)
return ok
def readUHSDRConfig(self, index):
return self.readEEPROM(index + 0x8000);
def writeUHSDRConfig(self, index, value):
return self.writeEEPROM(index + 0x8000, value);
class UhsdrConfig():
"""
CONFIG MANAGEMENT: Handling of reading / writing TRX configurations, detection of TRX presence etc.
This class represents high-level actions, should involve proper parameter checking etc.
"""
def __init__(self, catObj):
self.catObj = catObj
def getVersion(self):
"""
return firmware version as integer tuple (major,minor,build)
or (False,False,False) if something goes wrong
"""
return (self.catObj.readUHSDRConfig(UhsdrConfigIndex.VER_MAJOR),
self.catObj.readUHSDRConfig(UhsdrConfigIndex.VER_MINOR),
self.catObj.readUHSDRConfig(UhsdrConfigIndex.VER_BUILD))
def isUhsdrConnected(self):
"""
we test if an UHSDR with extended API is connected by using an identification API call not present
on a FT817 or older UHSDR / mcHF firmwares
returns: True if a suitable TRX is connected, False otherwise
"""
return self.catObj.readUHSDR()
#
def getConfigValueCount(self):
return self.catObj.readUHSDRConfig(UhsdrConfigIndex.NUMBER_OF_ENTRIES)
def getValue(self, index):
# TODO: do some range checking here
return self.catObj.readUHSDRConfig(index)
def setValue(self, index, value):
# TODO: do some range checking here
retval = False
if self.catObj.writeUHSDRConfig(index, value):
retval = value == self.getValue(index)
return retval
def configToJson(self):
"""
read the configuration from TRX into a data dictionary
returns tuple with boolean success state and read data
right now the returned JSON structure is quite simple
we store the version number as list of 3 integers under the 'version' key
we store the date and time of backup as UTC under the 'when' key
we store each configuration value as addr/value pair under the 'eeprom' key
"""
from datetime import datetime
retval = False
valList = []
self.data = {}
self.data['version'] = self.getVersion()
self.data['when'] = str(datetime.utcnow())
self.data['eeprom'] = []
numberOfValues = self.getConfigValueCount()
for index in range(numberOfValues):
val = self.getValue(index)
valList.append(val)
self.data['eeprom'].append({ 'addr' : index , 'value' : val })
retval = all(val is not False for val in valList) or len(valList) != 0
return retval,self.data
def jsonToConfig(self,data):
"""
write the configuration in passed data dictionary to TRX
returns tuple with boolean success state and human readable return msg
data dictionary must conform to format generated by configToJson()
"""
retval = True
retmsg = "OK"
if data['when'] != None and len(data['version']) == 3 and len(data['eeprom']) == data['eeprom'][UhsdrConfigIndex.NUMBER_OF_ENTRIES]['value']:
numberOfValues = data['eeprom'][UhsdrConfigIndex.NUMBER_OF_ENTRIES]['value']
# we do not restore index 0 as it contains EEPROM type. This is never changed during configuration backup, too dangerous
for index in range(numberOfValues):
addr = data['eeprom'][index]['addr']
value = data['eeprom'][index]['value']
if addr != 0:
if self.setValue(addr,value) == False:
retmsg = "Restoring value {} at addr {} failed".format(value,addr)
retval = False
break
else:
retmsg = "Configuration data failed consistency check"
retval = False
return retval,retmsg
@@ -0,0 +1,148 @@
"""
This module contains experimental code for using the (extend) UHSDR API
and contains a small commandline client for backup and restore of
the UHSDR configuration data from/to a TRX
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""
from __future__ import print_function
__author__ = "DB4PLE"
__copyright__ = "Copyright 2018, UHSDR project"
__credits__ = ["DB4PLE"]
__license__ = "GPLv3"
__status__ = "Prototype"
import sys
import json
import os
import uhsdr
def listUHSDRSerial():
"""
list serial ports. For new pySerial version we return only the real UHSDR device, otherwise just a list of serial port objects
returns tupel (Boolean,List) True if UHSDR filter was active, False otherwise, second element is actual list of info for com ports.
"""
import serial
import serial.tools.list_ports;
from distutils.version import StrictVersion
# UHSDR uses USB VID:PID=0483:5732
retval = False,[]
if StrictVersion(serial.VERSION) >= StrictVersion("3.0"):
retval = True,[ comport.device for comport in serial.tools.list_ports.comports() if comport.vid == 0x0483 and comport.pid == 0x5732 ]
else:
uhsdr.eprint("pySerial version ",serial.VERSION," is too old for detecting UHSDR device, using full serial port list")
retval = False,[ vars(comport) for comport in serial.tools.list_ports.comports()]
return retval
def backupRestoreApp():
import serial
"""
Simple command line tool to backup/restore the configuration from/to TRX
"""
if False and "idlelib" in sys.modules:
uhsdr.eprint("Running in IDLE GUI, please set parameters directly in script, search for #change ")
#change parameters here
sys.argv = [sys.argv[0],'--port','15','-b']
#no more changes below
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-b","--backup", help="backup the UHSDR TRX configuration to file", action="store_true")
parser.add_argument("-r","--restore", help="restore the UHSDR TRX configuration from file", action="store_true")
parser.add_argument("-p","--port", help="UHSDR serial port either by number (COM<num> in Windows, Linux /dev/ttyACM<num>) or full device name ( e.g. '/dev/cu.modemABCD', all operating systems )", type=str, default="undefined serial port name")
parser.add_argument("-f","--file", help="filename to backup to/restore from, if not defined 'uhsdr_config.json' is used", type=str, default="uhsdr_config.json")
args = parser.parse_args()
print("This program backups and restores the configuration of UHSDR TRX via USB")
if args.port == -1:
print("Use -h to get more information")
print("")
isFiltered, uhsdrDeviceList = listUHSDRSerial()
if uhsdrDeviceList == []:
uhsdr.eprint("No suitable serial port detected, make sure to connect UHSDR TRX")
else:
if isFiltered:
uhsdr.eprint("List of detected UHSDR TRX")
else:
uhsdr.eprint("List of detected serial ports:")
uhsdr.eprint(uhsdrDeviceList)
uhsdr.eprint("Please specify valid UHSDR TRX serial port number(!) with -p / --port")
else:
try:
int(args.port);
comPort= ("COM" if os.name == "nt" else "/dev/ttyACM") + str(args.port)
except:
comPort = args.port
uhsdr.eprint("Opening serial port ",comPort,":")
try:
mySer = serial.Serial(comPort, 38400, timeout=0.500, parity=serial.PARITY_NONE)
except:
uhsdr.eprint("... failed")
raise
uhsdr.eprint("... okay")
myCom = uhsdr.catSerial(mySer)
myCAT = uhsdr.catCommands(myCom)
myUHSDR = uhsdr.UhsdrConfig(myCAT)
uhsdr.eprint("Detecting if UHSDR is connected: ")
if myUHSDR.isUhsdrConnected():
uhsdr.eprint("... yes")
version = myUHSDR.getVersion()
print("Detected UHSDR Firmware Version", version)
if args.backup:
uhsdr.eprint("Reading configuration from UHSDR TRX:")
ok,data = myUHSDR.configToJson()
if ok:
uhsdr.eprint("... success. Now saving in file:")
with open(args.file, 'w') as outfile:
try:
json.dump(data, outfile, indent=4)
uhsdr.eprint("... saved to " + args.file + " file")
except:
uhsdr.eprint("... failed to save to " + args.file + " file")
raise
outfile.close()
else:
uhsdr.eprint("... could not read data sucessfully")
elif args.restore:
with open(args.file, 'r') as infile:
data = json.load(infile)
uhsdr.eprint("Sending configuration to UHSDR TRX:")
ok,msg = myUHSDR.jsonToConfig(data)
if ok:
uhsdr.eprint("... restored all data from " + args.file + " file")
print("ACTIVATING RESTORED CONFIGURATION: Switch off TRX WITHOUT saving configuration -> Press Band+ and Power buttons")
print("")
print("ATTENTION: In case of an accidential restore:")
print("Press Power button to save running configuration, overwriting the restored values in configuration memory.")
else:
uhsdr.eprint("... problem occured: ",msg)
infile.close()
else:
uhsdr.eprint("... could not find a connected UHSDR with extended CAT commands (required)")
mySer.close()
if __name__ == "__main__":
backupRestoreApp()