a42f2378f946f4a79aa50ff46ee61122454162b9
[renesas-ra-flasher] / src / RAFlasher.py
1 import os
2 import math
3 import argparse
4 from RAConnect import *
5 from RAPacker import *
6
7 SECTOR_SIZE = 2048
8
9 def int_to_hex_list(num):
10     hex_string = hex(num)[2:].upper()  # convert to hex string
11     hex_string = hex_string.zfill(8) # pad for 8 char's long
12     hex_list = [f'0x{hex_string[c:c+2]}' for c in range(0, 8, 2)]
13     return hex_list
14
15 def inquire_connection(dev):
16     packed = pack_pkt(INQ_CMD, "")
17     dev.send_data(packed)
18     info = dev.recv_data(7)
19     #print(info)
20     if info == bytearray(b'\x00') or info == bytearray(b''):
21         return False
22     msg = unpack_pkt(info)
23     print("Connection already established")
24     #print(msg)
25     return True
26
27 def get_area_info(dev):
28     for i in [0,1,2]:
29         print("===================")
30         packed = pack_pkt(ARE_CMD, [str(i)])
31         dev.send_data(packed)
32         info = dev.recv_data(23)
33         msg = unpack_pkt(info)
34         fmt = '>BIIII'
35         KOA, SAD, EAD, EAU, WAU = struct.unpack(fmt, bytes(int(x, 16) for x in msg))
36         print(f'Area {KOA} - {hex(SAD)}:{hex(EAD)}')
37         print(f'Erase {hex(EAU)} bytes - write {hex(WAU)} bytes')
38
39 def get_dev_info(dev):
40
41     packed = pack_pkt(SIG_CMD, "")
42     dev.send_data(packed)
43     print(packed)
44     info = dev.recv_data(18)
45     print(info, len(info))
46     #info = b'\x81\x00\x0D\x3A\x01\x31\x2d\x00\x00\x1e\x84\x80\x04\x02\x0a\x08' # test
47     fmt = '>IIIBBHH'
48     _HEADER, SCI, RMB, NOA, TYP, BFV, _FOOTER = struct.unpack(fmt, info)
49     print('Chip info:')
50     print('====================')
51     print(f'Serial interface speed: {SCI} Hz')
52     print(f'Recommend max UART baud rate {RMB} bps')
53     print(f'User area in Code flash [{NOA & 0x1}|{NOA & 0x02 >> 1}]')
54     print(f'User area in Data flash [{NOA & 0x03 >> 2}]')
55     print(f'Config area [{NOA & 0x04 >> 3}]')
56     if TYP == 0x02:
57         print('RA MCU + RA2/RA4 Series')
58     elif TYP == 0x03:
59         print('RA MCU + RA6 Series')
60     else:
61         print('Unknown MCU type')
62     print(f'Boot firmware version {BFV >> 8}.{BFV & 0xFF}')
63     print('====================')
64
65
66 def verify_img(dev, img, start_addr, end_addr):
67     raise Exception("Not implemented")
68
69 def write_img(dev, img, start_addr, end_addr, verify=False):
70
71     if os.path.exists(img):
72         file_size = os.path.getsize(img)
73     else:
74         raise Exception(f'file {img} does not exist')
75
76     # calculate / check start and end address 
77     if start_addr == None or end_addr == None:
78         if start_addr == None:
79             start_addr = 0
80         # align start addr
81         if start_addr % SECTOR_SIZE:
82             raise ValueError(f"start addr not aligned on sector size {SECTOR_SIZE}")
83         blocks = (file_size + SECTOR_SIZE - 1) // SECTOR_SIZE
84         end_addr = blocks * SECTOR_SIZE + start_addr
85         print(end_addr)
86     
87     chunk_size = 64 # max is 1024
88     if (start_addr > 0xFF800): # for RA4 series
89         raise ValueError("start address value error")
90     if (end_addr <= start_addr or end_addr > 0xFF800):
91         raise ValueError("end address value error")
92
93     # setup initial communication
94     SAD = int_to_hex_list(start_addr)
95     EAD = int_to_hex_list(end_addr)
96     packed = pack_pkt(WRI_CMD, SAD + EAD)
97     dev.send_data(packed)
98     ret = dev.recv_data(7)
99
100     with open(img, 'rb') as f:
101         chunk = f.read(chunk_size)
102         while chunk:
103             packed = pack_pkt(WRI_CMD, chunk)
104             print(f'Sending {len(chunk)} bytes')
105             dev.send_data(packed)
106             reply_len = 7
107             reply = dev.recv_data(reply_len)
108             #reply = b'\x81\x00\x02\x00\x00\xFE\x03' # test reply
109             if not reply == False:
110                 msg = unpack_pkt(reply)
111                 print(msg)
112             chunk = f.read(chunk_size)
113
114 def main():
115     parser = argparse.ArgumentParser(description="RA Flasher Tool")
116
117     subparsers = parser.add_subparsers(dest="command", title="Commands")
118
119     # Subparser for the write command
120     write_parser = subparsers.add_parser("write", help="Write data to flash")
121     write_parser.add_argument("--start_address", type=int, default=0x0000, help="Start address")
122     write_parser.add_argument("--end_address", type=int, help="End address")
123     write_parser.add_argument("--verify", action="store_true", help="Verify after writing")
124     write_parser.add_argument("file_name", type=str, help="File name")
125
126     # Subparser for the read command
127     read_parser = subparsers.add_parser("read", help="Read data from flash")
128     read_parser.add_argument("--start_address", type=int, default=0x000, help="Start address")
129     read_parser.add_argument("--size", type=int, default=1024, help="Size in bytes")
130     read_parser.add_argument("file_name", type=str, help="File name")
131
132     # Subparser for the info command
133     subparsers.add_parser("info", help="Show flasher information")
134
135     args = parser.parse_args()
136
137     if args.command == "write":
138         dev = RAConnect(vendor_id=0x045B, product_id=0x0261)
139         print(args)
140         write_img(dev, args.file_name, args.start_address, args.end_address, args.verify)
141     elif args.command == "read":
142         print('read command')
143     elif args.command == "info":
144         dev = RAConnect(vendor_id=0x045B, product_id=0x0261)
145         status_con = inquire_connection(dev)
146         if not status_con:
147             #dev.establish_connection()
148             dev.confirm_connection()
149         get_dev_info(dev)
150         get_area_info(dev)
151     else:
152         parser.print_help()
153
154 if __name__ == "__main__":
155     main()
156