kopia lustrzana https://github.com/OpenRTX/OpenRTX
Embedded OpenGD77 wrapping and flashing scripts
rodzic
75eac13001
commit
f2f7f6dd51
|
@ -385,8 +385,8 @@ targets = [
|
|||
|
||||
objcopy = find_program('objcopy', required:false, disabler:true)
|
||||
radio_tool = find_program('radio_tool', required:false, disabler:true)
|
||||
bin2sgl = find_program('bin2sgl.Linux', required:false, disabler:true)
|
||||
gd77_loader = find_program('gd-77_firmware_loader.py', required:false, disabler:true)
|
||||
bin2sgl = find_program('scripts/bin2sgl.Linux', required:false, disabler:true)
|
||||
gd77_loader = find_program('scripts/gd-77_firmware_loader.py', required:false, disabler:true)
|
||||
|
||||
foreach t : targets
|
||||
|
||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,619 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
################################################################################################################################################
|
||||
#
|
||||
# GD-77 Firmware uploader. By Roger VK3KYY
|
||||
#
|
||||
#
|
||||
# This script has only been tested on Windows and Linux, it may or may not work on OSX
|
||||
#
|
||||
# On Windows,..
|
||||
# the driver the system installs for the GD-77, which is the HID driver, needs to be replaced by the LibUSB-win32 using Zadig
|
||||
# for USB device with idVendor=0x15a2, idProduct=0x0073
|
||||
# Once this driver is installed the CPS and official firmware loader will no longer work as they can't find the device
|
||||
# To use the CPS etc again, use the DeviceManager to uninstall the driver associated with idVendor=0x15a2, idProduct=0x0073 (this will appear as a libusb-win32 device)
|
||||
# Then unplug the GD-77 and reconnect, and the HID driver will be re-installed
|
||||
#
|
||||
#
|
||||
# On Linux, depending of you distro, you need to install a special udev rule to automatically unbind the USB HID device to usbhid driver.
|
||||
#
|
||||
#
|
||||
# You also need python3-usb, enum34 and urllib3
|
||||
#
|
||||
################################################################################################################################################
|
||||
|
||||
######################### Error codes #########################
|
||||
#
|
||||
# -1: Missing firmware file
|
||||
# -2: Wrong SGL file format
|
||||
# -3: Unencrypted firmware
|
||||
# -4: Firmware file is too large
|
||||
# -5: Unknown HT model type
|
||||
# -6: Command line parsing error
|
||||
# -7: Online download firmware location error
|
||||
# -8: Online download firmware binary error
|
||||
# -9: Online firmware download failure
|
||||
# -10: Firmare/HT mismatch
|
||||
# -99: Unsupported GD-77S (will be removed in the futur)
|
||||
#
|
||||
###############################################################
|
||||
|
||||
import usb
|
||||
import getopt, sys
|
||||
import ntpath
|
||||
import os.path
|
||||
from array import array
|
||||
import enum
|
||||
import urllib3
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
class SGLFormatOutput(enum.Enum):
|
||||
GD_77 = 0
|
||||
GD_77S = 1
|
||||
DM_1801 = 2
|
||||
RD_5R = 3
|
||||
UNKNOWN = 4
|
||||
|
||||
def __int__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
# Globals
|
||||
responseOK = [0x41]
|
||||
outputModes = ["GD-77", "GD-77S", "DM-1801", "RD-5R", "Unknown"]
|
||||
outputFormat = SGLFormatOutput.GD_77
|
||||
downloadedFW = ""
|
||||
|
||||
########################################################################
|
||||
# Utilities to dump hex for testing
|
||||
########################################################################
|
||||
def hexdump(buf):
|
||||
cbuf = ""
|
||||
for b in buf:
|
||||
cbuf = cbuf + "0x%0.2X " % ord(b)
|
||||
return cbuf
|
||||
|
||||
def hexdumpArray(buf):
|
||||
cbuf = ""
|
||||
for b in buf:
|
||||
cbuf = cbuf + "0x%0.2X " % b
|
||||
return cbuf
|
||||
|
||||
def hexdumpArray2(buf):
|
||||
cbuf = ""
|
||||
for b in buf:
|
||||
cbuf = cbuf + "%0.2X-" % b
|
||||
return cbuf[:-1]
|
||||
|
||||
def strdumpArray(buf):
|
||||
cbuf = ""
|
||||
for b in buf:
|
||||
cbuf = cbuf + chr(b)
|
||||
return cbuf
|
||||
|
||||
def downloadFirmware(downloadStable):
|
||||
url = "https://github.com/rogerclarkmelbourne/OpenGD77/releases"
|
||||
urlBase = "http://github.com"
|
||||
httpPool = urllib3.PoolManager()
|
||||
pattern = ""
|
||||
fwVersion = "UNKNOWN"
|
||||
fwVersionPatternFormat = r'/{}([0-9\.]+)/'
|
||||
urlFW = ""
|
||||
webContent = ""
|
||||
|
||||
print(" - " + "Try to download the firmware for your {} from the project page".format(outputModes[int(outputFormat)]))
|
||||
print(" - " + "Retrieve firmware location");
|
||||
|
||||
try:
|
||||
response = httpPool.request('GET', url)
|
||||
except urllib3.URLError as e:
|
||||
print("".format(e.reason))
|
||||
sys.exit(-7)
|
||||
|
||||
webContent = str(response.data)
|
||||
|
||||
if (outputFormat == SGLFormatOutput.GD_77):
|
||||
patternFormat = r'/rogerclarkmelbourne/OpenGD77/releases/download/{}([0-9\.]+)/OpenGD77\.sgl'
|
||||
elif (outputFormat == SGLFormatOutput.GD_77S):
|
||||
patternFormat = r'/rogerclarkmelbourne/OpenGD77/releases/download/{}([0-9\.]+)/OpenGD77S\.sgl'
|
||||
elif (outputFormat == SGLFormatOutput.DM_1801):
|
||||
patternFormat = r'/rogerclarkmelbourne/OpenGD77/releases/download/{}([0-9\.]+)/OpenDM1801\.sgl'
|
||||
elif (outputFormat == SGLFormatOutput.RD_5R):
|
||||
patternFormat = r'/rogerclarkmelbourne/OpenGD77/releases/download/{}([0-9\.]+)/OpenDM5R\.sgl'
|
||||
|
||||
pattern = patternFormat.format("R" if downloadStable == True else "D")
|
||||
fwVersionPattern = fwVersionPatternFormat.format("R" if downloadStable == True else "D")
|
||||
contentArray = webContent.split("\n")
|
||||
|
||||
for l in contentArray:
|
||||
m = re.search(pattern, l)
|
||||
if (m != None):
|
||||
urlFW = urlBase + m.group(0)
|
||||
|
||||
m = re.search(fwVersionPattern, urlFW)
|
||||
if (m != None):
|
||||
fwVersion = m.group(0).strip('/')
|
||||
|
||||
break
|
||||
|
||||
if (len(urlFW)):
|
||||
global downloadedFW
|
||||
downloadedFW = os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + '.sgl')
|
||||
|
||||
print(" - " + "Downloading the firmware version {}, please wait".format(fwVersion));
|
||||
|
||||
try:
|
||||
response = httpPool.request('GET', urlFW, preload_content=False)
|
||||
except urllib3.URLError as e:
|
||||
print("".format(e.reason))
|
||||
sys.exit(-8)
|
||||
|
||||
length = response.getheader('content-length')
|
||||
|
||||
if (length != None):
|
||||
length = int(length)
|
||||
blocksize = max(4096, (length//100))
|
||||
else:
|
||||
blocksize = 4096
|
||||
|
||||
# Download data
|
||||
with open(downloadedFW, "w+b") as f:
|
||||
while True:
|
||||
data = response.read(blocksize)
|
||||
|
||||
if not data:
|
||||
break
|
||||
|
||||
f.write(data)
|
||||
f.close()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
########################################################################
|
||||
# Send the data packet to the GD-77 and return response
|
||||
########################################################################
|
||||
def sendAndGetResponse(dev, cmd):
|
||||
USB_WRITE_ENDPOINT = 0x02
|
||||
USB_READ_ENDPOINT = 0x81
|
||||
TRANSFER_LENGTH = 38
|
||||
headerData = [0x0] * 4
|
||||
|
||||
headerData[0] = 1
|
||||
headerData[1] = 0
|
||||
headerData[2] = ((len(cmd) >> 0) & 0xff)
|
||||
headerData[3] = ((len(cmd) >> 8) & 0xff)
|
||||
|
||||
cmd = headerData + cmd
|
||||
|
||||
#print("TX: " + hexdumpArray2(cmd))
|
||||
#print("TX: '{}'".format(strdumpArray(cmd[4:])))
|
||||
|
||||
ret = dev.write(USB_WRITE_ENDPOINT, cmd)
|
||||
ret = dev.read(USB_READ_ENDPOINT, TRANSFER_LENGTH + 4, 5000)
|
||||
|
||||
#print("RX: " + hexdumpArray2(ret[4:]))
|
||||
#print("RX: '{}'".format(strdumpArray(ret[4:])))
|
||||
|
||||
return ret[4:]
|
||||
|
||||
########################################################################
|
||||
# Send the data packet to the GD-77 and confirm the response is correct
|
||||
########################################################################
|
||||
def sendAndCheckResponse(dev, cmd, resp):
|
||||
USB_WRITE_ENDPOINT = 0x02
|
||||
USB_READ_ENDPOINT = 0x81
|
||||
TRANSFER_LENGTH = 38
|
||||
zeroPad = [0x0] * TRANSFER_LENGTH
|
||||
headerData = [0x0] * 4
|
||||
|
||||
headerData[0] = 1
|
||||
headerData[1] = 0
|
||||
headerData[2] = ((len(cmd) >> 0) & 0xff)
|
||||
headerData[3] = ((len(cmd) >> 8) & 0xff)
|
||||
|
||||
if (len(resp) < TRANSFER_LENGTH):
|
||||
resp = resp + zeroPad[0:TRANSFER_LENGTH - len(resp)]
|
||||
|
||||
cmd = headerData + cmd
|
||||
|
||||
#print("TX: " + hexdumpArray2(cmd))
|
||||
#print("TX: '{}'".format(strdumpArray(cmd[4:])))
|
||||
|
||||
ret = dev.write(USB_WRITE_ENDPOINT, cmd)
|
||||
ret = dev.read(USB_READ_ENDPOINT, TRANSFER_LENGTH + 4, 5000)
|
||||
expected = array("B", resp)
|
||||
|
||||
#print("RX: " + hexdumpArray2(ret[4:]))
|
||||
#print("RX: '{}'".format(strdumpArray(ret[4:])))
|
||||
|
||||
if (expected == ret[4:]):
|
||||
return True
|
||||
else:
|
||||
print("Error. Read returned: " + str(ret))
|
||||
return False
|
||||
|
||||
|
||||
##############################
|
||||
# Create checksum data packet
|
||||
##############################
|
||||
def createChecksumData(buf, startAddress, endAddress):
|
||||
#checksum data starts with a small header, followed by the 32 bit checksum value, least significant byte first
|
||||
checkSumData = [ 0x45, 0x4e, 0x44, 0xff, 0xDE, 0xAD, 0xBE, 0xEF ]
|
||||
cs = 0
|
||||
|
||||
for i in range(startAddress, endAddress):
|
||||
cs = cs + buf[i]
|
||||
|
||||
checkSumData[4] = (cs % 256) & 0xff
|
||||
checkSumData[5] = ((cs >> 8) % 256) & 0xff
|
||||
checkSumData[6] = ((cs >> 16) % 256) & 0xff
|
||||
checkSumData[7] = ((cs >> 24) % 256) & 0xff
|
||||
return checkSumData
|
||||
|
||||
|
||||
def updateBlockAddressAndLength(buf, address, length):
|
||||
buf[5] = ((length) % 256) & 0xff
|
||||
buf[4] = ((length >> 8) % 256) & 0xff
|
||||
buf[3] = ((address) % 256) & 0xff
|
||||
buf[2] = ((address >> 8) % 256) & 0xff
|
||||
buf[1] = ((address >> 16) % 256) & 0xff
|
||||
buf[0] = ((address >> 24) % 256) & 0xff
|
||||
return buf
|
||||
|
||||
|
||||
#####################################################
|
||||
# Open firmware file on disk and sent it to the GD-77
|
||||
###########################################b##########
|
||||
def sendFileData(fileBuf, dev):
|
||||
dataHeader = [0x00] * (0x20 + 0x06)
|
||||
BLOCK_LENGTH = 1024 #1k
|
||||
DATA_TRANSFER_SIZE = 0x20
|
||||
checksumStartAddress = 0
|
||||
address = 0
|
||||
|
||||
fileLength = len(fileBuf)
|
||||
totalBlocks = (fileLength // BLOCK_LENGTH) + 1
|
||||
|
||||
while address < fileLength:
|
||||
if ((address % BLOCK_LENGTH) == 0):
|
||||
checksumStartAddress = address
|
||||
|
||||
dataHeader = updateBlockAddressAndLength(dataHeader, address, DATA_TRANSFER_SIZE)
|
||||
|
||||
if ((address + DATA_TRANSFER_SIZE) < fileLength):
|
||||
|
||||
for i in range(DATA_TRANSFER_SIZE):
|
||||
dataHeader[6 + i] = fileBuf[address + i]
|
||||
|
||||
if (sendAndCheckResponse(dev, dataHeader, responseOK) == False):
|
||||
print("Error sending data")
|
||||
return False
|
||||
break
|
||||
|
||||
address = address + DATA_TRANSFER_SIZE
|
||||
|
||||
if ((address % 0x400) == 0):
|
||||
print("\r - Sent block " + str(address // BLOCK_LENGTH) + " of "+ str(totalBlocks), end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
if (sendAndCheckResponse(dev, createChecksumData(fileBuf, checksumStartAddress, address), responseOK) == False):
|
||||
print("Error sending checksum")
|
||||
return False
|
||||
break
|
||||
|
||||
else:
|
||||
print("\r - Sending last block ", end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
DATA_TRANSFER_SIZE = fileLength - address
|
||||
|
||||
dataHeader = updateBlockAddressAndLength(dataHeader, address, DATA_TRANSFER_SIZE)
|
||||
|
||||
for i in range(DATA_TRANSFER_SIZE):
|
||||
dataHeader[6 + i] = fileBuf[address + i]
|
||||
|
||||
if (sendAndCheckResponse(dev, dataHeader, responseOK) == False):
|
||||
print("Error sending data")
|
||||
return False
|
||||
break
|
||||
|
||||
address = address + DATA_TRANSFER_SIZE
|
||||
|
||||
if (sendAndCheckResponse(dev, createChecksumData(fileBuf, checksumStartAddress, address), responseOK) == False):
|
||||
print("Error sending checksum")
|
||||
return False
|
||||
break
|
||||
|
||||
print("")
|
||||
return True
|
||||
|
||||
#####################################################
|
||||
# Probe connected model
|
||||
###########################################b##########
|
||||
def probeModel(dev):
|
||||
commandLetterA = [ 0x41 ] # 'A'
|
||||
command0 = [[ 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44 ], [ 0x23, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x3f ]] # 'DOWNLOAD'
|
||||
command1 = [ commandLetterA, responseOK ]
|
||||
commandDummy = [ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ]
|
||||
#commandMOD = [ 0x46, 0x2D, 0x4D, 0x4F, 0x44, 0xff, 0xff, 0xff ] # F-MOD...
|
||||
#commandEND = [ 0x45, 0x4E, 0x44, 0xFF ] # END.
|
||||
commandID = [ command0, command1 ]
|
||||
models = [[ 'DV01', SGLFormatOutput.GD_77 ], [ 'DV02', SGLFormatOutput.GD_77S ], [ 'DV03', SGLFormatOutput.DM_1801 ]]
|
||||
# RD-5R also have "DV02" id
|
||||
|
||||
commandNumber = 0
|
||||
while commandNumber < len(commandID):
|
||||
if sendAndCheckResponse(dev, commandID[commandNumber][0], commandID[commandNumber][1]) == False:
|
||||
return SGLFormatOutput.UNKNOWN
|
||||
commandNumber = commandNumber + 1
|
||||
|
||||
resp = sendAndGetResponse(dev, commandDummy)
|
||||
##dummy = sendAndGetResponse(dev, command0[0])
|
||||
|
||||
for x in models:
|
||||
if (x[0] == str(resp[:4].tobytes().decode("ascii"))):
|
||||
return x[1]
|
||||
|
||||
return SGLFormatOutput.UNKNOWN
|
||||
|
||||
###########################################################################################################################################
|
||||
# Send commands to the GD-77 to verify we are the updater, prepare to program including erasing the internal program flash memory
|
||||
###########################################################################################################################################
|
||||
def sendInitialCommands(dev, encodeKey):
|
||||
commandLetterA =[ 0x41] #A
|
||||
command0 =[[0x44,0x4f,0x57,0x4e,0x4c,0x4f,0x41,0x44],[0x23,0x55,0x50,0x44,0x41,0x54,0x45,0x3f]] # DOWNLOAD
|
||||
command1 =[commandLetterA,responseOK]
|
||||
command3 =[[0x46, 0x2d, 0x50, 0x52, 0x4f, 0x47, 0xff, 0xff],responseOK] #... F-PROG..
|
||||
|
||||
if (outputFormat == SGLFormatOutput.GD_77):
|
||||
command2 =[[0x44, 0x56, 0x30, 0x31, (0x61 + 0x00), (0x61 + 0x0C), (0x61 + 0x0D), (0x61 + 0x01)],[0x44, 0x56, 0x30, 0x31]] #.... DV01enhi (DV01enhi comes from deobfuscated sgl file)
|
||||
command4 =[[0x53, 0x47, 0x2d, 0x4d, 0x44, 0x2d, 0x37, 0x36, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],responseOK] #SG-MD-760
|
||||
command5 =[[0x4d, 0x44, 0x2d, 0x37, 0x36, 0x30, 0xff, 0xff],responseOK] #MD-760..
|
||||
elif (outputFormat == SGLFormatOutput.GD_77S):
|
||||
command2 =[[0x44, 0x56, 0x30, 0x32, 0x6D, 0x40, 0x7D, 0x63],[0x44, 0x56, 0x30, 0x32]] #.... DV02Gpmj (thanks Wireshark)
|
||||
command4 =[[0x53, 0x47, 0x2d, 0x4d, 0x44, 0x2d, 0x37, 0x33, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],responseOK] #SG-MD-730
|
||||
command5 =[[0x4d, 0x44, 0x2d, 0x37, 0x33, 0x30, 0xff, 0xff],responseOK] #MD-730..
|
||||
elif (outputFormat == SGLFormatOutput.DM_1801):
|
||||
command2 =[[0x44, 0x56, 0x30, 0x33, 0x74, 0x21, 0x44, 0x39],[0x44, 0x56, 0x30, 0x33]] #.... last 4 bytes of the command are the offset encoded as letters a - p (hard coded fr
|
||||
command4 =[[0x42, 0x46, 0x2d, 0x44, 0x4d, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],responseOK] #BF-DMR
|
||||
command5 =[[0x31, 0x38, 0x30, 0x31, 0xff, 0xff, 0xff, 0xff],responseOK] # MD-1801
|
||||
elif (outputFormat == SGLFormatOutput.RD_5R):
|
||||
command2 =[[0x44, 0x56, 0x30, 0x32, 0x53, 0x36, 0x37, 0x62],[0x44, 0x56, 0x30, 0x32]] #.... last 4 bytes of the command are the offset encoded as letters a - p (hard coded fr
|
||||
command4 =[[0x42, 0x46, 0x2D, 0x35, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],responseOK] #BF-5R
|
||||
command5 =[[0x42, 0x46, 0x2D, 0x35, 0x52, 0xff, 0xff, 0xff],responseOK] # BF-5R
|
||||
|
||||
command6 =[[0x56, 0x31, 0x2e, 0x30, 0x30, 0x2e, 0x30, 0x31],responseOK] #V1.00.01
|
||||
commandErase =[[0x46, 0x2d, 0x45, 0x52, 0x41, 0x53, 0x45, 0xff],responseOK] #F-ERASE
|
||||
commandPostErase =[commandLetterA,responseOK]
|
||||
commandProgram =[[0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0xf],responseOK] #PROGRAM
|
||||
commands =[command0,command1,command2,command3,command4,command5,command6,commandErase,commandPostErase,commandProgram]
|
||||
commandNames =["Sending Download command", "Sending ACK", "Sending encryption key", "Sending F-PROG command", "Sending radio modem number", "Sending radio modem number 2", "Sending version", "Sending erase command", "Send post erase command", "Sending Program command"]
|
||||
commandNumber = 0
|
||||
|
||||
# Buffer.BlockCopy(encodeKey, 0, command2[0], 4, 4);
|
||||
command2[0] = command2[0][0:4] + encodeKey
|
||||
|
||||
# Send the commands which the GD-77 expects before the start of the data
|
||||
while commandNumber < len(commands):
|
||||
print(" - " + commandNames[commandNumber])
|
||||
|
||||
if sendAndCheckResponse(dev, commands[commandNumber][0], commands[commandNumber][1]) == False:
|
||||
print("Error sending command")
|
||||
return False
|
||||
break
|
||||
commandNumber = commandNumber + 1
|
||||
return True
|
||||
|
||||
###########################################################################################################################################
|
||||
#
|
||||
###########################################################################################################################################
|
||||
def checkForSGLAndReturnEncryptedData(fileBuf):
|
||||
header_tag = list("SGL!")
|
||||
headerModel = []
|
||||
|
||||
buf_in_4 = list("".join(map(chr, fileBuf[0:4])))
|
||||
headerModel.append(fileBuf[11])
|
||||
|
||||
if buf_in_4 == header_tag:
|
||||
# read and decode offset and xor tag
|
||||
buf_in_4 = list(fileBuf[0x000C : 0x000C + 4])
|
||||
|
||||
for i in range(0, 4):
|
||||
buf_in_4[i] = buf_in_4[i] ^ ord(header_tag[i])
|
||||
|
||||
offset = buf_in_4[0] + 256 * buf_in_4[1]
|
||||
xor_data = [ buf_in_4[2], buf_in_4[3] ]
|
||||
|
||||
# read and decode part of the header
|
||||
buf_in_512 = list(fileBuf[offset + 0x0006 : offset + 0x0006 + 512])
|
||||
|
||||
xor_idx = 0;
|
||||
for i in range(0, 512):
|
||||
buf_in_512[i] = buf_in_512[i] ^ xor_data[xor_idx]
|
||||
|
||||
xor_idx += 1
|
||||
if xor_idx == 2:
|
||||
xor_idx = 0
|
||||
|
||||
#
|
||||
encodeKey = buf_in_512[0x005D : 0x005D + 4]
|
||||
|
||||
# extract length
|
||||
length1 = buf_in_512[0x0000]
|
||||
length2 = buf_in_512[0x0001]
|
||||
length3 = buf_in_512[0x0002]
|
||||
length4 = buf_in_512[0x0003]
|
||||
length = (length4 << 24) + (length3 << 16) + (length2 << 8) + length1
|
||||
|
||||
# extract encoded raw firmware
|
||||
retBuf = [0x00] * length;
|
||||
retBuf = fileBuf[len(fileBuf) - length : len(fileBuf) - length + len(retBuf) ]
|
||||
|
||||
return retBuf, encodeKey, headerModel
|
||||
|
||||
print("ERROR: SGL! header is missing.")
|
||||
return None, None, None
|
||||
|
||||
###########################################################################################################################################
|
||||
#
|
||||
###########################################################################################################################################
|
||||
def usage():
|
||||
print("Usage:")
|
||||
print(" " + ntpath.basename(sys.argv[0]) + " [OPTION]")
|
||||
print("")
|
||||
print(" -h, --help : Display this help text")
|
||||
print(" -f, --firmware=<filename.sgl> : Flash <filename.sgl> instead of default file \"firmware.sgl\"")
|
||||
print(" -m, --model=<type> : Select transceiver model. Models are: {}".format(", ".join(str(x) for x in outputModes[:-1])) + ".")
|
||||
print(" -d, --download : Download firmware from the project website")
|
||||
print(" -S, --stable : Select the stable version while downloading from the project page")
|
||||
print(" -U, --unstable : Select the development version while downloading from the project page")
|
||||
print("")
|
||||
|
||||
#####################################################
|
||||
# Main function.
|
||||
#####################################################
|
||||
def main():
|
||||
global outputFormat
|
||||
sglFile = "firmware.sgl"
|
||||
downloadStable = True
|
||||
doDownload = False
|
||||
doForce = False
|
||||
|
||||
# Command line argument parsing
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "hf:m:dSUF", ["help", "firmware=", "model=", "download", "stable", "unstable", "force"])
|
||||
except getopt.GetoptError as err:
|
||||
print(str(err))
|
||||
usage()
|
||||
sys.exit(-6)
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt in ("-h", "--help"):
|
||||
usage()
|
||||
sys.exit(0)
|
||||
elif opt in ("-f", "--firmware"):
|
||||
sglFile = arg
|
||||
elif opt in ("-m", "--model"):
|
||||
try:
|
||||
index = outputModes.index(arg)
|
||||
except ValueError as e:
|
||||
print("Model \"{}\" is unknown".format(arg))
|
||||
sys.exit(-5)
|
||||
|
||||
outputFormat = SGLFormatOutput(index)
|
||||
|
||||
if (outputFormat == SGLFormatOutput.UNKNOWN):
|
||||
print("Unsupported model")
|
||||
sys.exit(-5)
|
||||
|
||||
elif opt in ["-d", "--download"]:
|
||||
doDownload = True
|
||||
elif opt in ["-S", "--stable"]:
|
||||
downloadStable = True
|
||||
elif opt in ["-U", "--unstable"]:
|
||||
downloadStable = False
|
||||
elif opt in ["-F", "--force"]:
|
||||
doForce = True
|
||||
else:
|
||||
assert False, "Unhandled option"
|
||||
|
||||
# Try to connect USB device
|
||||
dev = usb.core.find(idVendor=0x15a2, idProduct=0x0073)
|
||||
if (dev):
|
||||
# Needed on Linux
|
||||
try:
|
||||
if dev.is_kernel_driver_active(0):
|
||||
dev.detach_kernel_driver(0)
|
||||
except NotImplementedError as e:
|
||||
pass
|
||||
|
||||
#seems to be needed for the usb to work !
|
||||
dev.set_configuration()
|
||||
|
||||
if (outputFormat == SGLFormatOutput.UNKNOWN):
|
||||
outputFormat = probeModel(dev)
|
||||
if (outputFormat == SGLFormatOutput.UNKNOWN):
|
||||
print("Error. Failed to detect you transceiver model.")
|
||||
sys.exit(-5)
|
||||
print(" - Detected model: {}".format(outputModes[int(outputFormat)]))
|
||||
|
||||
# Try to download the firmware
|
||||
if (doDownload == True):
|
||||
if (downloadFirmware(downloadStable) == True):
|
||||
sglFile = downloadedFW
|
||||
else:
|
||||
print("Firmware download failed")
|
||||
sys.exit(-9)
|
||||
|
||||
if (os.path.isfile(sglFile) == False):
|
||||
print("Firmware file \"" + sglFile + "\" is missing.")
|
||||
sys.exit(-1)
|
||||
|
||||
print(" - " + "Now flashing your {} with \"{}\"".format(outputModes[int(outputFormat)], sglFile))
|
||||
|
||||
with open(sglFile, 'rb') as f:
|
||||
fileBuf = f.read()
|
||||
|
||||
# Check firmware
|
||||
filename, file_extension = os.path.splitext(sglFile)
|
||||
|
||||
# Define encodeKey according to HT model
|
||||
if (outputFormat == SGLFormatOutput.GD_77):
|
||||
encodeKey = [ (0x61 + 0x00), (0x61 + 0x0C), (0x61 + 0x0D), (0x61 + 0x01) ]
|
||||
elif (outputFormat == SGLFormatOutput.GD_77S):
|
||||
encodeKey = [ (0x6D), (0x40), (0x7D), (0x63) ] ## Original header (smaller filelength): was (0x47), (0x70), (0x6d), (0x4a)
|
||||
elif (outputFormat == SGLFormatOutput.DM_1801):
|
||||
encodeKey = [ (0x74), (0x21), (0x44), (0x39) ]
|
||||
elif (outputFormat == SGLFormatOutput.RD_5R):
|
||||
encodeKey = [ (0x53), (0x36), (0x37), (0x62) ]
|
||||
|
||||
if (file_extension == ".sgl"):
|
||||
firmwareModelTag = { SGLFormatOutput.GD_77: 0x1B , SGLFormatOutput.GD_77S: 0x70, SGLFormatOutput.DM_1801: 0x4F, SGLFormatOutput.RD_5R: 0x5C}
|
||||
|
||||
## Could be a SGL file !
|
||||
fileBuf, encodeKey, headerModel = checkForSGLAndReturnEncryptedData(fileBuf)
|
||||
|
||||
if (fileBuf == None):
|
||||
print("Error. Missing SGL in .sgl file header")
|
||||
sys.exit(-2)
|
||||
|
||||
print(" - " + "Firmware file confirmed as SGL")
|
||||
|
||||
if (doForce == False):
|
||||
# Check if the firmware matches the transceiver model
|
||||
if (headerModel[0] != firmwareModelTag[outputFormat]):
|
||||
print("Error. The firmware doesn't match the transceiver model.")
|
||||
sys.exit(-10)
|
||||
|
||||
else:
|
||||
print("Firmware file is an unencrypted binary. Exiting")
|
||||
sys.exit(-3)
|
||||
|
||||
if len(fileBuf) > 0x7b000:
|
||||
print("Error. Firmware file too large.")
|
||||
sys.exit(-4)
|
||||
|
||||
if (sendInitialCommands(dev, encodeKey) == True):
|
||||
if (sendFileData(fileBuf, dev) == True):
|
||||
print("Firmware update complete. Please reboot the {}.".format(outputModes[int(outputFormat)]))
|
||||
else:
|
||||
print("Error while sending data")
|
||||
else:
|
||||
print("Error while sending initial commands")
|
||||
|
||||
usb.util.dispose_resources(dev) #free up the USB device
|
||||
|
||||
else:
|
||||
print("Error. Can't find your transceiver.")
|
||||
|
||||
# Remove downloaded firmware, if any
|
||||
if (len(downloadedFW)):
|
||||
if (os.path.isfile(downloadedFW)):
|
||||
os.remove(downloadedFW)
|
||||
|
||||
|
||||
## Run the program
|
||||
main()
|
||||
sys.exit(0)
|
Ładowanie…
Reference in New Issue