int main (int argc, const char * argv[]) { FILE *fp, *fp_write; AtmelGenericRecord arec; IHexRecord irec; SRecord srec; int addr; int nodeid; if (argc < 3) { fprintf(stderr, "Usage: %s <file format> <file>\n", argv[0]); fprintf(stderr, "This program will print the records saved in a generic,\nIntel HEX, or Motorola S-Record formatted file.\n\n"); fprintf(stderr, "<file format> can be generic, ihex, or srecord.\n"); fprintf(stderr, "<file> is the path to the file containing the records.\n"); return -1; } fp = fopen(argv[2], "r"); if (fp == NULL) { perror("Error opening file!"); return -1; } fp_write = fopen(argv[3], "w"); if (fp_write == NULL) { perror("Error opening file!"); return -1; } addr = strtol(argv[4], (char **)NULL, 16); nodeid = strtol(argv[5], (char **)NULL, 10); if (strcasecmp(argv[1], "generic") == 0) { while (Read_AtmelGenericRecord(&arec, fp) == ATMEL_GENERIC_OK) { Print_AtmelGenericRecord(&arec); printf("\n"); } } else if (strcasecmp(argv[1], "ihex") == 0) { while (Read_IHexRecord(&irec, fp) == IHEX_OK) { Write_IHexRecord(&irec, fp_write, addr, nodeid); } } else if (strcasecmp(argv[1], "srecord") == 0) { while (Read_SRecord(&srec, fp) == SRECORD_OK) { Print_SRecord(&srec); printf("\n"); } } else { fprintf(stderr, "Invalid file format specified!\n"); fclose(fp); fclose(fp_write); return -1; } fclose(fp); return 0; }
int byte_stream_ihex_read(struct ByteStream *self, uint8_t *data, uint32_t *address) { struct byte_stream_ihex_state *state = (struct byte_stream_ihex_state *)self->state; int ret; if (state->availBytes == 0) { do { /* Read the next record */ ret = Read_IHexRecord(&(state->iRec), self->in); switch (ret) { case IHEX_OK: break; case IHEX_ERROR_NEWLINE: continue; case IHEX_ERROR_EOF: return STREAM_EOF; case IHEX_ERROR_FILE: self->error = "Error reading Intel HEX formatted file!"; return STREAM_ERROR_INPUT; case IHEX_ERROR_INVALID_RECORD: self->error = "Invalid Intel HEX formatted file!"; return STREAM_ERROR_INPUT; default: self->error = "Unknown error reading Intel HEX formatted file!"; return STREAM_ERROR_INPUT; } /* Continue reading until we get a data record */ } while(state->iRec.type != IHEX_TYPE_00); /* Update our available bytes counter */ state->availBytes = state->iRec.dataLen; } if (state->availBytes) { /* Copy over next low byte (assuming little-endian) */ *data = state->iRec.data[ (state->iRec.dataLen - state->availBytes) ]; *address = (uint32_t)state->iRec.address + (uint32_t)(state->iRec.dataLen - state->availBytes); state->availBytes--; } return 0; }
int flashIHexFile(FIL* file) { IHexRecord irec; flashsector_t sector; bool erasedSectors[FLASH_SECTOR_COUNT] = { FALSE }; flashaddr_t baseAddress = 0; flashaddr_t address = 0; while (Read_IHexRecord(&irec, file) == IHEX_OK) { switch (irec.type) { case IHEX_TYPE_00: /**< Data Record */ /* Compute the target address in flash */ address = baseAddress + irec.address; /* Erase the corresponding addresses if needed */ for (sector = flashSectorAt(address); sector <= flashSectorAt(address + irec.dataLen - 1); ++sector) { /* Check if the sector has been erased during this IHex flashing procedure to prevent erasing already written data */ if (erasedSectors[sector] == TRUE) continue; /* Check if the sector in flash needs to be erased */ if (flashIsErased(flashSectorBegin(sector), flashSectorSize(sector)) == FALSE) { /* Erase the sector */ if (flashSectorErase(sector) != FLASH_RETURN_SUCCESS) return BOOTLOADER_ERROR_BADFLASH; } /* Set the erased flag to prevent erasing the same sector twice during the IHex flashing procedure */ erasedSectors[sector] = TRUE; } /* Write the data in flash */ if (flashWrite(address, (const char*)irec.data, irec.dataLen) != FLASH_RETURN_SUCCESS) return BOOTLOADER_ERROR_BADFLASH; break; case IHEX_TYPE_04: /**< Extended Linear Address Record */ /* Compute the base address of the following data records */ baseAddress = irec.data[0]; baseAddress <<= 8; baseAddress += irec.data[1]; baseAddress <<= 16; break; case IHEX_TYPE_01: /**< End of File Record */ /* Check that the end of file record is at the end of the file... */ return f_eof(file) ? BOOTLOADER_SUCCESS : BOOTLOADER_ERROR_BADHEX; case IHEX_TYPE_05: /**< Start Linear Address Record */ /* Ignored */ break; case IHEX_TYPE_02: /**< Extended Segment Address Record */ case IHEX_TYPE_03: /**< Start Segment Address Record */ /* Not supported */ return BOOTLOADER_ERROR_BADHEX; } } return BOOTLOADER_ERROR_BADHEX; }
/* write fn to device */ int nrf_program_nrf24lu(devp dev, const char *fn){ unsigned char cmd[2], data[64], *flash_copy, dirty_bv[64]; FILE *fp = NULL; int ecode, block, page, rc; unsigned int first_addr, last_addr; IHexRecord record; printf("Programming nRF24LU\n"); /* read the entire ROM into memory * * Why? Because Nordic doesn't have decent software. Their flash write * command erases the page first, instead of letting me decide if the page * should be erased first. * * Byte-level writing is offered by using a read-modify-write operation. * It would be smarter to operate on a per-page basis, but Intel HEX files * are not guaranteed to have sequential addressing. Since Nordic screwed * up and wild IHX files are adhoc, let's work with the whole 32k flash * memory at once. */ if((flash_copy = malloc(FLASH_SIZE)) == NULL){ ecode = -4; goto err; } printf("[*] Reading device.\n"); for(block = 0; block < 0x200; block++){ /* set address MSB */ if((block % 0x100) == 0){ cmd[0] = 0x06; cmd[1] = (unsigned char)(block / 256); if(nrf_cmd(dev, cmd, 2, data, 1)){ ecode = -2; goto err; } } /* request the block */ cmd[0] = 0x03; cmd[1] = (unsigned char)block; if(nrf_cmd(dev, cmd, 2, &flash_copy[block2addr(block)], 64)){ ecode = -2; goto err; } } /* overwrite in-memory with IHX contents */ if((fp = fopen(fn, "r")) == NULL){ ecode = -1; goto err; } memset(dirty_bv, 0, sizeof(dirty_bv)); while((rc = Read_IHexRecord(&record, fp)) == IHEX_OK && record.type != IHEX_TYPE_01){ if(record.type != IHEX_TYPE_00){ /* we cannot process segment or linear ihex files */ printf("[!] IHX file contains segment or linear addressing.\n"); ecode = -5; goto err; } /* first and last byte that is touched by this record */ first_addr = record.address; last_addr = record.address + record.dataLen - 1; if(!addr_valid(first_addr) || !addr_valid(last_addr)){ printf("[!] IHX record touches invalid or protected bytes: " "0x%04X - 0x%04X\n", first_addr, last_addr); ecode = -6; goto err; } /* only write if the ihx record changes memory */ if(memcmp(&flash_copy[first_addr], record.data, record.dataLen)){ /* copy record into memory */ memcpy(&flash_copy[first_addr], record.data, record.dataLen); /* mark dirty blocks */ for(block = addr2block(first_addr); block <= addr2block(last_addr); block++){ /* check the block since we might have some *really* long * record */ if(!addr_valid(block2addr(block))){ printf("[!] IHX record touches invalid or protected bytes:" " 0x%04X\n", block2addr(block)); ecode = -6; goto err; } bitset(dirty_bv, block); } } } if(rc != IHEX_OK && rc != IHEX_ERROR_EOF){ /* we had an error that isn't EOF */ ecode = -4; goto err; } /* write to flash */ printf("[*] Writing device"); fflush(stdout); for(page = 0; page < 64; page++){ /* Each page is 8 blocks, which conviently maps to our dirty bit vector * on byte boundries. */ if(dirty_bv[page]){ printf("."); fflush(stdout); if(nrf_write_page(dev, page, &flash_copy[page2addr(page)])){ printf("\n[!] Write failed.\n"); ecode = -7; goto err; } } } printf("\n"); /* verify */ printf("[*] Verifying device"); fflush(stdout); for(block = 0; block < 512; block++){ if(bitisset(dirty_bv, block)){ if(nrf_compare_block(dev, block, &flash_copy[block2addr(block)])){ printf("\n[!] Block %d failed.\n", block); ecode = -8; goto err; } else { printf("."); fflush(stdout); } } } printf("\n"); ecode = 0; err: if(flash_copy){ free(flash_copy); } if(fp){ fclose(fp); } return ecode; }