1515#include "error.h"
1616#include "funcs.h"
1717
18- /**
19- * @brief Erase internal flash
20- * @retval error according to enum #ERR
21- */
22- static int bootloader_erase (void );
23-
2418/**
2519 * @brief Start the programming operation
2620 * @param offset Start of programmed region
2721 * @param length Length of programmed region
2822 * @retval error according to enum #ERR
2923 */
30- static int bootloader_start (int offset , int length );
24+ static int bootloader_erase_and_start (int offset , int length );
3125
3226/**
3327 * @brief Send firmware to bootloader
34- * @param fp Firmware file
28+ * @param firmware Firmware image
3529 * @param length Length of programmed region
3630 * @param pCrc32 Locally-calculated CRC32 of the firmware
3731 * @retval error according to enum #ERR
3832 */
39- static int bootloader_send (FILE * fp , int length , u32 * pCrc32 );
33+ static int bootloader_send (u8 * firmware , int length , u32 * pCrc32 );
4034
4135/**
4236 * @brief Request CRC32 verification from the bootloader
@@ -56,98 +50,85 @@ static int bootloader_checksum(int offset, int length, u32 *pCrc32);
5650 */
5751int bootloader_install (FILE * fp )
5852{
59- int err = ERR_UNK ;
60- u32 local_crc32 = 0 ;
61- u32 remote_crc32 = 0 ;
53+ u8 * firmware = calloc ( FLASH_SIZE , 1 ) ;
54+ int read_bytes = fread ( firmware , 1 , FLASH_SIZE , fp ); // this may be less than FLASH_SIZE (e.g. Pybricks has a small firmware image)
55+ int sector_count = ( read_bytes + FLASH_SECTOR_SIZE - 1 ) / FLASH_SECTOR_SIZE ;
6256
63- puts ("Erasing flash... (takes 1 minute 48 seconds)" ); // 108 seconds
64- err = bootloader_erase ();
65- if (err != ERR_UNK )
66- return err ;
57+ printf ("Programming %d EV3 flash sectors...\n" , sector_count );
6758
68- puts ("Downloading..." );
69- err = bootloader_start (FLASH_START , FLASH_SIZE ); // extremely short
70- if (err != ERR_UNK )
71- return err ;
72- err = bootloader_send (fp , FLASH_SIZE , & local_crc32 ); // variable time
73- if (err != ERR_UNK )
74- return err ;
75-
76- puts ("Calculating flash checksum... (takes 17 seconds)" );
77- err = bootloader_checksum (FLASH_START , FLASH_SIZE , & remote_crc32 ); // 16.7 seconds
59+ int err = ERR_UNK ;
60+ for (int sector = 0 ; sector < sector_count ; sector ++ ) {
61+ u32 local_crc32 = 0 ;
62+ u32 remote_crc32 = 0 ;
7863
79- // handle usb 3.0 bug
80- if (err == ERR_USBLOOP )
81- {
82- puts ("Checksum not checked, assuming update was OK. Rebooting." );
83- }
84- else if (err == ERR_UNK ) // no error occurred
85- {
86- if (local_crc32 != remote_crc32 ) {
87- fprintf (stderr , "error: checksums do not match: remote %08X != local %08X\n" ,
88- remote_crc32 , local_crc32 );
89- return ERR_IO ;
90- } else {
91- puts ("Success! Local and remote checksums match. Rebooting." );
64+ printf ("- sector %d of %d (%d %%)\n" , sector , sector_count , 100 * sector /sector_count );
65+ err = bootloader_erase_and_start (sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE );
66+ if (err != ERR_UNK ) {
67+ puts ("Flash erase returned an error!" );
68+ break ;
9269 }
93- }
94- else // other error occurred
95- {
96- return err ;
97- }
98-
99- return bootloader_exit ();
100- }
10170
102- static int bootloader_erase (void )
103- {
104- FW_ERASEFLASH * request = packet_alloc (FW_ERASEFLASH , 0 );
105- int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
106- if (res < 0 )
107- {
108- errmsg = "Unable to write FW_ERASEFLASH." ;
109- return ERR_COMM ;
110- }
71+ err = bootloader_send (firmware + sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE , & local_crc32 );
72+ if (err != ERR_UNK ) {
73+ puts ("Programming returned an error!" );
74+ break ;
75+ }
11176
112- FW_ERASEFLASH_REPLY * reply = malloc (sizeof (FW_ERASEFLASH_REPLY ));
113- res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_ERASEFLASH_REPLY ), -1 );
114- if (res <= 0 )
115- {
116- errmsg = "Unable to read FW_ERASEFLASH" ;
117- return ERR_COMM ;
77+ err = bootloader_checksum (sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE , & remote_crc32 );
78+ if (err == ERR_USBLOOP && sector == 0 )
79+ {
80+ puts ("NOTE: CRC not checked, because the brick is likely plugged to a USB 3.0 port." );
81+ }
82+ else if (err == ERR_UNK ) // no error occurred
83+ {
84+ if (local_crc32 != remote_crc32 ) {
85+ printf ("Checksum does not match: remote %08X != local %08X\n" , remote_crc32 , local_crc32 );
86+ err = ERR_COMM ;
87+ break ;
88+ }
89+ }
90+ else // other error occurred
91+ {
92+ puts ("Checksum computation returned an error!" );
93+ break ;
94+ }
11895 }
11996
120- // note: accept looped-back packets (usb 3.0 bug; reply not required here)
121- if (reply -> type != VM_OK && reply -> type != VM_SYS_RQ )
122- {
123- errno = reply -> ret ;
124- fputs ("Operation failed.\nlast_reply=" , stderr );
125- print_bytes (reply , reply -> packetLen + 2 );
126-
127- errmsg = "`FW_ERASEFLASH` was denied." ;
128- return ERR_VM ;
97+ free (firmware );
98+ if (err == ERR_UNK ) {
99+ puts ("Flashing finished, rebooting the brick." );
100+ return bootloader_exit ();
101+ } else {
102+ puts ("Some error occurred, leaving the brick in the bootloader mode." );
103+ puts ("To exit it manually, simply remove the EV3 battery and then put it back in." );
104+ return err ;
129105 }
130- return ERR_UNK ;
131106}
132107
133- static int bootloader_start (int offset , int length )
108+ static int bootloader_erase_and_start (int offset , int length )
134109{
135- FW_START_DOWNLOAD * request = packet_alloc (FW_START_DOWNLOAD , 0 );
110+ FW_START_DOWNLOAD_WITH_ERASE * request = NULL ;
111+ FW_START_DOWNLOAD_WITH_ERASE_REPLY * reply = NULL ;
112+ int err ;
113+
114+ request = packet_alloc (FW_START_DOWNLOAD_WITH_ERASE , 0 );
136115 request -> flashStart = offset ;
137116 request -> flashLength = length ;
138117 int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
139118 if (res < 0 )
140119 {
141120 errmsg = "Unable to write FW_START_DOWNLOAD." ;
142- return ERR_COMM ;
121+ err = ERR_COMM ;
122+ goto exit ;
143123 }
144124
145- FW_START_DOWNLOAD_REPLY * reply = malloc (sizeof (FW_START_DOWNLOAD_REPLY ));
146- res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_START_DOWNLOAD_REPLY ), -1 );
125+ reply = malloc (sizeof (FW_START_DOWNLOAD_WITH_ERASE_REPLY ));
126+ res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_START_DOWNLOAD_WITH_ERASE_REPLY ), -1 );
147127 if (res <= 0 )
148128 {
149129 errmsg = "Unable to read FW_START_DOWNLOAD" ;
150- return ERR_COMM ;
130+ err = ERR_COMM ;
131+ goto exit ;
151132 }
152133
153134 // note: accept looped-back packets (usb 3.0 bug; reply not required here)
@@ -157,43 +138,35 @@ static int bootloader_start(int offset, int length)
157138 fputs ("Operation failed.\nlast_reply=" , stderr );
158139 print_bytes (reply , reply -> packetLen + 2 );
159140
160- errmsg = "`FW_START_DOWNLOAD` was denied." ;
161- return ERR_VM ;
141+ errmsg = "`FW_START_DOWNLOAD_WITH_ERASE_REPLY` was denied." ;
142+ err = ERR_VM ;
143+ goto exit ;
162144 }
163- return ERR_UNK ;
145+ err = ERR_UNK ;
146+
147+ exit :
148+ free (request );
149+ free (reply );
150+ return err ;
164151}
165152
166- static int bootloader_send (FILE * fp , int length , u32 * pCrc32 )
153+ static int bootloader_send (u8 * buffer , int length , u32 * pCrc32 )
167154{
168- * pCrc32 = 0 ;
169-
170- int max_payload = 1024 - (sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + 2 );
155+ const int max_payload = 1024 - (sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + 2 );
171156 FW_DOWNLOAD_DATA * request = packet_alloc (FW_DOWNLOAD_DATA , max_payload );
172157 FW_DOWNLOAD_DATA_REPLY * reply = malloc (sizeof (FW_DOWNLOAD_DATA_REPLY ));
173158
174159 int total = length ;
175160 int sent_so_far = 0 ;
176- int file_ended = 0 ;
177- int res = 0 ;
178- int last_percent = 0 ;
161+ int err = ERR_UNK ;
179162 u32 crc = 0 ;
180163
181- printf ("Progress: %3d %%\n" , 0 );
182-
183164 while (sent_so_far < total ) {
184165 int remaining = total - sent_so_far ;
185166 int this_block = remaining <= max_payload ? remaining : max_payload ;
167+ int res ;
186168
187- if (!file_ended ) {
188- int real = fread (request -> payload , 1 , this_block , fp );
189- if (real < this_block ) {
190- file_ended = 1 ;
191- memset (request -> payload + real , 0 , this_block - real );
192- }
193- } else {
194- memset (request -> payload , 0 , this_block );
195- }
196-
169+ memcpy (request -> payload , buffer + sent_so_far , this_block );
197170 crc = crc32 (crc , request -> payload , this_block );
198171
199172 request -> packetLen = sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + this_block ;
@@ -202,14 +175,16 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32)
202175 if (res < 0 )
203176 {
204177 errmsg = "Unable to write FW_DOWNLOAD_DATA." ;
205- return ERR_COMM ;
178+ err = ERR_COMM ;
179+ break ;
206180 }
207181
208182 res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_DOWNLOAD_DATA_REPLY ), -1 );
209183 if (res <= 0 )
210184 {
211185 errmsg = "Unable to read FW_DOWNLOAD_DATA" ;
212- return ERR_COMM ;
186+ err = ERR_COMM ;
187+ break ;
213188 }
214189
215190 // note: accept looped-back packets (usb 3.0 bug; reply not required here)
@@ -220,19 +195,17 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32)
220195 print_bytes (reply , reply -> packetLen + 2 );
221196
222197 errmsg = "`FW_DOWNLOAD_DATA` was denied." ;
223- return ERR_VM ;
198+ err = ERR_VM ;
199+ break ;
224200 }
225201
226202 sent_so_far += this_block ;
227-
228- int new_percent = sent_so_far * 100 / total ;
229- if (new_percent >= last_percent + 5 ) {
230- last_percent += ((new_percent - last_percent ) / 5 ) * 5 ;
231- printf ("Progress: %3d %%\n" , last_percent );
232- }
233203 }
204+
234205 * pCrc32 = crc ;
235- return ERR_UNK ;
206+ free (request );
207+ free (reply );
208+ return err ;
236209}
237210
238211/**
@@ -300,30 +273,37 @@ int bootloader_crc(FILE *fp, u32 starting_sector, u32 num_sectors, bool verbose)
300273
301274static int bootloader_checksum (int offset , int length , u32 * pCrc32 )
302275{
276+ FW_GETCRC32 * request = NULL ;
277+ FW_GETCRC32_REPLY * reply = NULL ;
278+ int err ;
279+
303280 * pCrc32 = 0 ;
304281
305- FW_GETCRC32 * request = packet_alloc (FW_GETCRC32 , 0 );
282+ request = packet_alloc (FW_GETCRC32 , 0 );
306283 request -> flashStart = offset ;
307284 request -> flashLength = length ;
308285 int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
309286 if (res < 0 )
310287 {
311288 errmsg = "Unable to write FW_GETCRC32." ;
312- return ERR_COMM ;
289+ err = ERR_COMM ;
290+ goto exit ;
313291 }
314292
315- FW_GETCRC32_REPLY * reply = malloc (sizeof (FW_GETCRC32_REPLY ));
293+ reply = malloc (sizeof (FW_GETCRC32_REPLY ));
316294 res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_GETCRC32_REPLY ), -1 );
317295 if (res <= 0 )
318296 {
319297 errmsg = "Unable to read FW_GETCRC32" ;
320- return ERR_COMM ;
298+ err = ERR_COMM ;
299+ goto exit ;
321300 }
322301
323302 // note: report loopback bug to outer code
324303 if (reply -> type == VM_SYS_RQ )
325304 {
326- return ERR_USBLOOP ;
305+ err = ERR_USBLOOP ;
306+ goto exit ;
327307 }
328308
329309 if (reply -> type != VM_OK )
@@ -333,8 +313,14 @@ static int bootloader_checksum(int offset, int length, u32 *pCrc32)
333313 print_bytes (reply , reply -> packetLen + 2 );
334314
335315 errmsg = "`FW_GETCRC32` was denied." ;
336- return ERR_VM ;
316+ err = ERR_VM ;
317+ goto exit ;
337318 }
338319 * pCrc32 = reply -> crc32 ;
339- return ERR_UNK ;
320+ err = ERR_UNK ;
321+
322+ exit :
323+ free (request );
324+ free (reply );
325+ return err ;
340326}
0 commit comments