You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.2 KiB
Python

#!/usr/bin/env python3
#Copyright 2021 @ github.com/catSIXe
import time
import serial
import binascii
class TPLBirdySlim:
port = None
def __init__(self, serialPortName):
self.port = serial.Serial(
port=serialPortName,
baudrate=57600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=30,
xonxoff=False,
rtscts=False,
dsrdtr=False
)
print(self.port.name)
if self.port.is_open:
self.port.close()
self.port.open()
self.port.reset_input_buffer()
self.port.reset_output_buffer()
def _changeBaudrate(self, newRate):
if self.port.is_open:
self.port.close()
self.port.baudrate = newRate
self.port.open()
self.port.reset_input_buffer()
self.port.reset_output_buffer()
def checksum(self, data):
cs = 0x00
for x in data:
cs = (cs + x % 256) & 0xFF
return cs & 0xFF
def sendCMD(self, data):
cmd = []
cmd.append(0x02)
cmd.append(len(data))
cmd.extend(data)
cmd.append(0x03)
cmd.append(self.checksum(cmd.copy()))
cmd.append(0x04)
print(">", binascii.hexlify(bytes(cmd)))
self.port.write(cmd)
self.port.flush()
def readSingleByte(self):
return int.from_bytes(self.port.read(1), 'little')
def wait4Response(self):
#first Byte is always 0x02
if self.readSingleByte() != 0x02:
return None
dataLength = self.readSingleByte()
reply = []
for x in range(dataLength):
reply.append(self.readSingleByte())
if self.readSingleByte() != 0x03:
return None
pCRC = self.readSingleByte()
pCRCData = [0x02, dataLength]
pCRCData.extend(reply)
pCRCData.extend([0x03])
rCRC = self.checksum(pCRCData)
if self.readSingleByte() != 0x04:
return None
if pCRC != rCRC:
return None # crc mismatch
return reply
def askHighspeed(self):
self.sendCMD([0x25,0x01])
return self.wait4Response()
def switchToHighspeed(self):
resp = self.askHighspeed()
if len(resp) == 1 and resp[0] == 0x06:
self._changeBaudrate(115200)
return True
else:
return False
def readE2P(self, addr, size=0x80):
_addr = addr.to_bytes(2, byteorder='big')
_cmd = [0x29, 0x00, 0x00, _addr[0], _addr[1], size]
self.sendCMD(_cmd)
resp = self.wait4Response()
print(">", binascii.hexlify(bytes(resp)))
if resp[0:5] != _cmd[0:5]:
print(resp[0:5], _cmd[0:5])
return None # mismatch
return resp[5:]
def writeE2P(self, addr, data):
_addr = addr.to_bytes(2, byteorder='big')
_cmd = [0x2A, 0x00, 0x00, _addr[0], _addr[1]]
_cmd.extend(data)
self.sendCMD(_cmd)
resp = self.wait4Response()
if resp[0:4] != _cmd[0:4]:
print("resp mismatch", resp, _cmd)
return False # mismatch
if resp[5] != len(data):
print("length mismatch")
return False # mismatch
if resp[6:] != _cmd[5:]:
print("resp mismatch", resp, _cmd)
return False # mismatch
return True
#def boskrypt_mode(self):
# self.sendCMD([0xF3,0xF3])
def getDeviceInfo(self):
self.sendCMD([0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff])
return self.wait4Response()
def writeSerialNumber(self, newSerial):
_cmd = [0x13]
_cmd.extend(newSerial)
self.sendCMD(_cmd)
resp = self.wait4Response()
if _cmd[2:] != resp[2:]:
return False
return True
def checkE2PData(self, data):
return len(data) / 0x80 == 0xCD
test = TPLBirdySlim('/dev/ttyUSB0')
#test.switchBootloaderSpeed()
#test._changeBaudrate(38700)
#print(bytes(test.getDeviceInfo()).decode('ascii'))
#test.sendCMD([0x01,0x12])
#test.sendCMD([0x18,0x08])
#test.sendCMD([0x10,0x08])
#print(bytes(test.wait4Response()))
#test.writeSerialNumber([0x42,0x36,0x31,0x33,0x33,0x37,0x31,0x33,0x33,0x37,0x31,0x33,0x33,0x37])
#print(bytes(test.getDeviceInfo()).decode('ascii'))
#test.sendCMD([0x13,0x43,0x48,0x45,0x45,0x54,0x41,0x48,0x43,0x48,0x45,0x45,0x54,0x41,0x48])
#print(
test.switchToHighspeed()
#)
"""
e2pread = []
for i in range(0xCD):
e2pread.extend(test.readE2P(i*0x80))
with open("dump_434_232500.bin", "wb") as e2pfile:
e2pfile.write(bytes(e2pread))
"""
e2pdata = []
#with open("BrainwvaebusinessDefualt.birdyIOT.rev2.bin", "rb") as e2pfile:
with open("dump2.bin", "rb") as e2pfile:
e2pdata = e2pfile.read()
if test.checkE2PData(e2pdata):
for i in range(0xCD):
chunk = e2pdata[ 0x80*i : 0x80*(i+1) ]
print(test.writeE2P(i*0x80, chunk))
#print(e2pdata)
#print(test.port.read(62))