Merge pull request #80 from grigorig/pr64
Added protocol stc89a (BSL 7.2.5c) PR#64
This commit is contained in:
commit
a6b791b089
80
doc/reverse-engineering/stc89a-c52rc.txt
Normal file
80
doc/reverse-engineering/stc89a-c52rc.txt
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
001046: Read (UP): 2021-01-09 15:37:44.9125552 +0.0085328
|
||||||
|
46 b9 68 00 29 50 fd 84 1e 11 4d 05 8e 96 27 7c F.h.)P....M...'|
|
||||||
|
^
|
||||||
|
cpu_6t
|
||||||
|
04 47 01 7f 40 81 72 43 00 f0 51 05 80 00 ff ff .G..@.rC..Q.....
|
||||||
|
^ ^ ^ ^
|
||||||
|
freq_counte | | |
|
||||||
|
bl_version |
|
||||||
|
bl_stepping |
|
||||||
|
bl_minor
|
||||||
|
|
||||||
|
|
||||||
|
ff ff 38 20 20 02 19 60 0d a0 16 ..8 ..`...
|
||||||
|
|
||||||
|
|
||||||
|
001057: Write (DOWN): 2021-01-09 15:37:44.9814096 +0.0129872
|
||||||
|
46 b9 6a 00 0a 01 ff fd 82 02 f3 16 F.j.........
|
||||||
|
^
|
||||||
|
handshake
|
||||||
|
|
||||||
|
|
||||||
|
001072: Read (UP): 2021-01-09 15:37:45.0836096 +0.0115168
|
||||||
|
46 b9 68 00 07 01 00 70 16 F.h....p.
|
||||||
|
|
||||||
|
001113: Write (DOWN): 2021-01-09 15:37:45.1352048 +0.0171904
|
||||||
|
46 b9 6a 00 0b 05 00 00 46 b9 01 79 16 F.j.....F..y.
|
||||||
|
^
|
||||||
|
ping-pong
|
||||||
|
|
||||||
|
|
||||||
|
001116: Read (UP): 2021-01-09 15:37:45.1392768 +0.0017200
|
||||||
|
46 b9 68 00 07 05 00 74 16 F.h....t.
|
||||||
|
|
||||||
|
|
||||||
|
001127: Write (DOWN): 2021-01-09 15:37:45.1502464 +0.0109472
|
||||||
|
46 b9 6a 00 0b 03 00 00 46 b9 01 77 16 F.j.....F..w.
|
||||||
|
^
|
||||||
|
erase_flash ?
|
||||||
|
|
||||||
|
|
||||||
|
001170: Read (UP): 2021-01-09 15:37:45.4729040 +0.0099696
|
||||||
|
46 b9 68 00 0e 03 f0 51 c5 f2 06 7c 14 04 07 16 F.h....Q...|....
|
||||||
|
^
|
||||||
|
mcu id
|
||||||
|
|
||||||
|
|
||||||
|
001181: Write (DOWN): 2021-01-09 15:37:45.4791856 +0.0062576
|
||||||
|
46 b9 6a 00 8b 32 00 00 46 b9 02 00 08 12 00 3f F.j..2..F......?
|
||||||
|
^ ^
|
||||||
|
write address
|
||||||
|
write data
|
||||||
|
80 fe 75 81 07 12 00 4c e5 82 60 03 02 00 03 e4 ..u....L..`.....
|
||||||
|
78 ff f6 d8 fd 02 00 03 ae 82 af 83 8e 04 8f 05 x...............
|
||||||
|
1e be ff 01 1f ec 4d 60 0f 7c 90 7d 01 1c bc ff ......M`.|.}....
|
||||||
|
01 1d ec 4d 70 f7 80 e4 22 90 03 e8 12 00 1e e5 ...Mp...".......
|
||||||
|
80 f4 f5 80 80 f3 75 82 00 22 ff ff ff ff ff ff ......u.."......
|
||||||
|
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
|
||||||
|
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
|
||||||
|
ff ff ff ff ff ff ff ff ff ff 52 f9 16 ..........R..
|
||||||
|
|
||||||
|
|
||||||
|
001188: Read (UP): 2021-01-09 15:37:45.5301744 +0.0047088
|
||||||
|
46 b9 68 00 08 02 54 00 c6 16 F.h...T...
|
||||||
|
^
|
||||||
|
write done
|
||||||
|
|
||||||
|
|
||||||
|
001199: Write (DOWN): 2021-01-09 15:37:45.5575264 +0.0273248
|
||||||
|
46 b9 6a 00 0c 04 00 00 46 b9 fd 02 76 16 F.j.....F...v.
|
||||||
|
^
|
||||||
|
write msr
|
||||||
|
|
||||||
|
|
||||||
|
001202: Read (UP): 2021-01-09 15:37:45.5625296 +0.0018304
|
||||||
|
46 b9 68 00 08 04 54 00 c8 16 F.h...T...
|
||||||
|
unknown
|
||||||
|
|
||||||
|
001213: Write (DOWN): 2021-01-09 15:37:45.5712992 +0.0087472
|
||||||
|
46 b9 6a 00 07 ff 01 70 16 F.j....p.
|
||||||
|
unknown
|
@ -26,6 +26,7 @@ import stcgal
|
|||||||
import serial
|
import serial
|
||||||
from stcgal.utils import BaudType
|
from stcgal.utils import BaudType
|
||||||
from stcgal.protocols import Stc89Protocol
|
from stcgal.protocols import Stc89Protocol
|
||||||
|
from stcgal.protocols import Stc89AProtocol
|
||||||
from stcgal.protocols import Stc12AProtocol
|
from stcgal.protocols import Stc12AProtocol
|
||||||
from stcgal.protocols import Stc12BProtocol
|
from stcgal.protocols import Stc12BProtocol
|
||||||
from stcgal.protocols import Stc12Protocol
|
from stcgal.protocols import Stc12Protocol
|
||||||
@ -52,6 +53,8 @@ class StcGal:
|
|||||||
"""Initialize protocol backend"""
|
"""Initialize protocol backend"""
|
||||||
if opts.protocol == "stc89":
|
if opts.protocol == "stc89":
|
||||||
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
|
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
|
||||||
|
elif opts.protocol == "stc89a":
|
||||||
|
self.protocol = Stc89AProtocol(opts.port, opts.handshake, opts.baud)
|
||||||
elif opts.protocol == "stc12a":
|
elif opts.protocol == "stc12a":
|
||||||
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
|
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
|
||||||
elif opts.protocol == "stc12b":
|
elif opts.protocol == "stc12b":
|
||||||
|
@ -628,6 +628,239 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
|
|
||||||
|
class Stc89AProtocol(StcBaseProtocol):
|
||||||
|
"""Protocol handler for STC 89/90 series"""
|
||||||
|
|
||||||
|
PARITY = serial.PARITY_NONE
|
||||||
|
"""Parity configuration - these don't use any parity"""
|
||||||
|
|
||||||
|
PROGRAM_BLOCKSIZE = 128
|
||||||
|
"""block size for programming flash"""
|
||||||
|
|
||||||
|
def __init__(self, port, baud_handshake, baud_transfer):
|
||||||
|
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||||
|
|
||||||
|
self.cpu_6t = None
|
||||||
|
|
||||||
|
def extract_payload(self, packet):
|
||||||
|
"""Verify the checksum of packet and return its payload"""
|
||||||
|
|
||||||
|
packet_csum = packet[-2] + (packet[-3] << 8)
|
||||||
|
calc_csum = sum(packet[2:-3]) & 0xffff
|
||||||
|
if packet_csum != calc_csum:
|
||||||
|
self.dump_packet(packet)
|
||||||
|
raise StcFramingException("packet checksum mismatch")
|
||||||
|
|
||||||
|
payload = StcBaseProtocol.extract_payload(self, packet)
|
||||||
|
return payload[:-1]
|
||||||
|
|
||||||
|
def write_packet(self, packet_data):
|
||||||
|
"""Send packet to MCU.
|
||||||
|
|
||||||
|
Constructs a packet with supplied payload and sends it to the MCU.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# frame start and direction magic
|
||||||
|
packet = bytes()
|
||||||
|
packet += self.PACKET_START
|
||||||
|
packet += self.PACKET_HOST
|
||||||
|
|
||||||
|
# packet length and payload
|
||||||
|
packet += struct.pack(">H", len(packet_data) + 6)
|
||||||
|
packet += packet_data
|
||||||
|
|
||||||
|
# checksum and end code
|
||||||
|
packet += struct.pack(">H", sum(packet[2:]) & 0xffff)
|
||||||
|
packet += self.PACKET_END
|
||||||
|
|
||||||
|
self.dump_packet(packet, receive=False)
|
||||||
|
self.ser.write(packet)
|
||||||
|
self.ser.flush()
|
||||||
|
|
||||||
|
def get_status_packet(self):
|
||||||
|
"""Read and decode status packet"""
|
||||||
|
|
||||||
|
status_packet = self.read_packet()
|
||||||
|
if status_packet[0] != 0x50:
|
||||||
|
raise StcProtocolException("incorrect magic in status packet" + str(status_packet[0]))
|
||||||
|
return status_packet
|
||||||
|
|
||||||
|
def initialize_options(self, status_packet):
|
||||||
|
"""Initialize options"""
|
||||||
|
|
||||||
|
if len(status_packet) < 20:
|
||||||
|
raise StcProtocolException("invalid options in status packet")
|
||||||
|
self.options = Stc89Option(status_packet[1])
|
||||||
|
self.options.print()
|
||||||
|
|
||||||
|
self.ser.parity = "E"
|
||||||
|
|
||||||
|
def calculate_baud(self):
|
||||||
|
"""Calculate MCU baudrate setting.
|
||||||
|
|
||||||
|
Calculate appropriate baudrate settings for the MCU's UART,
|
||||||
|
according to clock frequency and requested baud rate.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# timing is different in 6T mode
|
||||||
|
sample_rate = 32 #if self.cpu_6t else 32
|
||||||
|
# baudrate is directly controlled by programming the MCU's BRT register
|
||||||
|
brt = 65536 - round((self.mcu_clock_hz) / (self.baud_transfer * sample_rate))
|
||||||
|
|
||||||
|
baud_actual = (self.mcu_clock_hz) / (sample_rate * (65536 - brt))
|
||||||
|
baud_error = (abs(self.baud_transfer - baud_actual) * 100.0) / self.baud_transfer
|
||||||
|
if baud_error > 5.0:
|
||||||
|
print("WARNING: baudrate error is %.2f%%. You may need to set a slower rate." %
|
||||||
|
baud_error, file=sys.stderr)
|
||||||
|
|
||||||
|
# IAP wait states (according to datasheet(s))
|
||||||
|
iap_wait = 0x80
|
||||||
|
if self.mcu_clock_hz < 10E6: iap_wait = 0x83
|
||||||
|
elif self.mcu_clock_hz < 30E6: iap_wait = 0x82
|
||||||
|
elif self.mcu_clock_hz < 50E6: iap_wait = 0x81
|
||||||
|
|
||||||
|
# MCU delay after switching baud rates
|
||||||
|
delay = 0xa0
|
||||||
|
|
||||||
|
return brt, iap_wait
|
||||||
|
|
||||||
|
def initialize_status(self, status_packet):
|
||||||
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
|
self.cpu_6t = not bool(status_packet[1] & 1)
|
||||||
|
|
||||||
|
freq_counter = struct.unpack(">H", status_packet[13:15])[0]
|
||||||
|
self.mcu_clock_hz = (12 * freq_counter * self.baud_handshake)
|
||||||
|
|
||||||
|
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
||||||
|
bl_minor = status_packet[22] & 0x0f
|
||||||
|
self.mcu_bsl_version = "%d.%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
|
bl_minor, chr(bl_stepping))
|
||||||
|
|
||||||
|
def handshake(self):
|
||||||
|
"""Switch to transfer baudrate
|
||||||
|
|
||||||
|
Switches to transfer baudrate and verifies that the setting works with
|
||||||
|
a ping-pong exchange of packets."""
|
||||||
|
|
||||||
|
# check new baudrate
|
||||||
|
print("Switching to %d baud: " % self.baud_transfer, end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
brt,iap = self.calculate_baud()
|
||||||
|
print("checking ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
packet = bytes([0x01])
|
||||||
|
packet += struct.pack(">H", brt)
|
||||||
|
packet += bytes([iap])
|
||||||
|
self.write_packet(packet)
|
||||||
|
time.sleep(0.2)
|
||||||
|
print(self.baud_transfer)
|
||||||
|
response = self.read_packet()
|
||||||
|
|
||||||
|
if response[0] != 0x01:
|
||||||
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
|
self.ser.baudrate = self.baud_transfer
|
||||||
|
|
||||||
|
# ping-pong test
|
||||||
|
print("testing ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
packet = bytes([0x05, 0x00, 0x00, 0x46, 0xB9])
|
||||||
|
self.write_packet(packet)
|
||||||
|
response = self.read_packet()
|
||||||
|
if response[0] != 0x05:
|
||||||
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
|
print("done")
|
||||||
|
|
||||||
|
def reset_device(self, resetcmd=False):
|
||||||
|
if not resetcmd:
|
||||||
|
print("Cycling power: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
self.ser.setDTR(False)
|
||||||
|
time.sleep(0.5)
|
||||||
|
self.ser.setDTR(True)
|
||||||
|
print("done")
|
||||||
|
else:
|
||||||
|
print("Cycling power via shell cmd: " + resetcmd)
|
||||||
|
os.system(resetcmd)
|
||||||
|
|
||||||
|
print("Waiting for MCU: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def erase_flash(self, erase_size, _):
|
||||||
|
"""Erase the MCU's flash memory.
|
||||||
|
|
||||||
|
Erase the flash memory with a block-erase command.
|
||||||
|
flash_size is ignored; not used on STC 89 series.
|
||||||
|
"""
|
||||||
|
|
||||||
|
print("Erasing All blocks: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
packet = bytes([0x03, 0x00, 0x00, 0x46, 0xB9])
|
||||||
|
self.write_packet(packet)
|
||||||
|
response = self.read_packet()
|
||||||
|
if response[0] != 0x03:
|
||||||
|
raise StcProtocolException("incorrect magic in erase packet")
|
||||||
|
|
||||||
|
print("MCU ID: {:x}{:x}{:x}{:x}{:x}{:x}{:x}".format(response[1],response[2],response[3]
|
||||||
|
,response[4],response[5],response[6],response[7]))
|
||||||
|
|
||||||
|
print("done")
|
||||||
|
|
||||||
|
def program_flash(self, data):
|
||||||
|
"""Program the MCU's flash memory.
|
||||||
|
|
||||||
|
Write data into flash memory, using the PROGRAM_BLOCKSIZE
|
||||||
|
as the block size (depends on MCU's RAM size).
|
||||||
|
"""
|
||||||
|
p = 0
|
||||||
|
|
||||||
|
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||||
|
packet = bytes(3)
|
||||||
|
if p == 0:
|
||||||
|
packet = bytes([0x22,0x00,0x00])
|
||||||
|
else:
|
||||||
|
packet = bytes([0x02])
|
||||||
|
packet += int(128 * p).to_bytes(length=2, byteorder='big', signed=True)
|
||||||
|
|
||||||
|
|
||||||
|
p = p + 1
|
||||||
|
packet += bytes([0x46, 0xB9])
|
||||||
|
packet += data[i:i+self.PROGRAM_BLOCKSIZE]
|
||||||
|
|
||||||
|
self.write_packet(packet)
|
||||||
|
|
||||||
|
response = self.read_packet()
|
||||||
|
if len(response) < 1 or response[0] != 0x02:
|
||||||
|
raise StcProtocolException("incorrect magic in write packet")
|
||||||
|
|
||||||
|
self.progress_cb(i, self.PROGRAM_BLOCKSIZE, len(data))
|
||||||
|
self.progress_cb(len(data), self.PROGRAM_BLOCKSIZE, len(data))
|
||||||
|
|
||||||
|
def program_options(self):
|
||||||
|
"""Program option byte into flash"""
|
||||||
|
|
||||||
|
print("Setting options: ")
|
||||||
|
sys.stdout.flush()
|
||||||
|
msr = self.options.get_msr()
|
||||||
|
packet = bytes([0x04,0x00,0x00,0x46,0xB9, msr])
|
||||||
|
self.write_packet(packet)
|
||||||
|
response = self.read_packet()
|
||||||
|
if response[0] != 0x04:
|
||||||
|
raise StcProtocolException("incorrect magic in option packet")
|
||||||
|
print("done")
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Disconnect from MCU"""
|
||||||
|
|
||||||
|
# reset mcu
|
||||||
|
packet = bytes([0xFF])
|
||||||
|
self.write_packet(packet)
|
||||||
|
self.ser.close()
|
||||||
|
print("Disconnected!")
|
||||||
|
|
||||||
|
|
||||||
class Stc12AOptionsMixIn:
|
class Stc12AOptionsMixIn:
|
||||||
def program_options(self):
|
def program_options(self):
|
||||||
print("Setting options: ", end="")
|
print("Setting options: ", end="")
|
||||||
|
Loading…
Reference in New Issue
Block a user