|
6 | 6 | */ |
7 | 7 | #include <stdio.h> |
8 | 8 | #include <stdlib.h> |
| 9 | +#include <stdbool.h> |
9 | 10 | #include <string.h> |
10 | 11 | #include <errno.h> |
11 | 12 |
|
@@ -46,10 +47,6 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32); |
46 | 47 | */ |
47 | 48 | static int bootloader_checksum(int offset, int length, u32 *pCrc32); |
48 | 49 |
|
49 | | -/* this matches LEGO FW sizes */ |
50 | | -#define FLASH_START 0x00000000 |
51 | | -#define FLASH_SIZE (16 * 1000 * 1024) |
52 | | - |
53 | 50 | /** |
54 | 51 | * @brief Install new firmware binary to the internal flash. |
55 | 52 | * @param fp Firmware file to download to the brick. |
@@ -238,6 +235,69 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32) |
238 | 235 | return ERR_UNK; |
239 | 236 | } |
240 | 237 |
|
| 238 | +/** |
| 239 | + * @brief Compare CRCs of the flash memory and the firmware image. |
| 240 | + * @param fp Firmware file that is supposed to be flashed in the brick. |
| 241 | + * @param starting_sector First 64 KiB sector of the flash memory to check (0-based) |
| 242 | + * @param num_sectors Number of 64 KiB sectors to check |
| 243 | + * @param verbose If true, CRC is checked for each sector individually. |
| 244 | + * Otherwise, it is computed across all sectors at once. |
| 245 | + * @retval error according to enum #ERR |
| 246 | + */ |
| 247 | +int bootloader_crc(FILE *fp, u32 starting_sector, u32 num_sectors, bool verbose) |
| 248 | +{ |
| 249 | + u8 *firmware = calloc(FLASH_SIZE, 1); |
| 250 | + int read_bytes = fread(firmware, 1, FLASH_SIZE, fp); |
| 251 | + if (read_bytes != FLASH_SIZE) { |
| 252 | + printf("WARNING: firmware file might be truncated: %d bytes expected, %d bytes read\n", FLASH_SIZE, read_bytes); |
| 253 | + } |
| 254 | + |
| 255 | + int err = ERR_UNK; |
| 256 | + if (verbose) { |
| 257 | + // Sector-by-sector CRC comparison. |
| 258 | + // Compares the remote and local CRCs of each sector, showing the results of each. |
| 259 | + printf("Sector CRC comparison:\n"); |
| 260 | + bool all_ok = true; |
| 261 | + for (u32 sector = starting_sector; sector < starting_sector + num_sectors; sector++) { |
| 262 | + u32 local_sector_crc32 = crc32(0, firmware + sector * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE); |
| 263 | + u32 remote_sector_crc32 = 0; |
| 264 | + int sector_err = bootloader_checksum(sector * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE, &remote_sector_crc32); |
| 265 | + |
| 266 | + bool this_ok = remote_sector_crc32 == local_sector_crc32; |
| 267 | + all_ok = all_ok && this_ok; |
| 268 | + |
| 269 | + if (sector_err == ERR_UNK) { |
| 270 | + printf("Sector %3d: Remote CRC = %08X, local CRC = %08X%s\n", sector, remote_sector_crc32, |
| 271 | + local_sector_crc32, this_ok ? "" : " ERR"); |
| 272 | + } else { |
| 273 | + printf("Error requesting sector CRC. Err = %i\n", sector_err); |
| 274 | + err = sector_err; |
| 275 | + } |
| 276 | + } |
| 277 | + |
| 278 | + if (all_ok) { |
| 279 | + puts("All sectors match."); |
| 280 | + } else { |
| 281 | + puts("Some sectors do not match."); |
| 282 | + } |
| 283 | + } else { |
| 284 | + // Do a single comparison, calculating the CRC over multiple sectors. |
| 285 | + u32 local_crc32 = crc32(0, firmware + starting_sector * FLASH_SECTOR_SIZE, num_sectors * FLASH_SECTOR_SIZE); |
| 286 | + printf("Requesting remote CRC...\n"); |
| 287 | + u32 remote_crc32 = 0; |
| 288 | + err = bootloader_checksum(starting_sector * FLASH_SECTOR_SIZE, num_sectors * FLASH_SECTOR_SIZE, &remote_crc32); |
| 289 | + if (err == ERR_UNK) { |
| 290 | + printf("Remote CRC = %08X, local CRC = %08X%s\n", remote_crc32, local_crc32, |
| 291 | + remote_crc32 == local_crc32 ? "" : " ERR"); |
| 292 | + } else { |
| 293 | + printf("Error requesting full CRC. Err = %i\n", err); |
| 294 | + } |
| 295 | + } |
| 296 | + |
| 297 | + free(firmware); |
| 298 | + return err; |
| 299 | +} |
| 300 | + |
241 | 301 | static int bootloader_checksum(int offset, int length, u32 *pCrc32) |
242 | 302 | { |
243 | 303 | *pCrc32 = 0; |
|
0 commit comments