tests: add/modify ack=True test
[renesas-ra-flasher] / src / RAPacker.py
1 # Copyright (C) Robin Krens - 2024
2
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17
18 import struct
19
20 # Commands send to boot firmware
21 INQ_CMD = 0x00
22 ERA_CMD = 0x12
23 WRI_CMD = 0x13
24 REA_CMD = 0x15
25 IDA_CMD = 0x30
26 BAU_CMD = 0x34
27 SIG_CMD = 0x3A
28 ARE_CMD = 0x3B
29
30 STATUS_OK = 0x00
31 STATUS_ERR = 0x80
32
33 # Error codes
34 error_codes = {
35     0xC: "ERR_UNSU",
36     0xC1: "ERR_PCKT",
37     0xC2: "ERR_CHKS",
38     0xC3: "ERR_FLOW",
39     0xD0: "ERR_ADDR",
40     0xD4: "ERR_BAUD",
41     0xDA: "ERR_PROT",
42     0xDB: "ERR_ID",
43     0xDC: "ERR_SERI",
44     0xE1: "ERR_ERA",
45     0xE2: "ERR_WRI",
46     0xE7: "ERR_SEQ"
47 }
48
49 # used for init sequence
50 LOW_PULSE = 0x00
51 GENERIC_CODE = 0x55
52 BOOT_CODE = 0xC3
53
54 TESTID = [
55     "0xF0", "0xF1", "0xF2", "0xF3",
56     "0xE4", "0xE5", "0xE6", "0xE7",
57     "0xD8", "0xD9", "0xDA", "0xDB",
58     "0xCC", "0xCD", "0xCE", "0xCF"
59 ]
60
61 def calc_sum(cmd, data):
62     data_len = len(data)
63     lnh = (data_len + 1 & 0xFF00) >> 8
64     lnl = data_len + 1 & 0x00FF
65     res = lnh + lnl + cmd
66     for i in range(data_len):
67             if isinstance(data[i], str):
68                 res += int(data[i], 16)
69             elif isinstance(data[i], int):
70                 res += data[i]
71             else:
72                 res += ord(data[i])
73     res = ~(res - 1) & 0xFF # two's complement
74     return (lnh, lnl, res)
75
76
77 # format of data packet is [SOD|LNH|LNL|COM|byte_data|SUM|ETX]
78 def pack_command(cmd, data):
79     SOD = 0x01
80     COM = cmd
81
82     if isinstance(data, str):
83         byte_data = bytes(data.encode('utf-8'))
84     else:
85         byte_data = bytes([int(x, 16) for x in data])
86     
87     LNH, LNL, SUM = calc_sum(int(cmd), data)
88     ETX = 0x03
89     fmt_header = '<BBBB'
90     fmt_footer = 'BB'
91     fmt = fmt_header + str(len(data)) + 's' + fmt_footer
92     pack = struct.pack(fmt, SOD, LNH, LNL, COM, byte_data, SUM, ETX)
93     print(fmt, pack, len(pack))
94     return fmt
95
96 # format of data packet is [SOD|LNH|LNL|RES|DAT|SUM|ETX]
97 def pack_pkt(res, data, ack=False):
98     SOD = 0x01 # TODO: check if 0x81 header needed
99     if ack:
100         SOD = 0x81
101     if (len(data) > 1024):
102         raise Exception(f'Data packet too large, data length is {DATA_LEN} (>1024)')
103     LNH, LNL, SUM = calc_sum(int(res), data)
104     if not isinstance(data, bytes):
105         DAT = bytes([int(x, 16) for x in data])
106     else:
107         DAT = data
108     RES = res
109     ETX = 0x03
110     fmt_header = '<BBBB'
111     fmt_footer = 'BB'
112     fmt = fmt_header + str(len(data)) + 's' + fmt_footer
113     pack = struct.pack(fmt, SOD, LNH, LNL, RES, DAT, SUM, ETX)
114     return pack
115
116 # packet received from mcu 
117 def unpack_pkt(data):
118     header = data[0:4]
119     fmt_header = '<BBBB'
120     SOD, LNH, LNL, RES = struct.unpack(fmt_header, header)
121     if (SOD != 0x81):
122         raise Exception(f'Wrong start of packet data received')
123     pkt_len = (LNH << 0x8 | LNL) - 1
124     fmt_message = '<' + str(pkt_len) + 's'
125     raw = struct.unpack_from(fmt_message, data, 4)[0]
126     message = ['0x{:02X}'.format(byte) for byte in raw]
127     if (RES & 0x80):
128         raise ValueError(f'MCU encountered error {message[0]}')
129     fmt_footer = '<BB'
130     SUM, ETX = struct.unpack_from(fmt_footer, data, 4 + pkt_len)
131     lnh, lnl, local_sum = calc_sum(RES, message)
132     if (SUM != local_sum):
133         raise Exception(f'Sum calculation mismatch, read {SUM} instead of {local_sum}')
134     if (ETX != 0x03):
135         raise Exception(f'Packet ETX error')
136     return message