add backup info

This commit is contained in:
pvvx 2023-12-28 09:28:09 +03:00
parent 5e47d20cb8
commit da2cb7bc2f
3 changed files with 578 additions and 0 deletions

View file

@ -32,3 +32,22 @@ Custom firmware for Tuya [THB2](https://pvvx.github.io/THB2).
Дополнительная информация по чипам [PHY62xx](https://github.com/pvvx/PHY62x2).
## Сохранение оригинальной прошивки.
1. Соединить GND, TX, RX, RTSRESET, 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, RTSRESET, VCC (+3.3B).
3. Запустить:
```
python3 WrFlash_phy6222.py -p COM11 -b 1000000 0 r11000000-00080000.bin
```
4. Прошивка зашита. Сбросить устройство переключением питания.

359
WrFlash_phy6222.py Normal file
View file

@ -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('<I', int(read[1:11], 16))
return dw
return None
def read_reg(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>>:':
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()

200
rdreg_phy6222.py Normal file
View file

@ -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('<I', int(read[1:11], 16))
ff.write(dw);
byteSaved +=len(dw);
else:
t2 = time.time()
print('\r Time: %.3f sec' % (t2-t1))
print('Writes: %d Bytes' % byteSent)
print(' Reads: %d Bytes' % byteRead)
print
print('\rError read address 0x%08x!' % addr)
serialPort.close()
ff.close()
exit(1);
addr += 4
length -= 4
t2 = time.time()
serialPort.close()
print('\r Time: %.3f sec' % (t2-t1))
print('Writes: %d Bytes' % byteSent)
print(' Reads: %d Bytes' % byteRead)
print
if byteSaved > 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()