Commit 8e4434caffc71abb2fd984e807c70bb211c99a68
authorMichel <michel@acer.vidiactive.com>
Wed, 10 Mar 2010 18:04:53 +0000 (18:04 +0000)
committerMichel <michel@acer.vidiactive.com>
Wed, 10 Mar 2010 18:04:53 +0000 (18:04 +0000)
.hex files can contain more than one section of data
this new loader handles that, allowing to have multiple
section of flash (app + bootloader) and/or eeprom.
Oh, a test unit too.

Signed-off-by: Michel Pollet <buserror@gmail.com>
2 files changed:
simavr/sim/sim_hex.c
simavr/sim/sim_hex.h

index 628032077445a239e4c248089a7b2efe53808235..0a8b10fd96b51104925cc2329e601699168d7688 100644 (file)
@@ -137,3 +137,98 @@ uint8_t * read_ihex_file(const char * fname, uint32_t * dsize, uint32_t * start)
        fclose(f);
        return res;
 }
+
+
+int read_ihex_chunks(const char * fname, struct ihex_chunk_t * chunks, int max_chunks)
+{
+       if (!fname || !chunks || !max_chunks)
+               return -1;
+       memset((void*)chunks, 0, sizeof(chunks[0]) * max_chunks);
+       FILE * f = fopen(fname, "r");
+       if (!f) {
+               perror(fname);
+               return -1;
+       }
+       uint32_t segment = 0;   // segment address
+       int chunk = 0;
+       chunks[0].baseaddr = ~0;
+
+       while (!feof(f)) {
+               char line[128];
+               if (!fgets(line, sizeof(line)-1, f))
+                       continue;
+               if (line[0] != ':') {
+                       fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line);
+                       break;
+               }
+               uint8_t bline[64];
+
+               int len = read_hex_string(line + 1, bline, sizeof(bline));
+               if (len <= 0)
+                       continue;
+
+               uint8_t chk = 0;
+               {       // calculate checksum
+                       uint8_t * src = bline;
+                       int tlen = len-1;
+                       while (tlen--)
+                               chk += *src++;
+                       chk = 0x100 - chk;
+               }
+               if (chk != bline[len-1]) {
+                       fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]);
+                       break;
+               }
+               uint32_t addr = 0;
+               switch (bline[3]) {
+                       case 0: // normal data
+                               addr = segment + (bline[1] << 8) | bline[2];
+                               break;
+                       case 1: // end of file
+                               continue;
+                       case 2: // extended address 2 bytes
+                               segment = ((bline[4] << 8) | bline[5]) << 4;
+                               continue;
+                       case 4:
+                               segment = ((bline[4] << 8) | bline[5]) << 16;
+                               continue;
+                       default:
+                               fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]);
+                               continue;
+               }
+               if (addr != chunks[chunk].baseaddr + chunks[chunk].size) {
+                       if (chunks[chunk].size)
+                               chunk++;
+                       chunks[chunk].baseaddr = addr;
+               }
+               chunks[chunk].data = realloc(chunks[chunk].data, chunks[chunk].size + bline[0]);
+               memcpy(chunks[chunk].data + chunks[chunk].size, bline + 4, bline[0]);
+               chunks[chunk].size += bline[0];
+       }
+       if (chunks[chunk].size)
+               chunk++;
+       fclose(f);
+       return chunk;
+}
+
+
+#ifdef IHEX_TEST
+// gcc -std=gnu99 -Isimavr/sim simavr/sim/sim_hex.c -o sim_hex -DIHEX_TEST
+int main(int argc, char * argv[])
+{
+       struct ihex_chunk_t chunk[4];
+       
+       for (int fi = 1; fi < argc; fi++) {
+               int c = read_ihex_chunks(argv[fi], chunk, 4);
+               if (c == -1) {
+                       perror(argv[fi]);
+                       continue;
+               }
+               for (int ci = 0; ci < c; ci++) {
+                       char n[96];
+                       sprintf(n, "%s[%d] = %08x", argv[fi], ci, chunk[ci].baseaddr);
+                       hdump(n, chunk[ci].data, chunk[ci].size);
+               }
+       }
+}
+#endif
index caf0afcb5d647cd291ad5e5812dc1f48abc05c48..83f50db5002302061e27f4669b1c0f7f26e73ac8 100644 (file)
 // parses a hex text string 'src' of at max 'maxlen' characters, decodes it into 'buffer'
 int read_hex_string(const char * src, uint8_t * buffer, int maxlen);
 
+// a .hex file chunk (base address + size)
+struct ihex_chunk_t {
+       uint32_t baseaddr;      // offset it started at in the .hex file
+       uint8_t * data;         // read data
+       uint32_t size;          // read data size
+};
+
+/*
+ * Read a .hex file, detects the various different chunks in it from their starting
+ * addresses and fills up the chunks passed as arguments up to max_chunks.
+ * Returns the number of chunks found, or -1 if an error occurs.
+ */
+int read_ihex_chunks(const char * fname, struct ihex_chunk_t * chunks, int max_chunks);
+
 // reads IHEX file 'fname', puts it's decoded size in *'dsize' and returns
 // a newly allocated buffer with the binary data (or NULL, if error)
 uint8_t * read_ihex_file(const char * fname, uint32_t * dsize, uint32_t * start);