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
@@ -70,98 +64,92 @@ static bool sector_is_mutable(u32 sector_number);
7064 */
7165int bootloader_install (FILE * fp )
7266{
73- int err = ERR_UNK ;
74- u32 local_crc32 = 0 ;
75- u32 remote_crc32 = 0 ;
67+ u8 * firmware = calloc ( FLASH_SIZE , 1 ) ;
68+ int read_bytes = fread ( firmware , 1 , FLASH_SIZE , fp ); // this may be less than FLASH_SIZE (e.g. Pybricks has a small firmware image)
69+ int sector_count = ( read_bytes + FLASH_SECTOR_SIZE - 1 ) / FLASH_SECTOR_SIZE ;
7670
77- puts ("Erasing flash... (takes 1 minute 48 seconds)" ); // 108 seconds
78- err = bootloader_erase ();
79- if (err != ERR_UNK )
80- return err ;
71+ printf ("Programming %d EV3 flash sectors...\n" , sector_count );
8172
82- puts ("Downloading..." );
83- err = bootloader_start (FLASH_START , FLASH_SIZE ); // extremely short
84- if (err != ERR_UNK )
85- return err ;
86- err = bootloader_send (fp , FLASH_SIZE , & local_crc32 ); // variable time
87- if (err != ERR_UNK )
88- return err ;
89-
90- puts ("Calculating flash checksum... (takes 17 seconds)" );
91- err = bootloader_checksum (FLASH_START , FLASH_SIZE , & remote_crc32 ); // 16.7 seconds
73+ int err = ERR_UNK ;
74+ const char * last_area = NULL ;
75+ for (int sector = 0 ; sector < sector_count ; sector ++ ) {
76+ u32 local_crc32 = 0 ;
77+ u32 remote_crc32 = 0 ;
9278
93- // handle usb 3.0 bug
94- if (err == ERR_USBLOOP )
95- {
96- puts ("Checksum not checked, assuming update was OK. Rebooting." );
97- }
98- else if (err == ERR_UNK ) // no error occurred
99- {
100- if (local_crc32 != remote_crc32 ) {
101- fprintf (stderr , "error: checksums do not match: remote %08X != local %08X\n" ,
102- remote_crc32 , local_crc32 );
103- return ERR_IO ;
104- } else {
105- puts ("Success! Local and remote checksums match. Rebooting." );
79+ const char * area = sector_explanation (sector );
80+ if (last_area != area ) {
81+ printf ("=== %s ===\n" , area );
82+ last_area = area ;
10683 }
107- }
108- else // other error occurred
109- {
110- return err ;
111- }
11284
113- return bootloader_exit ();
114- }
85+ printf ("- Sector %3d (%2d %%)\n" , sector , 100 * sector /sector_count );
86+ err = bootloader_erase_and_start (sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE );
87+ if (err != ERR_UNK ) {
88+ puts ("Flash erase returned an error!" );
89+ break ;
90+ }
11591
116- static int bootloader_erase (void )
117- {
118- FW_ERASEFLASH * request = packet_alloc (FW_ERASEFLASH , 0 );
119- int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
120- if (res < 0 )
121- {
122- errmsg = "Unable to write FW_ERASEFLASH." ;
123- return ERR_COMM ;
124- }
92+ err = bootloader_send (firmware + sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE , & local_crc32 );
93+ if (err != ERR_UNK ) {
94+ puts ("Programming returned an error!" );
95+ break ;
96+ }
12597
126- FW_ERASEFLASH_REPLY * reply = malloc (sizeof (FW_ERASEFLASH_REPLY ));
127- res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_ERASEFLASH_REPLY ), -1 );
128- if (res <= 0 )
129- {
130- errmsg = "Unable to read FW_ERASEFLASH" ;
131- return ERR_COMM ;
98+ err = bootloader_checksum (sector * FLASH_SECTOR_SIZE , FLASH_SECTOR_SIZE , & remote_crc32 );
99+ if (err == ERR_USBLOOP && sector == 0 )
100+ {
101+ puts ("NOTE: CRC not checked, because the brick is likely plugged to a USB 3.0 port." );
102+ }
103+ else if (err == ERR_UNK ) // no error occurred
104+ {
105+ if (local_crc32 != remote_crc32 ) {
106+ printf ("Checksum does not match: remote %08X != local %08X\n" , remote_crc32 , local_crc32 );
107+ err = ERR_COMM ;
108+ break ;
109+ }
110+ }
111+ else // other error occurred
112+ {
113+ puts ("Checksum computation returned an error!" );
114+ break ;
115+ }
132116 }
133117
134- // note: accept looped-back packets (usb 3.0 bug; reply not required here)
135- if (reply -> type != VM_OK && reply -> type != VM_SYS_RQ )
136- {
137- errno = reply -> ret ;
138- fputs ("Operation failed.\nlast_reply=" , stderr );
139- print_bytes (reply , reply -> packetLen + 2 );
140-
141- errmsg = "`FW_ERASEFLASH` was denied." ;
142- return ERR_VM ;
118+ free (firmware );
119+ if (err == ERR_UNK ) {
120+ puts ("Flashing finished, rebooting the brick." );
121+ return bootloader_exit ();
122+ } else {
123+ puts ("Some error occurred, leaving the brick in the bootloader mode." );
124+ puts ("To exit it manually, simply remove the EV3 battery and then put it back in." );
125+ return err ;
143126 }
144- return ERR_UNK ;
145127}
146128
147- static int bootloader_start (int offset , int length )
129+ static int bootloader_erase_and_start (int offset , int length )
148130{
149- FW_START_DOWNLOAD * request = packet_alloc (FW_START_DOWNLOAD , 0 );
131+ FW_START_DOWNLOAD_WITH_ERASE * request = NULL ;
132+ FW_START_DOWNLOAD_WITH_ERASE_REPLY * reply = NULL ;
133+ int err ;
134+
135+ request = packet_alloc (FW_START_DOWNLOAD_WITH_ERASE , 0 );
150136 request -> flashStart = offset ;
151137 request -> flashLength = length ;
152138 int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
153139 if (res < 0 )
154140 {
155141 errmsg = "Unable to write FW_START_DOWNLOAD." ;
156- return ERR_COMM ;
142+ err = ERR_COMM ;
143+ goto exit ;
157144 }
158145
159- FW_START_DOWNLOAD_REPLY * reply = malloc (sizeof (FW_START_DOWNLOAD_REPLY ));
160- res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_START_DOWNLOAD_REPLY ), -1 );
146+ reply = malloc (sizeof (FW_START_DOWNLOAD_WITH_ERASE_REPLY ));
147+ res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_START_DOWNLOAD_WITH_ERASE_REPLY ), -1 );
161148 if (res <= 0 )
162149 {
163150 errmsg = "Unable to read FW_START_DOWNLOAD" ;
164- return ERR_COMM ;
151+ err = ERR_COMM ;
152+ goto exit ;
165153 }
166154
167155 // note: accept looped-back packets (usb 3.0 bug; reply not required here)
@@ -171,43 +159,35 @@ static int bootloader_start(int offset, int length)
171159 fputs ("Operation failed.\nlast_reply=" , stderr );
172160 print_bytes (reply , reply -> packetLen + 2 );
173161
174- errmsg = "`FW_START_DOWNLOAD` was denied." ;
175- return ERR_VM ;
162+ errmsg = "`FW_START_DOWNLOAD_WITH_ERASE_REPLY` was denied." ;
163+ err = ERR_VM ;
164+ goto exit ;
176165 }
177- return ERR_UNK ;
166+ err = ERR_UNK ;
167+
168+ exit :
169+ free (request );
170+ free (reply );
171+ return err ;
178172}
179173
180- static int bootloader_send (FILE * fp , int length , u32 * pCrc32 )
174+ static int bootloader_send (u8 * buffer , int length , u32 * pCrc32 )
181175{
182- * pCrc32 = 0 ;
183-
184- int max_payload = 1024 - (sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + 2 );
176+ const int max_payload = 1024 - (sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + 2 );
185177 FW_DOWNLOAD_DATA * request = packet_alloc (FW_DOWNLOAD_DATA , max_payload );
186178 FW_DOWNLOAD_DATA_REPLY * reply = malloc (sizeof (FW_DOWNLOAD_DATA_REPLY ));
187179
188180 int total = length ;
189181 int sent_so_far = 0 ;
190- int file_ended = 0 ;
191- int res = 0 ;
192- int last_percent = 0 ;
182+ int err = ERR_UNK ;
193183 u32 crc = 0 ;
194184
195- printf ("Progress: %3d %%\n" , 0 );
196-
197185 while (sent_so_far < total ) {
198186 int remaining = total - sent_so_far ;
199187 int this_block = remaining <= max_payload ? remaining : max_payload ;
188+ int res ;
200189
201- if (!file_ended ) {
202- int real = fread (request -> payload , 1 , this_block , fp );
203- if (real < this_block ) {
204- file_ended = 1 ;
205- memset (request -> payload + real , 0 , this_block - real );
206- }
207- } else {
208- memset (request -> payload , 0 , this_block );
209- }
210-
190+ memcpy (request -> payload , buffer + sent_so_far , this_block );
211191 crc = crc32 (crc , request -> payload , this_block );
212192
213193 request -> packetLen = sizeof (FW_DOWNLOAD_DATA ) - PREFIX_SIZE + this_block ;
@@ -216,14 +196,16 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32)
216196 if (res < 0 )
217197 {
218198 errmsg = "Unable to write FW_DOWNLOAD_DATA." ;
219- return ERR_COMM ;
199+ err = ERR_COMM ;
200+ break ;
220201 }
221202
222203 res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_DOWNLOAD_DATA_REPLY ), -1 );
223204 if (res <= 0 )
224205 {
225206 errmsg = "Unable to read FW_DOWNLOAD_DATA" ;
226- return ERR_COMM ;
207+ err = ERR_COMM ;
208+ break ;
227209 }
228210
229211 // note: accept looped-back packets (usb 3.0 bug; reply not required here)
@@ -234,19 +216,17 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32)
234216 print_bytes (reply , reply -> packetLen + 2 );
235217
236218 errmsg = "`FW_DOWNLOAD_DATA` was denied." ;
237- return ERR_VM ;
219+ err = ERR_VM ;
220+ break ;
238221 }
239222
240223 sent_so_far += this_block ;
241-
242- int new_percent = sent_so_far * 100 / total ;
243- if (new_percent >= last_percent + 5 ) {
244- last_percent += ((new_percent - last_percent ) / 5 ) * 5 ;
245- printf ("Progress: %3d %%\n" , last_percent );
246- }
247224 }
225+
248226 * pCrc32 = crc ;
249- return ERR_UNK ;
227+ free (request );
228+ free (reply );
229+ return err ;
250230}
251231
252232/**
@@ -358,30 +338,37 @@ static bool sector_is_mutable(u32 sector_number)
358338
359339static int bootloader_checksum (int offset , int length , u32 * pCrc32 )
360340{
341+ FW_GETCRC32 * request = NULL ;
342+ FW_GETCRC32_REPLY * reply = NULL ;
343+ int err ;
344+
361345 * pCrc32 = 0 ;
362346
363- FW_GETCRC32 * request = packet_alloc (FW_GETCRC32 , 0 );
347+ request = packet_alloc (FW_GETCRC32 , 0 );
364348 request -> flashStart = offset ;
365349 request -> flashLength = length ;
366350 int res = ev3_write (handle , (u8 * ) request , request -> packetLen + PREFIX_SIZE );
367351 if (res < 0 )
368352 {
369353 errmsg = "Unable to write FW_GETCRC32." ;
370- return ERR_COMM ;
354+ err = ERR_COMM ;
355+ goto exit ;
371356 }
372357
373- FW_GETCRC32_REPLY * reply = malloc (sizeof (FW_GETCRC32_REPLY ));
358+ reply = malloc (sizeof (FW_GETCRC32_REPLY ));
374359 res = ev3_read_timeout (handle , (u8 * ) reply , sizeof (FW_GETCRC32_REPLY ), -1 );
375360 if (res <= 0 )
376361 {
377362 errmsg = "Unable to read FW_GETCRC32" ;
378- return ERR_COMM ;
363+ err = ERR_COMM ;
364+ goto exit ;
379365 }
380366
381367 // note: report loopback bug to outer code
382368 if (reply -> type == VM_SYS_RQ )
383369 {
384- return ERR_USBLOOP ;
370+ err = ERR_USBLOOP ;
371+ goto exit ;
385372 }
386373
387374 if (reply -> type != VM_OK )
@@ -391,8 +378,14 @@ static int bootloader_checksum(int offset, int length, u32 *pCrc32)
391378 print_bytes (reply , reply -> packetLen + 2 );
392379
393380 errmsg = "`FW_GETCRC32` was denied." ;
394- return ERR_VM ;
381+ err = ERR_VM ;
382+ goto exit ;
395383 }
396384 * pCrc32 = reply -> crc32 ;
397- return ERR_UNK ;
385+ err = ERR_UNK ;
386+
387+ exit :
388+ free (request );
389+ free (reply );
390+ return err ;
398391}
0 commit comments