Skip to content

Commit ff9d1c9

Browse files
gtminchJakubVanek
authored andcommitted
feat(flash): Add "flash crc" command
"flash crc" gives the user various ways of comparing the CRC of a file to the CRC reported by the EV3 bootloader. Can do that for the full image, or a group of sectors, or sector-by-sector.
1 parent 5ceca38 commit ff9d1c9

File tree

3 files changed

+119
-4
lines changed

3 files changed

+119
-4
lines changed

src/bl_install.c

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
#include <stdio.h>
88
#include <stdlib.h>
9+
#include <stdbool.h>
910
#include <string.h>
1011
#include <errno.h>
1112

@@ -46,10 +47,6 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32);
4647
*/
4748
static int bootloader_checksum(int offset, int length, u32 *pCrc32);
4849

49-
/* this matches LEGO FW sizes */
50-
#define FLASH_START 0x00000000
51-
#define FLASH_SIZE (16 * 1000 * 1024)
52-
5350
/**
5451
* @brief Install new firmware binary to the internal flash.
5552
* @param fp Firmware file to download to the brick.
@@ -238,6 +235,69 @@ static int bootloader_send(FILE *fp, int length, u32* pCrc32)
238235
return ERR_UNK;
239236
}
240237

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+
241301
static int bootloader_checksum(int offset, int length, u32 *pCrc32)
242302
{
243303
*pCrc32 = 0;

src/funcs.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include <stdio.h>
1919
#include <stddef.h>
20+
#include <stdbool.h>
21+
2022
/**
2123
* @name General Usage
2224
* @ingroup EV3 commands
@@ -71,6 +73,18 @@ extern int bootloader_enter(void);
7173
//! install new firmware to the brick
7274
extern int bootloader_install(FILE *fp);
7375

76+
// First address of EV3 flash memory
77+
#define FLASH_START 0x00000000
78+
// Size of EV3 flash memory in bytes
79+
#define FLASH_SIZE (16 * 1000 * 1024)
80+
// Size of EV3 flash memory erase block
81+
#define FLASH_SECTOR_SIZE (64*1024) // N25Q128 datasheet says that it has 64-Kbyte sectors/eraseblocks
82+
// Number of sectors in EV3 flash memory
83+
#define FLASH_SECTOR_COUNT (FLASH_SIZE / FLASH_SECTOR_SIZE)
84+
85+
//! compare device CRC to CRC from a file
86+
extern int bootloader_crc(FILE *fp, u32 starting_sector, u32 num_sectors, bool verbose);
87+
7488
//! print brick hardware version
7589
extern int bootloader_info(void);
7690

src/main.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdlib.h>
1212
#include <string.h>
1313
#include <errno.h>
14+
#include <stdbool.h>
1415

1516
#include <hidapi/hidapi.h>
1617

@@ -154,6 +155,9 @@ const char *const usage_desc = "Info:\n"
154155
"flash install install the given firmware file to the EV3\n"
155156
"flash info show hardware and EEPROM versions\n"
156157
"flash exit exit from the firmware update mode without installing new firmware\n"
158+
"flash crc compares CRCs of the given firmware file and the EV3 installed firmware\n"
159+
"flash crc f n compares file/EV3 CRCs of a block of n 64k sectors, starting at sector #f (zero-based). Full size is 250 sectors.\n"
160+
"flash crc f n v verbose (sector-by-sector) file/EV3 CRC comparison, starting at sector #f (zero-based) and doing n sectors (max 250).\n"
157161
"uf2 pack pack files into a Microsoft UF2 container\n"
158162
" note: common brickdir options are: \n"
159163
" 'Projects' (internal flash, default), 'SD Card', 'USB Stick',\n"
@@ -656,6 +660,43 @@ int main(int argc, char *argv[])
656660

657661
ret = bootloader_install(fp);
658662

663+
} else if (strcmp(argv[0], "crc") == 0) {
664+
// ev3duder --usb flash crc firmware.bin Full CRC comparison
665+
// ev3duder --usb flash crc firmware.bin f n CRC comparison of n sectors, starting at sector f (zero-based)
666+
// ev3duder --usb flash crc firmware.bin f n v Verbose comparison: compare CRC of every sector, showing the results
667+
bool verbose = argc == 5 && strcmp(argv[4], "v") == 0;
668+
if (argc == 2) {
669+
fp = fopen(SANITIZE(argv[1]), "rb");
670+
if (!fp) {
671+
printf("File <%s> doesn't exist.\n", argv[1]);
672+
return ERR_IO;
673+
}
674+
printf("Comparing full device CRCs...\n");
675+
ret = bootloader_crc(fp, 0, FLASH_SECTOR_COUNT, false);
676+
677+
} else if (argc == 4 || verbose) {
678+
u32 first_sector = atol(argv[2]);
679+
if (first_sector >= FLASH_SECTOR_COUNT) first_sector = FLASH_SECTOR_COUNT - 1;
680+
u32 num_sectors = atol(argv[3]);
681+
if (num_sectors == 0) num_sectors = 1; // Doesn't make sense to do zero.
682+
if (first_sector + num_sectors > FLASH_SECTOR_COUNT) {
683+
num_sectors = FLASH_SECTOR_COUNT - first_sector;
684+
}
685+
fp = fopen(SANITIZE(argv[1]), "rb");
686+
if (!fp)
687+
{
688+
printf("File <%s> doesn't exist.\n", argv[1]);
689+
return ERR_IO;
690+
}
691+
printf("Comparing CRCs of sectors %d - %d (%d sectors)\n", first_sector,
692+
first_sector + num_sectors - 1, num_sectors);
693+
ret = bootloader_crc(fp, first_sector, num_sectors, verbose);
694+
695+
} else {
696+
ret = ERR_ARG;
697+
printf("Expected either <filename> or <filename firstsector numsectors>\n");
698+
}
699+
659700
} else if (strcmp(argv[0], "info") == 0) {
660701
assert(argc == 1);
661702
ret = bootloader_info();

0 commit comments

Comments
 (0)