From da2cb7bc2f5caa76db3600e1e1fe52cfac542a18 Mon Sep 17 00:00:00 2001 From: pvvx Date: Thu, 28 Dec 2023 09:28:09 +0300 Subject: [PATCH] add backup info --- README.md | 19 +++ WrFlash_phy6222.py | 359 +++++++++++++++++++++++++++++++++++++++++++++ rdreg_phy6222.py | 200 +++++++++++++++++++++++++ 3 files changed, 578 insertions(+) create mode 100644 WrFlash_phy6222.py create mode 100644 rdreg_phy6222.py diff --git a/README.md b/README.md index b1a72a1..b5e7544 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,22 @@ Custom firmware for Tuya [THB2](https://pvvx.github.io/THB2). Дополнительная информация по чипам [PHY62xx](https://github.com/pvvx/PHY62x2). +## Сохранение оригинальной прошивки. + +1. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). +2. Запустить: +``` +python3 rdreg_phy6222.py -p COM11 -b 1000000 0x11000000 0x80000 +``` +3. Полученный файл r11000000-00080000.bin сохранить. + +## Восстановление оригинальной прошивки. + +1. Взять сохраненный файл r11000000-00080000.bin оригинальной прошивки. +2. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). +3. Запустить: +``` +python3 WrFlash_phy6222.py -p COM11 -b 1000000 0 r11000000-00080000.bin +``` +4. Прошивка зашита. Сбросить устройство переключением питания. + diff --git a/WrFlash_phy6222.py b/WrFlash_phy6222.py new file mode 100644 index 0000000..a079e64 --- /dev/null +++ b/WrFlash_phy6222.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 + +# wrflash_phy6202.py 07.12.2019 pvvx # + +import serial; +import time; +import argparse +import os +import struct +import sys + +START_BAUD = 9600 +DEF_RUN_BAUD = 115200 +MAX_FLASH_SIZE = 0x200000 +EXT_FLASH_ADD = 0x400000 + +PHY_FLASH_SECTOR_SIZE = 4096 +PHY_FLASH_SECTOR_MASK = 0xfffff000 +PHY_WR_BLK_SIZE = 0x2000 + +__version__ = "28.12.23" + +class phyflasher: + def __init__(self, port='COM1'): + self.port = port + self.baud = START_BAUD + try: + self._port = serial.Serial(self.port, self.baud) + self._port.timeout = 1 + except: + print ('Error: Open %s, %d baud!' % (self.port, self.baud)) + sys.exit(1) + def SetAutoErase(self, enable = True): + self.autoerase = enable + def write_cmd(self, pkt): + print(pkt); + self._port.write(pkt.encode()); + read = self._port.read(6); + return read == b'#OK>>:' + def read_regb(self, addr): + pkt = 'rdreg%08x' % addr; + sent = self._port.write(pkt.encode()); + read = self._port.read(17); + if len(read) == 17 and read[0:3] == b'=0x' and read[11:17] == b'#OK>>:': + dw = struct.pack('>:': + return int(read[1:11], 16) + return None + def write_reg(self, addr, data): + pkt = 'wrreg%08x %08x ' % (addr, data); + self._port.write(pkt.encode()); + read = self._port.read(6); + return read == b'#OK>>:' + def ExpFlashSize(self): + if not self.write_reg(0x1fff0898, EXT_FLASH_ADD): + print('Error set ext.Flash size %08x!' % EXT_FLASH_ADD) + return False + return True + def wr_flash_cmd(self, cmd, data = 0, size = 0): + if size > 0: + if not self.write_reg(0x4000c8a8, data): #Flash Command Write Data Register + print('Error write Flash Data Register!') + return False + if not self.write_reg(0x4000c890, (cmd << 24) | (size <<15) | 1): + print('Error write Flash Command Register!') + return False + return True + def FlashUnlock(self): + #Flash cmd: Write Enable, Write Status Register 0x00 + return self.wr_flash_cmd(6) and self.wr_flash_cmd(1, 0, 1) + def ReadRevision(self): + #0x001364c8 6222M005 #OK>>: + self._port.write(str.encode('rdrev+ ')); + self._port.timeout = 0.1 + read = self._port.read(26); + if len(read) == 26 and read[0:2] == b'0x' and read[20:26] == b'#OK>>:': + print('Revision:', read[2:19]) + if read[11:15] != b'6222': + print('Wrong Version!') + self.flash_id = int(read[2:11], 16) + self.flash_size = 1 << ((self.flash_id >> 16) & 0xff) + print('FlashID: %06x, size: %d kbytes' % (self.flash_id, self.flash_size >> 10)) + return True + else: + print('Error read Revision!') + return False + def SetBaud(self, baud): + if self._port.baudrate != baud: + print ('Reopen %s port %i baud...' % (self.port, baud), end = ' '), + self._port.write(str.encode("uarts%i" % baud)); + self._port.timeout = 1 + read = self._port.read(3); + if read == b'#OK': + print ('ok') + self._port.close() + self.baud = baud + self._port.baudrate = baud + self._port.open(); + else: + print ('error!') + print ('Error set %i baud on %s port!' % (baud, self.port)) + self._port.close() + sys.exit(3) + return True + def Connect(self, baud=DEF_RUN_BAUD): + self._port.setDTR(True) #TM (lo) + self._port.setRTS(True) #RSTN (lo) + self._port.flushOutput() + self._port.flushInput() + time.sleep(0.2) + self._port.setDTR(False) #TM (hi) + self._port.flushOutput() + self._port.flushInput() + time.sleep(0.1) + self._port.setRTS(False) #RSTN (hi) + self._port.timeout = 0.04 + ttcl = 50; + pkt = 'UXTDWU' # UXTL16 UDLL48 UXTDWU + while ttcl > 0: + sent = self._port.write(pkt.encode()); + read = self._port.read(6); + if read == b'cmd>>:' : + break + ttcl = ttcl - 1 + if ttcl < 1: + print('PHY62x2 - Error Reset!') + print('Check connection TX->RX, RX<-TX and Chip Power!') + self._port.close() + exit(4) + print('PHY62x2 - Reset Ok') + self._port.close() + self._port.baudrate = DEF_RUN_BAUD + self._port.open(); + self._port.timeout = 0.2 + if not self.ReadRevision(): + self._port.close() + exit(4) + if not self.FlashUnlock(): + self._port.close() + exit(4) + if not self.ExpFlashSize(): + self._port.close() + exit(4) + if not self.write_reg(0x4000f054, 0): + print('PHY62x2 - Error init1!') + self._port.close() + exit(4) + if not self.write_reg(0x4000f140, 0): + print('PHY62x2 - Error init2!') + self._port.close() + exit(4) + if not self.write_reg(0x4000f144, 0): + print('PHY62x2 - Error init3!') + self._port.close() + exit(4) + print('PHY6222 - connected Ok') + return self.SetBaud(baud) + def cmd_era4k(self, offset): + print ('Erase sector Flash at 0x%08x...' % offset, end = ' ') + self._port.write(str.encode('era4k %X' % (offset | MAX_FLASH_SIZE))), + tmp = self._port.timeout + self._port.timeout = 0.5 + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + self._port.timeout = tmp + return True + def cmd_era64k(self, offset): + print ('Erase block 64k Flash at 0x%08x...' % offset, end = ' '), + self._port.write(str.encode('er64k %X' % (offset | MAX_FLASH_SIZE))) + tmp = self._port.timeout + self._port.timeout = 2 + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + self._port.timeout = tmp + return True + def cmd_er512(self, offset = 0): + print ('Erase block 512k Flash at 0x%08x...' % offset, end = ' '), + self._port.write(str.encode('er512 %X' % (offset | MAX_FLASH_SIZE))) + tmp = self._port.timeout + self._port.timeout = 2 + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + self._port.timeout = tmp + return True + def cmd_erase_all_chipf(self): + print ('Erase Flash work area...', end = ' '), + self._port.write(str.encode('erall ')) + tmp = self._port.timeout + self._port.timeout = 7 + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + self._port.timeout = tmp + return True + def cmd_erase_all_flash(self): + print ('Erase All Chip Flash...', end = ' '), + if self.wr_flash_cmd(6) and self.wr_flash_cmd(0x60): #Write Enable, Chip Erase + print ('ok') + return True + return False + def EraseSectorsFlash(self, offset = 0, size = MAX_FLASH_SIZE): + count = int((size + PHY_FLASH_SECTOR_SIZE - 1) / PHY_FLASH_SECTOR_SIZE) + offset &= PHY_FLASH_SECTOR_MASK + if count > 0 and count < 0x10000 and offset >= 0: # 1 byte .. 16 Mbytes + while count > 0: + if (offset & 0x7FFFF) == 0 and count > 127: + if not self.cmd_er512(offset): + return False + offset += 0x80000 + count-=128 + elif (offset & 0x0FFFF) == 0 and count > 15: + if not self.cmd_era64k(offset): + return False + offset += 0x10000 + count-=16 + else: + if not self.cmd_era4k(offset): + return False + offset += PHY_FLASH_SECTOR_SIZE + count-=1 + else: + return False + return True + def send_blk(self, stream, offset, size, blkcnt, blknum): + self._port.timeout = 1 + print ('Write 0x%08x bytes to Flash at 0x%08x...' % (size, offset), end = ' '), + if blknum == 0: + self._port.write(str.encode('cpnum %d ' % blkcnt)) + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + self._port.write(str.encode('cpbin c%d %X %X %X' % (blknum, offset | MAX_FLASH_SIZE, size, 0x1FFF0000 + offset))) + read = self._port.read(12) + if read != b'by hex mode:': + print ('error!') + return False + data = stream.read(size) + self._port.write(data) + read = self._port.read(23); #'checksum is: 0x00001d1e' + #print ('%s' % read), + if read[0:15] != b'checksum is: 0x': + print ('error!') + return False + self._port.write(read[15:]) + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + return True + def WriteBlockFlash(self, stream, offset = 0, size = 0x8000): + offset &= 0x00ffffff + if self.autoerase: + if not self.EraseSectorsFlash(offset, size): + return False + sblk = PHY_WR_BLK_SIZE + blkcount = (size + sblk - 1) / sblk + blknum = 0 + while(size > 0): + if size < sblk: + sblk = size + if not self.send_blk(stream, offset, sblk, blkcount, blknum): + return False + blknum+=1 + offset+=sblk + size-=sblk + return True + +class FatalError(RuntimeError): + def __init__(self, message): + RuntimeError.__init__(self, message) + + @staticmethod + def WithResult(message, result): + message += " (result was %s)" % hexify(result) + return FatalError(message) + +def arg_auto_int(x): + return int(x, 0) + +def main(): + parser = argparse.ArgumentParser(description='WrFlash-PHY6222 Utility version %s' % __version__, prog='WrFlash_phy6222') + parser.add_argument('--port', '-p', help='Serial port device', default='COM1'); + parser.add_argument('--baud', '-b', help='Set Port Baud (115200, 250000, 500000, 1000000)', type=arg_auto_int, default=DEF_RUN_BAUD); + parser.add_argument('--erase', '-e', action='store_true', help='Erase Flash work area'); + parser.add_argument('--allerase', '-a', action='store_true', help='All Chip Erase'); + parser.add_argument('address', help='Start Flash address', type=arg_auto_int) + parser.add_argument('filename', help='File name') + + args = parser.parse_args() + + print('WrFlash-PHY6222 Utility version %s' % __version__) + + phy = phyflasher(args.port) + print ('Connecting...') + offset = args.address + if offset >= MAX_FLASH_SIZE: + print ('Error Start Flash address!') + sys.exit(1) + if phy.Connect(args.baud): + stream = open(args.filename, 'rb') + size = os.path.getsize(args.filename) + if size < 1: + stream.close + print ('Error: File size = 0!') + sys.exit(1) + offset = args.address & (MAX_FLASH_SIZE-1) + if size + offset > MAX_FLASH_SIZE: + size = MAX_FLASH_SIZE - offset + if size < 1: + stream.close + print ('Error: Write File size = 0!') + sys.exit(1) + aerase = True; + if args.erase == True or args.allerase == True: + aerase = False; + if args.allerase == True: + if not phy.cmd_erase_all_flash(): # cmd_erase_all_chipf(): + stream.close + print ('Error: Erase Flash!') + sys.exit(3) + else: + if args.erase == True: + if not cmd_erase_all_chipf(): + stream.close + print ('Error: Clear Flash!') + sys.exit(3) + phy.SetAutoErase(aerase) + print ('Write Flash data 0x%08x to 0x%08x from file: %s ...' % (offset, offset + size, args.filename)) + if size > 0: + if not phy.WriteBlockFlash(stream, offset, size): + stream.close + print ('Error: Write Flash!') + sys.exit(2) + stream.close + print ('--------------------------------------------------------') + print ('Write Flash data 0x%08x to 0x%08x from file: %s - ok.' % (offset, offset + size, args.filename)) + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/rdreg_phy6222.py b/rdreg_phy6222.py new file mode 100644 index 0000000..7f13b4d --- /dev/null +++ b/rdreg_phy6222.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +# rdreg_phy6202.py 30.11.2019 pvvx # + +import serial; +import time; +import argparse +import os +import struct +import sys + +__version__ = "23.11.22" + +class FatalError(RuntimeError): + def __init__(self, message): + RuntimeError.__init__(self, message) + + @staticmethod + def WithResult(message, result): + message += " (result was %s)" % hexify(result) + return FatalError(message) + +def arg_auto_int(x): + return int(x, 0) + +def main(): + parser = argparse.ArgumentParser(description='RdRegs-PHY6222 Utility version %s' % __version__, prog='rdreg_phy6222') + parser.add_argument( + '--port', '-p', + help='Serial port device', + default='COM1'); + parser.add_argument( + '--baud', '-b', + help='Set Port Baud (115200, 250000, 500000, 1000000), default: 1000000', + type=arg_auto_int, + default=1000000); + parser.add_argument('address', help='Start address', type=arg_auto_int) + parser.add_argument('size', help='Size of region to dump', type=arg_auto_int) + + args = parser.parse_args() + + baud = 9600; + print('RdRegs-PHY62x2 Utility version %s' % __version__) + try: + serialPort = serial.Serial(args.port, baud, \ + serial.EIGHTBITS,\ + serial.PARITY_NONE, \ + serial.STOPBITS_ONE); + except: + print('Error: Open %s, %d baud!' % (args.port, baud)) + sys.exit(2) + + serialPort.setDTR(False) #TM (lo) + serialPort.setRTS(True) #RSTN (lo) + serialPort.flushOutput() + serialPort.flushInput() + time.sleep(0.1) + serialPort.setDTR(True) #TM (hi) + serialPort.flushOutput() + serialPort.flushInput() + time.sleep(0.1) + serialPort.setRTS(False) #RSTN (hi) + serialPort.timeout = 0.04 + +#-------------------------------- + + byteSent = 0; + byteRead = 0; + byteSaved = 0; + + addr = args.address; + length = args.size; + + ttcl = 250; + pkt = 'UXTDWU' # UXTL16 UDLL48 UXTDWU + while ttcl > 0: + sent = serialPort.write(pkt.encode()); + byteSent += sent + read = serialPort.read(6); + byteRead += len(read); + if read == b'cmd>>:' : + break + ttcl = ttcl - 1 + if ttcl < 1: + print('PHY62x2 - Error Reset!') + print('Check connection TX->RX, RX<-TX and Chip Power!') + serialPort.close() + exit(4) + + print('PHY62x2 - Reset Ok') + serialPort.close() + serialPort.baudrate = 115200 + serialPort.open(); + serialPort.timeout = 0.2 + + pkt = 'wrreg4000f054 0 '; + sent = serialPort.write(pkt.encode()); + byteSent += sent; + read = serialPort.read(6); + byteRead += len(read); + if read != b'#OK>>:' : + print('PHY62x2 - Error init1!') + serialPort.close() + exit(4) + + pkt = 'wrreg4000f140 0 '; + sent = serialPort.write(pkt.encode()); + byteSent += sent; + read = serialPort.read(6); + byteRead += len(read); + if read != b'#OK>>:' : + print('PHY62x2 - Error init2!') + serialPort.close() + exit(4) + + pkt = 'wrreg4000f144 0 '; + sent = serialPort.write(pkt.encode()); + byteSent += sent; + read = serialPort.read(6); + byteRead += len(read); + if read != b'#OK>>:' : + print('PHY62x2 - Error init3!') + serialPort.close() + exit(4) + + if baud != args.baud: + baud = args.baud; + print('Reopen %s port %i baud' % (args.port, baud)) + pkt = "uarts%i" % baud + sent = serialPort.write(pkt.encode()); + byteSent += sent; + serialPort.timeout = 1 +# 012 +# #OK + read = serialPort.read(3); + #print(read); + serialPort.close() + serialPort.baudrate = baud + serialPort.open(); + + serialPort.write(str.encode("rdrev")); + serialPort.timeout = 0.1 + read = serialPort.read(16); + if read[0:2] == b'0x' and read[10:16] == b'#OK>>:': + print('Revision:', read[0:10]) + else: + print('Error read Revision!') + exit(2) + print('Start address: 0x%08x, length: 0x%08x' % (addr, length)) + + filename = "r%08x-%08x.bin" % (addr, length) + try: + ff = open(filename, "wb") + except: + serialPort.close() + print('Error file open ' + filename) + exit(2) + + t1 = time.time() + while length > 0: + if args.size > 128 and addr&127 == 0: + print('\rRead 0x%08x...' % addr, end='') #, flush=True + txt = "rdreg%08x" % addr; + sent = serialPort.write(txt.encode()); + byteSent += sent; +# 01234567890123456 +# =0x1fff3710#OK>>: + read = serialPort.read(17); + byteRead += len(read); + if read[0:3] == b'=0x' and read[11:17] == b'#OK>>:': + dw = struct.pack(' 1024: + print("%.3f KBytes saved to file '%s'" % (byteSaved/1024, filename)) + else: + print("%i Bytes saved to file '%s'" % (byteSaved, filename)) + ff.close() + exit(0); + +if __name__ == '__main__': + main()