mirror of
https://github.com/spm81/Quansheng_UV-K5.git
synced 2024-09-21 07:47:11 +00:00
Update Firmware & README.md
This commit is contained in:
parent
9e5e9738df
commit
d1f54175d2
Binary file not shown.
@ -4,6 +4,6 @@ MCFW V0.01 - Only release on Telegram for feedback, (buggy version). <br>
|
||||
MCFW V0.02 - Based on Open Spectrum Firmware - OSFW-ecd267e by fagci + Old Style Keys + RSSI + Voltage + improvement in SATCOM reception. <br>
|
||||
MCFW V0.03 - Based on Open Spectrum Firmware - OSFW-40e01a6 by Tunas1337 with facgi Spectrum + New Menu + Old Style Keys + RSSI + improvement in SATCOM reception.<br>
|
||||
MCFW V0.04 - Based on Open Spectrum Firmware - OSFW-502a638 by Tunas1337 with facgi Spectrum + New Menu + Old Style Keys + RSSI + Voltage + improvement in SATCOM reception.
|
||||
|
||||
MCFW V0.05 - Based on Open Spectrum Firmware - OSFW-7bcb669 by Tunas1337 with facgi Spectrum + New Menu + Old Style Keys + RSSI + Voltage + Unlimited Freq. Scan + improvement in SATCOM reception.
|
||||
|
||||
Fagci Spectrum Help (are not the "Old Style Keys" but the rest is iqual)
|
||||
|
Binary file not shown.
@ -20,6 +20,12 @@ A cool achievement
|
||||
<img src="image5.jpg" width="300" />
|
||||
</p><br>
|
||||
|
||||
Video showing the AM fix working ..
|
||||
|
||||
<video src="AM_fix.mp4"></video>
|
||||
|
||||
<video src="https://github.com/OneOfEleven/uv-k5-firmware-custom/assets/51590168/2a3a9cdc-97da-4966-bf0d-1ce6ad09779c"></video>
|
||||
|
||||
# Matoz Add-ons
|
||||
|
||||
F-LOCK PMR = ( Disables TX on all bands except PMR446 )
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
66
Software/Battery Calibrator/batt_calibrator.py
Normal file
66
Software/Battery Calibrator/batt_calibrator.py
Normal file
@ -0,0 +1,66 @@
|
||||
import libuvk5
|
||||
import sys,os
|
||||
import struct
|
||||
|
||||
if len(sys.argv)<3: print(f'Usage: {os.path.basename(sys.argv[0])} <COMx> <read | write val0 val1 val2 val3 val4 val5 | calibrate>') ; exit(1)
|
||||
arg_port = sys.argv[1]
|
||||
action = sys.argv[2]
|
||||
|
||||
with libuvk5.uvk5(arg_port) as radio:
|
||||
radio.debug=False
|
||||
if radio.connect():
|
||||
_=radio.get_fw_version() #mandatory before reading mem
|
||||
calib_raw = radio.get_cfg_mem(0x1F40,16)
|
||||
calib_data = list(struct.unpack('<8H',calib_raw))
|
||||
calib_data_old = [i for i in calib_data]
|
||||
if action == 'read':
|
||||
def calculate_voltage(value, denominator):
|
||||
if denominator != 0:
|
||||
return 760 * value / denominator / 100
|
||||
else:
|
||||
return 0 # Handle the division by zero case
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(0, calib_data[0], calculate_voltage(calib_data[0], calib_data[3]), '// Empty battery blinking'))
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(1, calib_data[1], calculate_voltage(calib_data[1], calib_data[3]), '// 1 battery bar if above this value'))
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(2, calib_data[2], calculate_voltage(calib_data[2], calib_data[3]), '// 2 battery bars if above this value'))
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(3, calib_data[3], calculate_voltage(calib_data[3], calib_data[3]), '// 3 battery bars if above this value, also value used to calculate adc to volt'))
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(4, calib_data[4], calculate_voltage(calib_data[4], calib_data[3]), '// 4 battery bars if above this value'))
|
||||
print('Level {}: [{:>4}] {:.2f} V {}'.format(5, calib_data[5], calculate_voltage(calib_data[5], calib_data[3]), '// overwritten by radio to 2300 anyway'))
|
||||
print('\nActual = {:.2f} V'.format(calculate_voltage(radio.get_adc()[0], calib_data[3])))
|
||||
|
||||
if action=='write':
|
||||
if len(sys.argv)!=9: print(f'Usage: {os.path.basename(sys.argv[0])} <COMx> write val0 val1 val2 val3 val4 val5') ; exit(1)
|
||||
calib_data[0] = int(sys.argv[3],0)
|
||||
calib_data[1] = int(sys.argv[4],0)
|
||||
calib_data[2] = int(sys.argv[5],0)
|
||||
calib_data[3] = int(sys.argv[6],0)
|
||||
calib_data[4] = int(sys.argv[7],0)
|
||||
calib_data[5] = int(sys.argv[8],0)
|
||||
calib_raw = struct.pack('<8H',*calib_data)
|
||||
radio.set_cfg_mem(0x1F40,calib_raw)
|
||||
|
||||
if action=='calibrate':
|
||||
while True:
|
||||
actual_voltage = input("Enter voltage from multimeter and press enter: ")
|
||||
try:
|
||||
actual_voltage = float(actual_voltage.replace(',','.'))
|
||||
except:
|
||||
actual_voltage = None
|
||||
|
||||
if actual_voltage is not None:
|
||||
break
|
||||
adc_value = radio.get_adc()[0]
|
||||
new_coeff = int(760*adc_value/actual_voltage/100)
|
||||
print('Current battery voltage = {:.2f}'.format(760*adc_value/calib_data[3]/100))
|
||||
print('Current battery ADC coefficient = {}'.format(calib_data[3]))
|
||||
print('')
|
||||
print('Desired battery voltage = {:.2f}'.format(actual_voltage))
|
||||
print('New battery ADC coefficient = {}'.format(new_coeff))
|
||||
print('Wait... ', end='')
|
||||
calib_data[3] = new_coeff
|
||||
calib_raw = struct.pack('<8H',*calib_data)
|
||||
radio.set_cfg_mem(0x1F40,calib_raw)
|
||||
print('OK. New value written to eeprom')
|
||||
print('Previous calibration values:',calib_data_old[0:6])
|
||||
print('Current calibration values :',struct.unpack('<8H',radio.get_cfg_mem(0x1F40,16))[0:6])
|
||||
print('')
|
||||
print('!!! PLEASE REBOOT RADIO FOR THE CHANGES TO TAKE EFFECT !!!')
|
234
Software/Battery Calibrator/libuvk5.py
Normal file
234
Software/Battery Calibrator/libuvk5.py
Normal file
@ -0,0 +1,234 @@
|
||||
import serial
|
||||
import struct
|
||||
import os
|
||||
|
||||
|
||||
Crc16Tab = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302,
|
||||
37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907,
|
||||
9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789,
|
||||
59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640,14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879,
|
||||
19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395,36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374,
|
||||
57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979,
|
||||
46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798,
|
||||
25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368,
|
||||
35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801,
|
||||
6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955,
|
||||
49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920]
|
||||
|
||||
|
||||
def crc16_ccitt(data):
|
||||
i2 = 0
|
||||
for i3 in range(0, len(data)):
|
||||
out = Crc16Tab[((i2 >> 8) ^ data[i3]) & 255]
|
||||
i2 = out ^ (i2 << 8)
|
||||
return 65535 & i2
|
||||
|
||||
|
||||
def crc16_ccitt_le(data):
|
||||
crc = crc16_ccitt(data)
|
||||
return bytes([crc & 0xFF,]) + bytes([crc>>8,])
|
||||
|
||||
|
||||
def firmware_xor(fwcontent):
|
||||
XOR_ARRAY = bytes.fromhex('4722c0525d574894b16060db6fe34c7cd84ad68b30ec25e04cd9007fbfe35405e93a976bb06e0cfbb11ae2c9c15647e9baf142b6675f0f96f7c93c841b26e14e3b6f66e6a06ab0bfc6a5703aba189e271a535b71b1941e18f2d6810222fd5a2891dbba5d64c6fe86839c501c730311d6af30f42c77b27dbb3f29285722d6928b')
|
||||
XOR_LEN = len(XOR_ARRAY)
|
||||
|
||||
ba=bytearray(fwcontent)
|
||||
for i in range(0,len(ba)):
|
||||
ba[i] ^= XOR_ARRAY[i%XOR_LEN]
|
||||
return bytes(ba)
|
||||
|
||||
|
||||
def payload_xor(payload):
|
||||
XOR_ARRAY = bytes.fromhex('166c14e62e910d402135d5401303e980')
|
||||
XOR_LEN = len(XOR_ARRAY)
|
||||
|
||||
ba=bytearray(payload)
|
||||
for i in range(0,len(ba)):
|
||||
ba[i] ^= XOR_ARRAY[i%XOR_LEN]
|
||||
return bytes(ba)
|
||||
|
||||
#================================================================================================================
|
||||
|
||||
|
||||
|
||||
class uvk5:
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
||||
|
||||
def __init__(self,portName='COM1'):
|
||||
|
||||
self.serial = serial.Serial()
|
||||
self.serial.baudrate = 38400
|
||||
self.serial.timeout=1
|
||||
self.serial.port=portName
|
||||
self.sessTimestamp = b'\x46\x9C\x6F\x64'
|
||||
|
||||
self.CMD_GET_FW_VER = b'\x14\x05' #0x0514 -> 0x0515
|
||||
self.CMD_READ_FW_MEM = b'\x17\x05' #0x0517 -> 0x0518
|
||||
self.CMD_WRITE_FW_MEM = b'\x19\x05' #0x0519 -> 0x051a //Only in bootloader
|
||||
|
||||
self.CMD_READ_CFG_MEM = b'\x1B\x05' #0x051B -> 0x051C
|
||||
self.CMD_WRITE_CFG_MEM= b'\x1D\x05' #0x051D -> 0x051E
|
||||
|
||||
|
||||
self.CMD_052D = b'\x2D\x05'
|
||||
self.CMD_051F = b'\x1F\x05'
|
||||
self.CMD_052F = b'\x2F\x05'
|
||||
|
||||
self.CMD_REBOOT = b'\xDD\x05' #0x05DD -> no reply
|
||||
self.CMD_0530 = b'\x30\x05' #0x0530 -> no reply //Only in bootloader
|
||||
self.CMD_0527 = b'\x27\x05'
|
||||
self.CMD_0529 = b'\x29\x05'
|
||||
|
||||
self.debug = False if os.getenv('DEBUG') is None else True
|
||||
|
||||
def __del__(self):
|
||||
self.serial.close()
|
||||
return not self.serial.is_open
|
||||
|
||||
|
||||
|
||||
|
||||
def connect(self):
|
||||
self.serial.open()
|
||||
return self.serial.is_open
|
||||
|
||||
def uart_send_msg(self,msg_dec):
|
||||
if self.debug: print('>dec>',msg_dec.hex())
|
||||
msg_raw = msg_dec[:4] + payload_xor(msg_dec[4:-2]) + msg_dec[-2:]
|
||||
if self.debug: print('>raw>',msg_raw.hex())
|
||||
return self.serial.write(msg_raw)
|
||||
|
||||
def uart_receive_msg(self,len):
|
||||
msg_raw = self.serial.read(len)
|
||||
if self.debug: print('<raw<',msg_raw.hex())
|
||||
msg_dec = msg_raw[:4] + payload_xor(msg_raw[4:-2]) + msg_raw[-2:]
|
||||
if self.debug: print('<dec<',msg_dec.hex())
|
||||
return msg_dec
|
||||
|
||||
|
||||
def build_uart_command(self, command_type, command_body=b''):
|
||||
cmd = command_type + struct.pack('<H',len(command_body))+ command_body
|
||||
cmd_len = struct.pack('<H',len(cmd))
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + cmd_len + cmd + cmd_crc + b'\xDC\xBA'
|
||||
return cmd
|
||||
|
||||
|
||||
def get_fw_version(self):
|
||||
cmd=self.build_uart_command(self.CMD_GET_FW_VER, self.sessTimestamp)
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[8:].split(b'\0', 1)[0].decode()
|
||||
|
||||
def get_cfg_mem(self,address,length):
|
||||
cmd=self.build_uart_command(self.CMD_READ_CFG_MEM, struct.pack('<HH',address,length) + self.sessTimestamp)
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(length+16)
|
||||
return reply[12:-4]
|
||||
|
||||
def set_cfg_mem(self,address,payload):
|
||||
if len(payload)%8==0:
|
||||
cmd=self.CMD_WRITE_CFG_MEM + struct.pack('<HHH',len(payload)+8, address, len(payload)) + self.sessTimestamp + payload
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd=b'\xAB\xCD' + struct.pack('<H',len(payload)+0xC) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(14)
|
||||
return reply[12:-4]
|
||||
else:
|
||||
raise Exception('Payload have to be multiples of 8 bytes')
|
||||
|
||||
def reboot(self):
|
||||
cmd = self.CMD_REBOOT + b'\x00\x00'
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',4) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
return True
|
||||
|
||||
def get_fw_mem(self,address,length):
|
||||
cmd=self.CMD_READ_FW_MEM #+ b'\x00\x00' # struct.pack('<HH',address,length)
|
||||
cmd= b'\x00\x05' #+ b'\x00\x00' # struct.pack('<HH',address,length)
|
||||
cmd_crc = b'' #struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd=b'\xAB\xCD' + struct.pack('<H',len(cmd)) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(1024)
|
||||
return reply[12:-4]
|
||||
|
||||
#def set_fw_mem(self,block,payload):
|
||||
# bytes_to_write = length(payload)
|
||||
# padd_bytes = b'\x00'*(1000 - bytes_to_write)
|
||||
# payload=payload+padd_bytes
|
||||
# print(payload.hex())
|
||||
# cmd=self.build_uart_command(self.CMD_WRITE_FW_MEM, struct.pack('<IIII',block,bytes_to_write,0xe6,0) + self.sessTimestamp + payload)
|
||||
# self.uart_send_msg(cmd)
|
||||
# reply = self.uart_receive_msg(128)
|
||||
# return reply[12:-4]
|
||||
|
||||
def unk_fn_0530(self,text):
|
||||
buff = bytes(text,'ascii') + b'\x00'*(16-len(text))
|
||||
cmd = self.CMD_0530 + struct.pack('<H',16) + buff
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',20) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def unk_fn_051F(self):
|
||||
# 0/1 + 2/3
|
||||
cmd = self.CMD_051F + struct.pack('<H',18)+ \
|
||||
struct.pack('<I',433000000) + \
|
||||
struct.pack('<H',0x00) + \
|
||||
struct.pack('<H',0x7F) + \
|
||||
struct.pack('<H',0xFF) + \
|
||||
struct.pack('<H',0x00) + \
|
||||
struct.pack('<H',0x7F) + \
|
||||
struct.pack('<H',0xFF) + \
|
||||
struct.pack('<H',1)
|
||||
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',22) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def unk_fn_052F(self):
|
||||
# 0/1 + 2/3
|
||||
cmd = self.CMD_052F + struct.pack('<H',4) + self.sessTimestamp
|
||||
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
|
||||
def unk_fn_1325(self,uint1,uint2,uint3,uint4):
|
||||
cmd = self.CMD_052D + struct.pack('<HIIII',16,uint1,uint2,uint3,uint4)
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',20) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def get_rssi(self):
|
||||
cmd = self.CMD_0527 + struct.pack('<H',4) + self.sessTimestamp
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(16)
|
||||
rssi,noise,glitch = struct.unpack('<HBB',reply[8:-4])
|
||||
rssi = rssi / 2 - 160
|
||||
return {'rssi':rssi, 'noise':noise, 'glitch':glitch, 'raw':reply[8:-4].hex()}
|
||||
|
||||
|
||||
def get_adc(self):
|
||||
cmd = self.CMD_0529 + struct.pack('<H',4) + self.sessTimestamp
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(16)
|
||||
reply = struct.unpack('<HH',reply[8:-4])
|
||||
return reply
|
234
Software/Squelch Table Read & Write/libuvk5.py
Normal file
234
Software/Squelch Table Read & Write/libuvk5.py
Normal file
@ -0,0 +1,234 @@
|
||||
import serial
|
||||
import struct
|
||||
import os
|
||||
|
||||
|
||||
Crc16Tab = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302,
|
||||
37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907,
|
||||
9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789,
|
||||
59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640,14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879,
|
||||
19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395,36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374,
|
||||
57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979,
|
||||
46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798,
|
||||
25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368,
|
||||
35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801,
|
||||
6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955,
|
||||
49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920]
|
||||
|
||||
|
||||
def crc16_ccitt(data):
|
||||
i2 = 0
|
||||
for i3 in range(0, len(data)):
|
||||
out = Crc16Tab[((i2 >> 8) ^ data[i3]) & 255]
|
||||
i2 = out ^ (i2 << 8)
|
||||
return 65535 & i2
|
||||
|
||||
|
||||
def crc16_ccitt_le(data):
|
||||
crc = crc16_ccitt(data)
|
||||
return bytes([crc & 0xFF,]) + bytes([crc>>8,])
|
||||
|
||||
|
||||
def firmware_xor(fwcontent):
|
||||
XOR_ARRAY = bytes.fromhex('4722c0525d574894b16060db6fe34c7cd84ad68b30ec25e04cd9007fbfe35405e93a976bb06e0cfbb11ae2c9c15647e9baf142b6675f0f96f7c93c841b26e14e3b6f66e6a06ab0bfc6a5703aba189e271a535b71b1941e18f2d6810222fd5a2891dbba5d64c6fe86839c501c730311d6af30f42c77b27dbb3f29285722d6928b')
|
||||
XOR_LEN = len(XOR_ARRAY)
|
||||
|
||||
ba=bytearray(fwcontent)
|
||||
for i in range(0,len(ba)):
|
||||
ba[i] ^= XOR_ARRAY[i%XOR_LEN]
|
||||
return bytes(ba)
|
||||
|
||||
|
||||
def payload_xor(payload):
|
||||
XOR_ARRAY = bytes.fromhex('166c14e62e910d402135d5401303e980')
|
||||
XOR_LEN = len(XOR_ARRAY)
|
||||
|
||||
ba=bytearray(payload)
|
||||
for i in range(0,len(ba)):
|
||||
ba[i] ^= XOR_ARRAY[i%XOR_LEN]
|
||||
return bytes(ba)
|
||||
|
||||
#================================================================================================================
|
||||
|
||||
|
||||
|
||||
class uvk5:
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
||||
|
||||
def __init__(self,portName='COM1'):
|
||||
|
||||
self.serial = serial.Serial()
|
||||
self.serial.baudrate = 38400
|
||||
self.serial.timeout=1
|
||||
self.serial.port=portName
|
||||
self.sessTimestamp = b'\x46\x9C\x6F\x64'
|
||||
|
||||
self.CMD_GET_FW_VER = b'\x14\x05' #0x0514 -> 0x0515
|
||||
self.CMD_READ_FW_MEM = b'\x17\x05' #0x0517 -> 0x0518
|
||||
self.CMD_WRITE_FW_MEM = b'\x19\x05' #0x0519 -> 0x051a //Only in bootloader
|
||||
|
||||
self.CMD_READ_CFG_MEM = b'\x1B\x05' #0x051B -> 0x051C
|
||||
self.CMD_WRITE_CFG_MEM= b'\x1D\x05' #0x051D -> 0x051E
|
||||
|
||||
|
||||
self.CMD_052D = b'\x2D\x05'
|
||||
self.CMD_051F = b'\x1F\x05'
|
||||
self.CMD_052F = b'\x2F\x05'
|
||||
|
||||
self.CMD_REBOOT = b'\xDD\x05' #0x05DD -> no reply
|
||||
self.CMD_0530 = b'\x30\x05' #0x0530 -> no reply //Only in bootloader
|
||||
self.CMD_0527 = b'\x27\x05'
|
||||
self.CMD_0529 = b'\x29\x05'
|
||||
|
||||
self.debug = False if os.getenv('DEBUG') is None else True
|
||||
|
||||
def __del__(self):
|
||||
self.serial.close()
|
||||
return not self.serial.is_open
|
||||
|
||||
|
||||
|
||||
|
||||
def connect(self):
|
||||
self.serial.open()
|
||||
return self.serial.is_open
|
||||
|
||||
def uart_send_msg(self,msg_dec):
|
||||
if self.debug: print('>dec>',msg_dec.hex())
|
||||
msg_raw = msg_dec[:4] + payload_xor(msg_dec[4:-2]) + msg_dec[-2:]
|
||||
if self.debug: print('>raw>',msg_raw.hex())
|
||||
return self.serial.write(msg_raw)
|
||||
|
||||
def uart_receive_msg(self,len):
|
||||
msg_raw = self.serial.read(len)
|
||||
if self.debug: print('<raw<',msg_raw.hex())
|
||||
msg_dec = msg_raw[:4] + payload_xor(msg_raw[4:-2]) + msg_raw[-2:]
|
||||
if self.debug: print('<dec<',msg_dec.hex())
|
||||
return msg_dec
|
||||
|
||||
|
||||
def build_uart_command(self, command_type, command_body=b''):
|
||||
cmd = command_type + struct.pack('<H',len(command_body))+ command_body
|
||||
cmd_len = struct.pack('<H',len(cmd))
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + cmd_len + cmd + cmd_crc + b'\xDC\xBA'
|
||||
return cmd
|
||||
|
||||
|
||||
def get_fw_version(self):
|
||||
cmd=self.build_uart_command(self.CMD_GET_FW_VER, self.sessTimestamp)
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[8:].split(b'\0', 1)[0].decode()
|
||||
|
||||
def get_cfg_mem(self,address,length):
|
||||
cmd=self.build_uart_command(self.CMD_READ_CFG_MEM, struct.pack('<HH',address,length) + self.sessTimestamp)
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(length+16)
|
||||
return reply[12:-4]
|
||||
|
||||
def set_cfg_mem(self,address,payload):
|
||||
if len(payload)%8==0:
|
||||
cmd=self.CMD_WRITE_CFG_MEM + struct.pack('<HHH',len(payload)+8, address, len(payload)) + self.sessTimestamp + payload
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd=b'\xAB\xCD' + struct.pack('<H',len(payload)+0xC) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(14)
|
||||
return reply[12:-4]
|
||||
else:
|
||||
raise Exception('Payload have to be multiples of 8 bytes')
|
||||
|
||||
def reboot(self):
|
||||
cmd = self.CMD_REBOOT + b'\x00\x00'
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',4) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
return True
|
||||
|
||||
def get_fw_mem(self,address,length):
|
||||
cmd=self.CMD_READ_FW_MEM #+ b'\x00\x00' # struct.pack('<HH',address,length)
|
||||
cmd= b'\x00\x05' #+ b'\x00\x00' # struct.pack('<HH',address,length)
|
||||
cmd_crc = b'' #struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd=b'\xAB\xCD' + struct.pack('<H',len(cmd)) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(1024)
|
||||
return reply[12:-4]
|
||||
|
||||
#def set_fw_mem(self,block,payload):
|
||||
# bytes_to_write = length(payload)
|
||||
# padd_bytes = b'\x00'*(1000 - bytes_to_write)
|
||||
# payload=payload+padd_bytes
|
||||
# print(payload.hex())
|
||||
# cmd=self.build_uart_command(self.CMD_WRITE_FW_MEM, struct.pack('<IIII',block,bytes_to_write,0xe6,0) + self.sessTimestamp + payload)
|
||||
# self.uart_send_msg(cmd)
|
||||
# reply = self.uart_receive_msg(128)
|
||||
# return reply[12:-4]
|
||||
|
||||
def unk_fn_0530(self,text):
|
||||
buff = bytes(text,'ascii') + b'\x00'*(16-len(text))
|
||||
cmd = self.CMD_0530 + struct.pack('<H',16) + buff
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',20) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def unk_fn_051F(self):
|
||||
# 0/1 + 2/3
|
||||
cmd = self.CMD_051F + struct.pack('<H',18)+ \
|
||||
struct.pack('<I',433000000) + \
|
||||
struct.pack('<H',0x00) + \
|
||||
struct.pack('<H',0x7F) + \
|
||||
struct.pack('<H',0xFF) + \
|
||||
struct.pack('<H',0x00) + \
|
||||
struct.pack('<H',0x7F) + \
|
||||
struct.pack('<H',0xFF) + \
|
||||
struct.pack('<H',1)
|
||||
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',22) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def unk_fn_052F(self):
|
||||
# 0/1 + 2/3
|
||||
cmd = self.CMD_052F + struct.pack('<H',4) + self.sessTimestamp
|
||||
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
|
||||
def unk_fn_1325(self,uint1,uint2,uint3,uint4):
|
||||
cmd = self.CMD_052D + struct.pack('<HIIII',16,uint1,uint2,uint3,uint4)
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd= b'\xAB\xCD' + struct.pack('<H',20) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(128)
|
||||
return reply[12:-4]
|
||||
|
||||
def get_rssi(self):
|
||||
cmd = self.CMD_0527 + struct.pack('<H',4) + self.sessTimestamp
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(16)
|
||||
rssi,noise,glitch = struct.unpack('<HBB',reply[8:-4])
|
||||
rssi = rssi / 2 - 160
|
||||
return {'rssi':rssi, 'noise':noise, 'glitch':glitch, 'raw':reply[8:-4].hex()}
|
||||
|
||||
|
||||
def get_adc(self):
|
||||
cmd = self.CMD_0529 + struct.pack('<H',4) + self.sessTimestamp
|
||||
cmd_crc = struct.pack('<H',crc16_ccitt(cmd))
|
||||
cmd = b'\xAB\xCD' + struct.pack('<H',8) + cmd + cmd_crc + b'\xDC\xBA'
|
||||
self.uart_send_msg(cmd)
|
||||
reply = self.uart_receive_msg(16)
|
||||
reply = struct.unpack('<HH',reply[8:-4])
|
||||
return reply
|
68
Software/Squelch Table Read & Write/squelch_table_read.py
Normal file
68
Software/Squelch Table Read & Write/squelch_table_read.py
Normal file
@ -0,0 +1,68 @@
|
||||
import libuvk5
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
# Handle arguments
|
||||
# if len(sys.argv) not in [4,5]: print(f'Usage: {os.path.basename(sys.argv[0])} <COMx> <address> <len> [dest_file.bin]') ; exit(1)
|
||||
|
||||
arg_port = sys.argv[1]
|
||||
if len(sys.argv)==5:
|
||||
arg_file=sys.argv[4]
|
||||
else:
|
||||
arg_file=None
|
||||
|
||||
# SquelchOpenRSSIThreshold,
|
||||
# SquelchCloseRSSIThreshold,
|
||||
# SquelchOpenNoiseThreshold,
|
||||
# SquelchCloseNoiseThreshold,
|
||||
# SquelchCloseGlitchThreshold,
|
||||
# SquelchOpenGlitchThreshold
|
||||
|
||||
# Connect and read
|
||||
with libuvk5.uvk5(arg_port) as radio:
|
||||
if radio.connect():
|
||||
_=radio.get_fw_version() #mandatory before reading mem
|
||||
# print radio.get_cfg_mem(0x1e00,10).hex() but in comma separated hex digits
|
||||
# for i in range(12):
|
||||
# print(str(0x1e00+i*0x10) + ": ", end='')
|
||||
# temp = radio.get_cfg_mem(0x1e00+i*0x10,10).hex()
|
||||
# temp = ','.join([f'0x{temp[i:i+2]}' for i in range(0,len(temp),2)])
|
||||
# print(temp)
|
||||
# sys.exit(0)
|
||||
print("UHF Squelch Open RSSI Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e00+i,1).hex(),16)/2-160))
|
||||
print("UHF Squelch Close RSSI Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e10+i,1).hex(),16)/2-160))
|
||||
print("UHF Squelch Open Noise Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e20+i,1).hex(),16)))
|
||||
print("UHF Squelch Close Noise Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e30+i,1).hex(),16)))
|
||||
print("UHF Squelch Close Glitch Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e40+i,1).hex(),16)))
|
||||
print("UHF Squelch Open Glitch Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e50+i,1).hex(),16)))
|
||||
print("VHF Squelch Open RSSI Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e60+i,1).hex(),16)/2-160))
|
||||
print("VHF Squelch Close RSSI Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e70+i,1).hex(),16)/2-160))
|
||||
print("VHF Squelch Open Noise Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e80+i,1).hex(),16)))
|
||||
print("VHF Squelch Close Noise Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1e90+i,1).hex(),16)))
|
||||
print("VHF Squelch Close Glitch Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1ea0+i,1).hex(),16)))
|
||||
print("VHF Squelch Open Glitch Thresholds:")
|
||||
for i in range(10):
|
||||
print("SQL " + str(i) + ": " + str(int(radio.get_cfg_mem(0x1eb0+i,1).hex(),16)))
|
45
Software/Squelch Table Read & Write/squelch_table_write.py
Normal file
45
Software/Squelch Table Read & Write/squelch_table_write.py
Normal file
@ -0,0 +1,45 @@
|
||||
import libuvk5
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
# Handle arguments
|
||||
if len(sys.argv) not in [2,3]: print(f'Usage: {os.path.basename(sys.argv[0])} <COMx> <address> <hex_payload>') ; exit(1)
|
||||
|
||||
arg_port = sys.argv[1]
|
||||
|
||||
# Defaults taken from my radio
|
||||
# To get from RSSI to the byte value, use the following formula:
|
||||
# byte_value = (rssi + 160) / 2
|
||||
uhf_squelch_open_rssi = bytearray([0x0a,0x35,0x53,0x56,0x59,0x5c,0x5f,0x62,0x64,0x66,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
uhf_squelch_close_rssi = bytearray([0x05,0x30,0x50,0x53,0x56,0x59,0x5c,0x5f,0x62,0x64,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
uhf_squelch_open_noise = bytearray([0x5a,0x2a,0x29,0x26,0x23,0x20,0x1d,0x1a,0x17,0x14,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
uhf_squelch_close_noise = bytearray([0x64,0x2f,0x2d,0x29,0x26,0x23,0x20,0x1d,0x1a,0x17,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
uhf_squelch_close_glitch = bytearray([0x5a,0x12,0x11,0x0e,0x0b,0x08,0x03,0x02,0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
uhf_squelch_open_glitch = bytearray([0x64,0x10,0x0e,0x0b,0x08,0x05,0x05,0x04,0x04,0x04,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_open_rssi = bytearray([0x32,0x58,0x6b,0x6e,0x6f,0x72,0x75,0x77,0x79,0x7b,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_close_rssi = bytearray([0x28,0x54,0x67,0x6a,0x6c,0x6e,0x71,0x73,0x76,0x78,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_open_noise = bytearray([0x41,0x32,0x2d,0x28,0x24,0x21,0x1e,0x1a,0x17,0x16,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_close_noise = bytearray([0x46,0x39,0x32,0x2d,0x28,0x25,0x22,0x1e,0x1b,0x19,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_close_glitch = bytearray([0x5a,0x12,0x0f,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
vhf_squelch_open_glitch = bytearray([0x64,0x1e,0x14,0x0f,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0xff,0xff,0xff,0xff,0xff,0xff])
|
||||
|
||||
|
||||
|
||||
# Connect and read
|
||||
with libuvk5.uvk5(arg_port) as radio:
|
||||
if radio.connect():
|
||||
_=radio.get_fw_version() #mandatory before reading mem
|
||||
radio.set_cfg_mem(0x1e00,uhf_squelch_open_rssi).hex()
|
||||
radio.set_cfg_mem(0x1e10,uhf_squelch_close_rssi).hex()
|
||||
radio.set_cfg_mem(0x1e20,uhf_squelch_open_noise).hex()
|
||||
radio.set_cfg_mem(0x1e30,uhf_squelch_close_noise).hex()
|
||||
radio.set_cfg_mem(0x1e40,uhf_squelch_close_glitch).hex()
|
||||
radio.set_cfg_mem(0x1e50,uhf_squelch_open_glitch).hex()
|
||||
radio.set_cfg_mem(0x1e60,vhf_squelch_open_rssi).hex()
|
||||
radio.set_cfg_mem(0x1e70,vhf_squelch_close_rssi).hex()
|
||||
radio.set_cfg_mem(0x1e80,vhf_squelch_open_noise).hex()
|
||||
radio.set_cfg_mem(0x1e90,vhf_squelch_close_noise).hex()
|
||||
radio.set_cfg_mem(0x1ea0,vhf_squelch_close_glitch).hex()
|
||||
radio.set_cfg_mem(0x1eb0,vhf_squelch_open_glitch).hex()
|
||||
|
Loading…
Reference in New Issue
Block a user