From 53a1a41140fecb19e4addeeb7ed1def394e33670 Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Fri, 6 Jan 2017 16:11:55 +0100 Subject: [PATCH 1/7] Intial commit of fork. Purpose of fork is to add functionality to read and write Motorola S-record files --- srec.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ srec.h | 8 ++++++ 2 files changed, 94 insertions(+) create mode 100644 srec.c create mode 100644 srec.h diff --git a/srec.c b/srec.c new file mode 100644 index 0000000..7eb2395 --- /dev/null +++ b/srec.c @@ -0,0 +1,86 @@ +/* stlink/v2 stm8 memory programming utility + (c) Valentin Dudouyt, 2012 - 2014 */ + +#include +#include +#include +#include "srec.h" +#include "error.h" +#include "byte_utils.h" + +char line[256]; + +static unsigned char checksum(unsigned char *buf, unsigned int length, int chunk_len, int chunk_addr, int chunk_type) { + int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; + unsigned int i; + for(i = 0; i < length; i++) { + sum += buf[i]; + } + + int complement = (~sum + 1); + return complement & 0xff; +} + +int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { + fseek(pFile, 0, SEEK_SET); + unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; + while(fgets(line, sizeof(line), pFile)) { + line_no++; + // Reading chunk header + if(sscanf(line, ":%02x%04x%02x", &chunk_len, &chunk_addr, &chunk_type) != 3) { + free(buf); + ERROR2("Error while parsing IHEX at line %d\n", line_no); + } + // Reading chunk data + for(i = 9; i < strlen(line) - 1; i +=2) { + if(sscanf(&(line[i]), "%02x", &byte) != 1) { + free(buf); + ERROR2("Error while parsing IHEX at line %d byte %d\n", line_no, i); + } + if(chunk_type != 0x00) { + // The only data records have to be processed + continue; + } + if((i - 9) / 2 >= chunk_len) { + // Respect chunk_len and do not capture checksum as data + break; + } + if(chunk_addr < start) { + free(buf); + ERROR2("Address %04x is out of range at line %d\n", chunk_addr, line_no); + } + if(chunk_addr + chunk_len > end) { + free(buf); + ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, chunk_len, line_no); + } + if(chunk_addr + chunk_len > greatest_addr) { + greatest_addr = chunk_addr + chunk_len; + } + buf[chunk_addr - start + (i - 9) / 2] = byte; + } + } + + return(greatest_addr - start); +} + +void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { + unsigned int chunk_len, chunk_start, chunk_type, i, byte, line_no = 0, greatest_addr = 0; + chunk_start = start; + while(chunk_start < end) + { + chunk_len = end - chunk_start; + if (chunk_len > 32) + { + chunk_len = 32; + } + fprintf(pFile, ":%02X%04X00",chunk_len,chunk_start); + for(i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) + { + fprintf(pFile, "%02X",buf[i]); + } + fprintf(pFile, "%02X\n", checksum( &buf[chunk_start - start], chunk_len, chunk_len, chunk_start, 0)); + + chunk_start += chunk_len; + } + fprintf(pFile,":00000001FF\n"); +} diff --git a/srec.h b/srec.h new file mode 100644 index 0000000..52b3cc6 --- /dev/null +++ b/srec.h @@ -0,0 +1,8 @@ +#ifndef __SREC_H +#define __SREC_H + +int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); + +void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); + +#endif From dfa3d061483228bab80c1eab55534c802a3cd06e Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Fri, 6 Jan 2017 16:17:33 +0100 Subject: [PATCH 2/7] Intial fork of stm8flash. Purpose of fork is to add functionality to enable the reading and writing of Motorola S-records. --- .gitignore | 1 + Makefile | 2 +- main.c | 32 +++++++++++++++++++++++--------- pgm.h | 3 +-- srec.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index c343f00..7049123 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ *.ihx *.hex *.exe +*.gch tags diff --git a/Makefile b/Makefile index ca7e634..7b47f50 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ override CFLAGS := $(BASE_CFLAGS) $(LIBUSB_CFLAGS) $(CFLAGS) BIN =stm8flash -OBJECTS =stlink.o stlinkv2.o main.o byte_utils.o ihex.o stm8.o +OBJECTS =stlink.o stlinkv2.o main.o byte_utils.o ihex.o srec.o stm8.o .PHONY: all clean install diff --git a/main.c b/main.c index 28e4087..fae5d63 100644 --- a/main.c +++ b/main.c @@ -13,6 +13,7 @@ #include "stlinkv2.h" #include "stm8.h" #include "ihex.h" +#include "srec.h" #ifdef __APPLE__ extern char *optarg; @@ -32,8 +33,8 @@ programmer_t pgms[] = { stlink_swim_read_range, stlink_swim_write_range, }, - { - "stlinkv2", + { + "stlinkv2", 0x0483, 0x3748, stlink2_open, @@ -130,7 +131,8 @@ const stm8_device_t *get_part(const char *name) } int main(int argc, char **argv) { - int start, bytes_count = 0; + unsigned int start; + int bytes_count = 0; char filename[256]; memset(filename, 0, sizeof(filename)); // Parsing command line @@ -241,7 +243,7 @@ int main(int argc, char **argv) { } if(memtype != UNKNOWN) { - // Selecting start addr depending on + // Selecting start addr depending on // specified part and memtype switch(memtype) { case RAM: @@ -296,6 +298,8 @@ int main(int argc, char **argv) { spawn_error("Couldn't initialize stlink"); if(!pgm->open(pgm)) spawn_error("Error communicating with MCU. Please check your SWIM connection."); + + FILE *f; if(action == READ) { fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); @@ -315,6 +319,11 @@ int main(int argc, char **argv) { fprintf(stderr, "Reading from Intel hex file "); ihex_write(f, buf, start, start+bytes_count); } + else if(is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) + { + fprintf(stderr, "Reading form Motorola S-record file "); + srec_write(f, buf, start, start+bytes_count); + } else { fwrite(buf, 1, bytes_count, f); @@ -347,9 +356,9 @@ int main(int argc, char **argv) { fseek(f, 0L, SEEK_END); bytes_to_verify = ftell(f); if(bytes_count_specified) { - bytes_to_verify = bytes_count; + bytes_to_verify = bytes_count; } else if(bytes_count < bytes_to_verify) { - bytes_to_verify = bytes_count; + bytes_to_verify = bytes_count; } fseek(f, 0, SEEK_SET); fread(buf2, 1, bytes_to_verify, f); @@ -363,6 +372,8 @@ int main(int argc, char **argv) { fprintf(stderr, "FAILED\n"); exit(-1); } + + } else if (action == WRITE) { if(!(f = fopen(filename, "r"))) spawn_error("Failed to open file"); @@ -376,14 +387,17 @@ int main(int argc, char **argv) { if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { fprintf(stderr, "Writing Intel hex file "); bytes_to_write = ihex_read(f, buf, start, start + bytes_count); + } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) { + fprintf(stderr, "Writing Motorola S-record file "); + bytes_to_write = srec_read(f, buf, start, start + bytes_count); } else { fprintf(stderr, "Writing binary file "); fseek(f, 0L, SEEK_END); bytes_to_write = ftell(f); if(bytes_count_specified) { - bytes_to_write = bytes_count; + bytes_to_write = bytes_count; } else if(bytes_count < bytes_to_write) { - bytes_to_write = bytes_count; + bytes_to_write = bytes_count; } fseek(f, 0, SEEK_SET); fread(buf, 1, bytes_to_write, f); @@ -411,7 +425,7 @@ int main(int argc, char **argv) { for (int i=0; i0)&&((i&1)==0)) buf[i]=0xff; - } + } } /* flashing MCU */ diff --git a/pgm.h b/pgm.h index f1c510f..d2f7131 100644 --- a/pgm.h +++ b/pgm.h @@ -3,7 +3,7 @@ #ifndef WIN32 #include - #include + #include "libusb.h" #else #include #endif @@ -52,4 +52,3 @@ typedef int (*pgm_read_range_cb)(programmer_t *, unsigned char *, unsigned int, typedef int (*pgm_write_range_cb)(programmer_t *, unsigned char *, unsigned int, unsigned int); #endif - diff --git a/srec.c b/srec.c index 7eb2395..e85ca54 100644 --- a/srec.c +++ b/srec.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "srec.h" #include "error.h" #include "byte_utils.h" @@ -21,27 +22,52 @@ static unsigned char checksum(unsigned char *buf, unsigned int length, int chunk return complement & 0xff; } + +static bool is_data_type(unsigned int chunk_type) +{ + return (chunk_type == 0x01 || chunk_type == 0x02 || chunk_type == 0x03); +} + + +//TODO This function has just been copied from ihex.c and does not work as intended. int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { fseek(pFile, 0, SEEK_SET); unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; + unsigned int number_of_records = 0; + + bool data_record = false; + unsigned int expected_data_records = 0; + while(fgets(line, sizeof(line), pFile)) { + data_record = true; //Assume that the read data is a data record. Set to false if not. line_no++; + // Reading chunk header - if(sscanf(line, ":%02x%04x%02x", &chunk_len, &chunk_addr, &chunk_type) != 3) { + if(sscanf(line, "S%01x%02x%04x", &chunk_type, &chunk_len, &chunk_addr) != 3) { free(buf); - ERROR2("Error while parsing IHEX at line %d\n", line_no); + ERROR2("Error while parsing SREC at line %d\n", line_no); + } + + if(chunk_type == 0x05) { //This will contain the total expected number of data records. Save for error checking later + if (chunk_len != 3) { // Length field must contain a 3 to be a valid S5 record. + ERROR2("Error while parsing S5 Record at line %d\n", line_no); + } + expected_data_records = chunk_addr; //The expected total number of data records is saved in S503 field. } + // Reading chunk data - for(i = 9; i < strlen(line) - 1; i +=2) { + for(i = 8; i < strlen(line) - 1; i +=2) { if(sscanf(&(line[i]), "%02x", &byte) != 1) { free(buf); - ERROR2("Error while parsing IHEX at line %d byte %d\n", line_no, i); + ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); } - if(chunk_type != 0x00) { + + if(!is_data_type(chunk_type)) { // The only data records have to be processed + data_record = false; continue; } - if((i - 9) / 2 >= chunk_len) { + if((i - 8) / 2 >= chunk_len) { // Respect chunk_len and do not capture checksum as data break; } @@ -56,13 +82,23 @@ int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int if(chunk_addr + chunk_len > greatest_addr) { greatest_addr = chunk_addr + chunk_len; } - buf[chunk_addr - start + (i - 9) / 2] = byte; + buf[chunk_addr - start + (i - 8) / 2] = byte; } + if(data_record) { //We found a data record. Remember this. + number_of_records++; + } + } + + //Check to see if the number of data records expected is the same as we actually read. + if(number_of_records != expected_data_records) { + ERROR2("Error while comparing S5 record (number of data records: %d) with the number actually read: %d\n", expected_data_records, number_of_records); } return(greatest_addr - start); + } +//TODO This function has just been copied from ihex.c and does not work as intended. void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { unsigned int chunk_len, chunk_start, chunk_type, i, byte, line_no = 0, greatest_addr = 0; chunk_start = start; @@ -73,7 +109,8 @@ void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned in { chunk_len = 32; } - fprintf(pFile, ":%02X%04X00",chunk_len,chunk_start); + // TODO Check if S1 is good to assume. Might not be correct, might be 1,2 or 3 here as a data record. + fprintf(pFile, "S1%02X%04X",chunk_len,chunk_start); for(i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) { fprintf(pFile, "%02X",buf[i]); From a9d0e3c6921cd226b27bc58fa022cb4f74dbdd06 Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Fri, 6 Jan 2017 16:23:34 +0100 Subject: [PATCH 3/7] Fixed an incorrect (added by me) include. --- pgm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgm.h b/pgm.h index d2f7131..9f3e578 100644 --- a/pgm.h +++ b/pgm.h @@ -3,7 +3,7 @@ #ifndef WIN32 #include - #include "libusb.h" + #include #else #include #endif From 9a164091a18bbd6b229264acfc0190e1154b23a9 Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Mon, 9 Jan 2017 20:44:49 +0100 Subject: [PATCH 4/7] Added functionality for reading .s8, .s19, .srec files and flashing them onto a STM8 device. Only tested on a 32K device (STM8AF5288) Dumping to SREC is _NOT_ supported yet. --- main.c | 786 +++++++++++++++++++++++++++++---------------------------- srec.c | 233 +++++++++-------- 2 files changed, 529 insertions(+), 490 deletions(-) diff --git a/main.c b/main.c index fae5d63..e10c428 100644 --- a/main.c +++ b/main.c @@ -1,19 +1,19 @@ /* stlink/v2 stm8 memory programming utility (c) Valentin Dudouyt, 2012 - 2014 */ +#include "ihex.h" +#include "pgm.h" +#include "srec.h" +#include "stlink.h" +#include "stlinkv2.h" +#include "stm8.h" +#include +#include #include #include #include #include #include -#include -#include -#include "pgm.h" -#include "stlink.h" -#include "stlinkv2.h" -#include "stm8.h" -#include "ihex.h" -#include "srec.h" #ifdef __APPLE__ extern char *optarg; @@ -24,418 +24,434 @@ extern int optreset; #endif programmer_t pgms[] = { - { "stlink", - 0x0483, // USB vid - 0x3744, // USB pid - stlink_open, - stlink_close, - stlink_swim_srst, - stlink_swim_read_range, - stlink_swim_write_range, - }, - { - "stlinkv2", - 0x0483, - 0x3748, - stlink2_open, - stlink_close, - stlink2_srst, - stlink2_swim_read_range, - stlink2_swim_write_range, - }, - { NULL }, + { + "stlink", + 0x0483, // USB vid + 0x3744, // USB pid + stlink_open, stlink_close, stlink_swim_srst, stlink_swim_read_range, + stlink_swim_write_range, + }, + { + "stlinkv2", 0x0483, 0x3748, stlink2_open, stlink_close, stlink2_srst, + stlink2_swim_read_range, stlink2_swim_write_range, + }, + {NULL}, }; void print_help_and_exit(const char *name, bool err) { - FILE *stream = err ? stderr : stdout; - fprintf(stream, "Usage: %s [-c programmer] [-p partno] [-s memtype] [-b bytes] [-r|-w|-v] \n", name); - fprintf(stream, "Options:\n"); - fprintf(stream, "\t-? Display this help\n"); - fprintf(stream, "\t-c programmer Specify programmer used (stlink or stlinkv2)\n"); - fprintf(stream, "\t-p partno Specify STM8 device\n"); - fprintf(stream, "\t-l List supported STM8 devices\n"); - fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, opt or explicit address)\n"); - fprintf(stream, "\t-b bytes Specify number of bytes\n"); - fprintf(stream, "\t-r Read data from device to file\n"); - fprintf(stream, "\t-w Write data from file to device\n"); - fprintf(stream, "\t-v Verify data in device against file\n"); - fprintf(stream, "\t-u Unlock. Reset option bytes to factory default to remove write protection.\n"); - exit(-err); + FILE *stream = err ? stderr : stdout; + fprintf(stream, "Usage: %s [-c programmer] [-p partno] [-s memtype] [-b " + "bytes] [-r|-w|-v] \n", + name); + fprintf(stream, "Options:\n"); + fprintf(stream, "\t-? Display this help\n"); + fprintf(stream, + "\t-c programmer Specify programmer used (stlink or stlinkv2)\n"); + fprintf(stream, "\t-p partno Specify STM8 device\n"); + fprintf(stream, "\t-l List supported STM8 devices\n"); + fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, " + "opt or explicit address)\n"); + fprintf(stream, "\t-b bytes Specify number of bytes\n"); + fprintf(stream, "\t-r Read data from device to file\n"); + fprintf(stream, "\t-w Write data from file to device\n"); + fprintf(stream, "\t-v Verify data in device against file\n"); + fprintf(stream, "\t-u Unlock. Reset option bytes to factory " + "default to remove write protection.\n"); + exit(-err); } void spawn_error(const char *msg) { - fprintf(stderr, "%s\n", msg); - exit(-1); + fprintf(stderr, "%s\n", msg); + exit(-1); } void dump_pgms(programmer_t *pgms) { - // Dump programmers list in stderr - int i; - for(i = 0; pgms[i].name; i++) - fprintf(stderr, "%s\n", pgms[i].name); + // Dump programmers list in stderr + int i; + for (i = 0; pgms[i].name; i++) + fprintf(stderr, "%s\n", pgms[i].name); } bool is_ext(const char *filename, const char *ext) { - char *ext_begin = strrchr(filename, '.'); - return(ext_begin && strcmp(ext_begin, ext) == 0); + char *ext_begin = strrchr(filename, '.'); + return (ext_begin && strcmp(ext_begin, ext) == 0); } bool usb_init(programmer_t *pgm, unsigned int vid, unsigned int pid) { - libusb_device **devs; - libusb_context *ctx = NULL; + libusb_device **devs; + libusb_context *ctx = NULL; - int r; - ssize_t cnt; - r = libusb_init(&ctx); - if(r < 0) return(false); + int r; + ssize_t cnt; + r = libusb_init(&ctx); + if (r < 0) + return (false); #ifdef STM8FLASH_LIBUSB_QUIET - libusb_set_debug(ctx, 0); + libusb_set_debug(ctx, 0); #else - libusb_set_debug(ctx, 3); + libusb_set_debug(ctx, 3); #endif - cnt = libusb_get_device_list(ctx, &devs); - if(cnt < 0) return(false); + cnt = libusb_get_device_list(ctx, &devs); + if (cnt < 0) + return (false); - pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); - pgm->ctx = ctx; - if (!pgm->dev_handle) spawn_error("Could not open USB device."); - // assert(pgm->dev_handle); + pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); + pgm->ctx = ctx; + if (!pgm->dev_handle) + spawn_error("Could not open USB device."); + // assert(pgm->dev_handle); - libusb_free_device_list(devs, 1); //free the list, unref the devices in it + libusb_free_device_list(devs, 1); // free the list, unref the devices in it - if(libusb_kernel_driver_active(pgm->dev_handle, 0) == 1) { //find out if kernel driver is attached - int r = libusb_detach_kernel_driver(pgm->dev_handle, 0); - assert(r == 0); - } + if (libusb_kernel_driver_active(pgm->dev_handle, 0) == + 1) { // find out if kernel driver is attached + int r = libusb_detach_kernel_driver(pgm->dev_handle, 0); + assert(r == 0); + } #if defined(__APPLE__) || defined(WIN32) - r = libusb_claim_interface(pgm->dev_handle, 0); - assert(r == 0); + r = libusb_claim_interface(pgm->dev_handle, 0); + assert(r == 0); #endif - return(true); + return (true); } -const stm8_device_t *get_part(const char *name) -{ - for(unsigned int i = 0; stm8_devices[i].name; i++) - { - const char *e = stm8_devices[i].name; - const char *s = name; - for(e = stm8_devices[i].name, s = name; *s && (*e == *s || *e == '?'); e++, s++); - if(!*e) - return(&stm8_devices[i]); - } - return(0); +const stm8_device_t *get_part(const char *name) { + for (unsigned int i = 0; stm8_devices[i].name; i++) { + const char *e = stm8_devices[i].name; + const char *s = name; + for (e = stm8_devices[i].name, s = name; *s && (*e == *s || *e == '?'); + e++, s++) + ; + if (!*e) + return (&stm8_devices[i]); + } + return (0); } int main(int argc, char **argv) { - unsigned int start; - int bytes_count = 0; - char filename[256]; - memset(filename, 0, sizeof(filename)); - // Parsing command line - char c; - action_t action = NONE; - bool start_addr_specified = false, - pgm_specified = false, - part_specified = false, - bytes_count_specified = false; - memtype_t memtype = FLASH; - int i; - programmer_t *pgm = NULL; - const stm8_device_t *part = NULL; - while((c = getopt (argc, argv, "r:w:v:nc:p:s:b:lu")) != (char)-1) { - switch(c) { - case 'c': - pgm_specified = true; - for(i = 0; pgms[i].name; i++) { - if(!strcmp(optarg, pgms[i].name)) - pgm = &pgms[i]; - } - break; - case 'p': - part_specified = true; - part = get_part(optarg); - break; - case 'l': - for(i = 0; stm8_devices[i].name; i++) - printf("%s ", stm8_devices[i].name); - printf("\n"); - exit(0); - case 'r': - action = READ; - strcpy(filename, optarg); - break; - case 'w': - action = WRITE; - strcpy(filename, optarg); - break; - case 'v': - action = VERIFY; - strcpy(filename, optarg); - break; - case 'u': - action = UNLOCK; - start = 0x4800; - memtype = OPT; - strcpy(filename, "Workaround"); - break; - case 's': - // Start addr is depending on MCU type - if(strcasecmp(optarg, "flash") == 0) { - memtype = FLASH; - } else if(strcasecmp(optarg, "eeprom") == 0) { - memtype = EEPROM; - } else if(strcasecmp(optarg, "ram") == 0) { - memtype = RAM; - } else if(strcasecmp(optarg, "opt") == 0) { - memtype = OPT; - } else { - // Start addr is specified explicitely - memtype = UNKNOWN; - int success = sscanf(optarg, "%x", &start); - assert(success); - start_addr_specified = true; - } - break; - case 'b': - bytes_count = atoi(optarg); - bytes_count_specified = true; - break; - case '?': - print_help_and_exit(argv[0], false); - default: - print_help_and_exit(argv[0], true); - } - } - if(argc <= 1) - print_help_and_exit(argv[0], true); - if(pgm_specified && !pgm) { - fprintf(stderr, "No valid programmer specified. Possible values are:\n"); - dump_pgms( (programmer_t *) &pgms); - exit(-1); - } - if(!pgm) - spawn_error("No programmer has been specified"); - if(part_specified && !part) { - fprintf(stderr, "No valid part specified. Use -l to see the list of supported devices.\n"); - exit(-1); - } - if(!part) - spawn_error("No part has been specified"); - - // Try define memory type by address - if(memtype == UNKNOWN) { - if((start >= 0x4800) && (start < 0x4880)) { - memtype = OPT; - } - if((start >= part->ram_start) && (start < part->ram_start + part->ram_size)) { - memtype = RAM; - } - else if((start >= part->flash_start) && (start < part->flash_start + part->flash_size)) { - memtype = FLASH; - } - else if((start >= part->eeprom_start) && (start < part->eeprom_start + part->eeprom_size)) { - memtype = EEPROM; - } + unsigned int start; + int bytes_count = 0; + char filename[256]; + memset(filename, 0, sizeof(filename)); + // Parsing command line + char c; + action_t action = NONE; + bool start_addr_specified = false, pgm_specified = false, + part_specified = false, bytes_count_specified = false; + memtype_t memtype = FLASH; + int i; + programmer_t *pgm = NULL; + const stm8_device_t *part = NULL; + while ((c = getopt(argc, argv, "r:w:v:nc:p:s:b:lu")) != (char)-1) { + switch (c) { + case 'c': + pgm_specified = true; + for (i = 0; pgms[i].name; i++) { + if (!strcmp(optarg, pgms[i].name)) + pgm = &pgms[i]; + } + break; + case 'p': + part_specified = true; + part = get_part(optarg); + break; + case 'l': + for (i = 0; stm8_devices[i].name; i++) + printf("%s ", stm8_devices[i].name); + printf("\n"); + exit(0); + case 'r': + action = READ; + strcpy(filename, optarg); + break; + case 'w': + action = WRITE; + strcpy(filename, optarg); + break; + case 'v': + action = VERIFY; + strcpy(filename, optarg); + break; + case 'u': + action = UNLOCK; + start = 0x4800; + memtype = OPT; + strcpy(filename, "Workaround"); + break; + case 's': + // Start addr is depending on MCU type + if (strcasecmp(optarg, "flash") == 0) { + memtype = FLASH; + } else if (strcasecmp(optarg, "eeprom") == 0) { + memtype = EEPROM; + } else if (strcasecmp(optarg, "ram") == 0) { + memtype = RAM; + } else if (strcasecmp(optarg, "opt") == 0) { + memtype = OPT; + } else { + // Start addr is specified explicitely + memtype = UNKNOWN; + int success = sscanf(optarg, "%x", &start); + assert(success); + start_addr_specified = true; + } + break; + case 'b': + bytes_count = atoi(optarg); + bytes_count_specified = true; + break; + case '?': + print_help_and_exit(argv[0], false); + default: + print_help_and_exit(argv[0], true); + } + } + if (argc <= 1) + print_help_and_exit(argv[0], true); + if (pgm_specified && !pgm) { + fprintf(stderr, "No valid programmer specified. Possible values are:\n"); + dump_pgms((programmer_t *)&pgms); + exit(-1); + } + if (!pgm) + spawn_error("No programmer has been specified"); + if (part_specified && !part) { + fprintf(stderr, "No valid part specified. Use -l to see the list of " + "supported devices.\n"); + exit(-1); + } + if (!part) + spawn_error("No part has been specified"); + + // Try define memory type by address + if (memtype == UNKNOWN) { + if ((start >= 0x4800) && (start < 0x4880)) { + memtype = OPT; + } + if ((start >= part->ram_start) && + (start < part->ram_start + part->ram_size)) { + memtype = RAM; + } else if ((start >= part->flash_start) && + (start < part->flash_start + part->flash_size)) { + memtype = FLASH; + } else if ((start >= part->eeprom_start) && + (start < part->eeprom_start + part->eeprom_size)) { + memtype = EEPROM; + } + } + + if (memtype != UNKNOWN) { + // Selecting start addr depending on + // specified part and memtype + switch (memtype) { + case RAM: + if (!start_addr_specified) { + start = part->ram_start; + } + if (!bytes_count_specified || bytes_count > part->ram_size) { + bytes_count = part->ram_size; + } + fprintf(stderr, "Determine RAM area\r\n"); + break; + case EEPROM: + if (!start_addr_specified) { + start = part->eeprom_start; + } + if (!bytes_count_specified || bytes_count > part->eeprom_size) { + bytes_count = part->eeprom_size; + } + fprintf(stderr, "Determine EEPROM area\r\n"); + break; + case FLASH: + if (!start_addr_specified) { + start = part->flash_start; + } + if (!bytes_count_specified || bytes_count > part->flash_size) { + bytes_count = part->flash_size; + } + fprintf(stderr, "Determine FLASH area\r\n"); + break; + case OPT: + if (!start_addr_specified) { + start = 0x4800; + } + size_t opt_size = (part->flash_size <= 8 * 1024 ? 0x40 : 0x80); + if (!bytes_count_specified || bytes_count > opt_size) { + bytes_count = opt_size; + } + fprintf(stderr, "Determine OPT area\r\n"); + break; + } + start_addr_specified = true; + } + if (!action) + spawn_error("No action has been specified"); + if (!start_addr_specified) + spawn_error("No memtype or start_addr has been specified"); + if (!strlen(filename)) + spawn_error("No filename has been specified"); + if (!action || !start_addr_specified || !strlen(filename)) + print_help_and_exit(argv[0], true); + if (!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) + spawn_error("Couldn't initialize stlink"); + if (!pgm->open(pgm)) + spawn_error( + "Error communicating with MCU. Please check your SWIM connection."); + + FILE *f; + if (action == READ) { + fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); + fflush(stderr); + int bytes_count_align = + ((bytes_count - 1) / 256 + 1) * + 256; // Reading should be done in blocks of 256 bytes + unsigned char *buf = malloc(bytes_count_align); + if (!buf) + spawn_error("malloc failed"); + int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); + if (recv < bytes_count_align) { + fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", + bytes_count_align, recv); + spawn_error("Failed to read MCU"); + } + if (!(f = fopen(filename, "w"))) + spawn_error("Failed to open file"); + if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { + fprintf(stderr, "Reading from Intel hex file "); + ihex_write(f, buf, start, start + bytes_count); + } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || + is_ext(filename, ".srec")) { + printf( + "Reading from Motorola S-record files are not implemented (yet)\n"); + printf("Exiting...\n"); + exit(0); + fprintf(stderr, "Reading form Motorola S-record file "); + srec_write(f, buf, start, start + bytes_count); + } else { + fwrite(buf, 1, bytes_count, f); + } + fclose(f); + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes received: %d\n", bytes_count); + } else if (action == VERIFY) { + fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); + fflush(stderr); + + int bytes_count_align = + ((bytes_count - 1) / 256 + 1) * + 256; // Reading should be done in blocks of 256 bytes + unsigned char *buf = malloc(bytes_count_align); + if (!buf) + spawn_error("malloc failed"); + int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); + if (recv < bytes_count_align) { + fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", + bytes_count_align, recv); + spawn_error("Failed to read MCU"); } - if(memtype != UNKNOWN) { - // Selecting start addr depending on - // specified part and memtype - switch(memtype) { - case RAM: - if(!start_addr_specified) { - start = part->ram_start; - } - if(!bytes_count_specified || bytes_count > part->ram_size) { - bytes_count = part->ram_size; - } - fprintf(stderr, "Determine RAM area\r\n"); - break; - case EEPROM: - if(!start_addr_specified) { - start = part->eeprom_start; - } - if(!bytes_count_specified || bytes_count > part->eeprom_size) { - bytes_count = part->eeprom_size; - } - fprintf(stderr, "Determine EEPROM area\r\n"); - break; - case FLASH: - if(!start_addr_specified) { - start = part->flash_start; - } - if(!bytes_count_specified || bytes_count > part->flash_size) { - bytes_count = part->flash_size; - } - fprintf(stderr, "Determine FLASH area\r\n"); - break; - case OPT: - if(!start_addr_specified) { - start = 0x4800; - } - size_t opt_size = (part->flash_size <= 8*1024 ? 0x40 : 0x80); - if(!bytes_count_specified || bytes_count > opt_size) { - bytes_count = opt_size; - } - fprintf(stderr, "Determine OPT area\r\n"); - break; - } - start_addr_specified = true; - } - if(!action) - spawn_error("No action has been specified"); - if(!start_addr_specified) - spawn_error("No memtype or start_addr has been specified"); - if (!strlen(filename)) - spawn_error("No filename has been specified"); - if(!action || !start_addr_specified || !strlen(filename)) - print_help_and_exit(argv[0], true); - if(!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) - spawn_error("Couldn't initialize stlink"); - if(!pgm->open(pgm)) - spawn_error("Error communicating with MCU. Please check your SWIM connection."); - - - FILE *f; - if(action == READ) { - fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); - fflush(stderr); - int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes - unsigned char *buf = malloc(bytes_count_align); - if(!buf) spawn_error("malloc failed"); - int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); - if(recv < bytes_count_align) { - fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); - spawn_error("Failed to read MCU"); - } - if(!(f = fopen(filename, "w"))) - spawn_error("Failed to open file"); - if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) - { - fprintf(stderr, "Reading from Intel hex file "); - ihex_write(f, buf, start, start+bytes_count); - } - else if(is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) - { - fprintf(stderr, "Reading form Motorola S-record file "); - srec_write(f, buf, start, start+bytes_count); - } - else - { - fwrite(buf, 1, bytes_count, f); - } - fclose(f); - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes received: %d\n", bytes_count); - } else if (action == VERIFY) { - fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); - fflush(stderr); - - int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes - unsigned char *buf = malloc(bytes_count_align); - if(!buf) spawn_error("malloc failed"); - int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); - if(recv < bytes_count_align) { - fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); - spawn_error("Failed to read MCU"); - } - - if(!(f = fopen(filename, "r"))) - spawn_error("Failed to open file"); - unsigned char *buf2 = malloc(bytes_count); - if(!buf2) spawn_error("malloc failed"); - int bytes_to_verify; - /* reading bytes to RAM */ - if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { - bytes_to_verify = ihex_read(f, buf, start, start + bytes_count); - } else { - fseek(f, 0L, SEEK_END); - bytes_to_verify = ftell(f); - if(bytes_count_specified) { - bytes_to_verify = bytes_count; - } else if(bytes_count < bytes_to_verify) { - bytes_to_verify = bytes_count; - } - fseek(f, 0, SEEK_SET); - fread(buf2, 1, bytes_to_verify, f); - } - fclose(f); - - if(memcmp(buf, buf2, bytes_to_verify) == 0) { - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); - } else { - fprintf(stderr, "FAILED\n"); - exit(-1); - } - - - } else if (action == WRITE) { - if(!(f = fopen(filename, "r"))) - spawn_error("Failed to open file"); - int bytes_count_align = ((bytes_count-1)/part->flash_block_size+1)*part->flash_block_size; - unsigned char *buf = malloc(bytes_count_align); - if(!buf) spawn_error("malloc failed"); - memset(buf, 0, bytes_count_align); // Clean aligned buffer - int bytes_to_write; - - /* reading bytes to RAM */ - if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { - fprintf(stderr, "Writing Intel hex file "); - bytes_to_write = ihex_read(f, buf, start, start + bytes_count); - } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) { - fprintf(stderr, "Writing Motorola S-record file "); - bytes_to_write = srec_read(f, buf, start, start + bytes_count); - } else { - fprintf(stderr, "Writing binary file "); - fseek(f, 0L, SEEK_END); - bytes_to_write = ftell(f); - if(bytes_count_specified) { - bytes_to_write = bytes_count; - } else if(bytes_count < bytes_to_write) { - bytes_to_write = bytes_count; - } - fseek(f, 0, SEEK_SET); - fread(buf, 1, bytes_to_write, f); - } - fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); - - /* flashing MCU */ - int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); - if(pgm->reset) { - // Restarting core (if applicable) - pgm->reset(pgm); - } - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes written: %d\n", sent); - fclose(f); - } else if (action == UNLOCK) { - int bytes_to_write=part->option_bytes_size; - - if (part->read_out_protection_mode==ROP_UNKNOWN) spawn_error("No unlocking mode defined for this device. You may need to edit the file stm8.c"); + if (!(f = fopen(filename, "r"))) + spawn_error("Failed to open file"); + unsigned char *buf2 = malloc(bytes_count); + if (!buf2) + spawn_error("malloc failed"); + int bytes_to_verify; + /* reading bytes to RAM */ + if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { + bytes_to_verify = ihex_read(f, buf, start, start + bytes_count); + } else { + fseek(f, 0L, SEEK_END); + bytes_to_verify = ftell(f); + if (bytes_count_specified) { + bytes_to_verify = bytes_count; + } else if (bytes_count < bytes_to_verify) { + bytes_to_verify = bytes_count; + } + fseek(f, 0, SEEK_SET); + fread(buf2, 1, bytes_to_verify, f); + } + fclose(f); + + if (memcmp(buf, buf2, bytes_to_verify) == 0) { + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); + } else { + fprintf(stderr, "FAILED\n"); + exit(-1); + } - unsigned char *buf=malloc(bytes_to_write); - if(!buf) spawn_error("malloc failed"); + } else if (action == WRITE) { + if (!(f = fopen(filename, "r"))) + spawn_error("Failed to open file"); + int bytes_count_align = ((bytes_count - 1) / part->flash_block_size + 1) * + part->flash_block_size; + unsigned char *buf = malloc(bytes_count_align); + if (!buf) + spawn_error("malloc failed"); + memset(buf, 0, bytes_count_align); // Clean aligned buffer + int bytes_to_write; + + /* reading bytes to RAM */ + if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { + fprintf(stderr, "Writing Intel hex file "); + bytes_to_write = ihex_read(f, buf, start, start + bytes_count); + } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || + is_ext(filename, ".srec")) { + fprintf(stderr, "Writing Motorola S-record file "); + bytes_to_write = srec_read(f, buf, start, start + bytes_count); + } else { + fprintf(stderr, "Writing binary file "); + fseek(f, 0L, SEEK_END); + bytes_to_write = ftell(f); + if (bytes_count_specified) { + bytes_to_write = bytes_count; + } else if (bytes_count < bytes_to_write) { + bytes_to_write = bytes_count; + } + fseek(f, 0, SEEK_SET); + fread(buf, 1, bytes_to_write, f); + } + fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); - if (part->read_out_protection_mode==ROP_STM8S_STD) { - for (int i=0; i0)&&((i&1)==0)) buf[i]=0xff; - } - } + /* flashing MCU */ + int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); + if (pgm->reset) { + // Restarting core (if applicable) + pgm->reset(pgm); + } + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes written: %d\n", sent); + fclose(f); + } else if (action == UNLOCK) { + int bytes_to_write = part->option_bytes_size; + + if (part->read_out_protection_mode == ROP_UNKNOWN) + spawn_error("No unlocking mode defined for this device. You may need to " + "edit the file stm8.c"); + + unsigned char *buf = malloc(bytes_to_write); + if (!buf) + spawn_error("malloc failed"); + + if (part->read_out_protection_mode == ROP_STM8S_STD) { + for (int i = 0; i < bytes_to_write; i++) { + buf[i] = 0; + if ((i > 0) && ((i & 1) == 0)) + buf[i] = 0xff; + } + } - /* flashing MCU */ - int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); - if(pgm->reset) { - // Restarting core (if applicable) - pgm->reset(pgm); - } - fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); - fprintf(stderr, "Bytes written: %d\n", sent); - } - return(0); + /* flashing MCU */ + int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); + if (pgm->reset) { + // Restarting core (if applicable) + pgm->reset(pgm); + } + fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); + fprintf(stderr, "Bytes written: %d\n", sent); + } + return (0); } diff --git a/srec.c b/srec.c index e85ca54..fc8ed88 100644 --- a/srec.c +++ b/srec.c @@ -1,123 +1,146 @@ /* stlink/v2 stm8 memory programming utility (c) Valentin Dudouyt, 2012 - 2014 */ +#include "byte_utils.h" +#include "error.h" +#include "srec.h" +#include #include #include #include -#include -#include "srec.h" -#include "error.h" -#include "byte_utils.h" char line[256]; -static unsigned char checksum(unsigned char *buf, unsigned int length, int chunk_len, int chunk_addr, int chunk_type) { - int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; - unsigned int i; - for(i = 0; i < length; i++) { - sum += buf[i]; - } +static unsigned char checksum(unsigned char *buf, unsigned int length, + int chunk_len, int chunk_addr, int chunk_type) { + int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; + unsigned int i; + for (i = 0; i < length; i++) { + sum += buf[i]; + } - int complement = (~sum + 1); - return complement & 0xff; + int complement = (~sum + 1); + return complement & 0xff; } - -static bool is_data_type(unsigned int chunk_type) -{ - return (chunk_type == 0x01 || chunk_type == 0x02 || chunk_type == 0x03); +static bool is_data_type(unsigned int chunk_type) { + return (chunk_type == 0x01 || chunk_type == 0x02 || chunk_type == 0x03); } +int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, + unsigned int end) { + fseek(pFile, 0, SEEK_SET); + unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, + greatest_addr = 0; + unsigned int number_of_records = 0; + + bool data_record = false; + bool found_S5_rec = false; + unsigned int expected_data_records = 0; + unsigned int data_len = 0; + + while (fgets(line, sizeof(line), pFile)) { + data_record = true; // Assume that the read data is a data record. Set to + // false if not. + line_no++; + + // Reading chunk header + if (sscanf(line, "S%01x%02x%04x", &chunk_type, &chunk_len, &chunk_addr) != 3) { + free(buf); + ERROR2("Error while parsing SREC at line %d\n", line_no); + } + + if (chunk_type == 0x00 || + chunk_type == 0x04) // Header type record or reserved. Skip! + { + continue; + } else if (chunk_type == 0x05) { // This will contain the total expected + // number of data records. Save for error + // checking later + found_S5_rec = true; + if (chunk_len != + 3) { // Length field must contain a 3 to be a valid S5 record. + ERROR2("Error while parsing S5 Record at line %d\n", line_no); + } + expected_data_records = chunk_addr; // The expected total number of data + // records is saved in S503 + // field. + } else if (is_data_type(chunk_type)) { + // See https://en.wikipedia.org/wiki/SREC_(file_format)#Record_types + data_len = chunk_len - chunk_type - 2; //Addr field differs with record type + } else { + continue; + } + + // Reading chunk data + for (i = 6 + 2 * chunk_type; i < 2 * data_len + 8; i += 2) { + if (sscanf(&(line[i]), "%02x", &byte) != 1) { + free(buf); + ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); + } + + if (!is_data_type(chunk_type)) { + // The only data records have to be processed + data_record = false; + continue; + } + + if ((i - 8) / 2 >= chunk_len) { + // Respect chunk_len and do not capture checksum as data + break; + } + if (chunk_addr < start) { + free(buf); + ERROR2("Address %04x is out of range at line %d\n", chunk_addr, + line_no); + } + if (chunk_addr + chunk_len > end) { + free(buf); + ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, + chunk_len, line_no); + } + if (chunk_addr + chunk_len > greatest_addr) { + greatest_addr = chunk_addr + chunk_len; + } + buf[chunk_addr - start + (i - 8) / 2] = byte; + } + if (data_record) { // We found a data record. Remember this. + number_of_records++; + } + } + + // Check to see if the number of data records expected is the same as we + // actually read. + if (found_S5_rec && number_of_records != expected_data_records) { + ERROR2("Error while comparing S5 record (number of data records: %d) with " + "the number actually read: %d\n", + expected_data_records, number_of_records); + } + + return (greatest_addr - start); +} -//TODO This function has just been copied from ihex.c and does not work as intended. -int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { - fseek(pFile, 0, SEEK_SET); - unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; - unsigned int number_of_records = 0; - - bool data_record = false; - unsigned int expected_data_records = 0; - - while(fgets(line, sizeof(line), pFile)) { - data_record = true; //Assume that the read data is a data record. Set to false if not. - line_no++; - - // Reading chunk header - if(sscanf(line, "S%01x%02x%04x", &chunk_type, &chunk_len, &chunk_addr) != 3) { - free(buf); - ERROR2("Error while parsing SREC at line %d\n", line_no); - } - - if(chunk_type == 0x05) { //This will contain the total expected number of data records. Save for error checking later - if (chunk_len != 3) { // Length field must contain a 3 to be a valid S5 record. - ERROR2("Error while parsing S5 Record at line %d\n", line_no); - } - expected_data_records = chunk_addr; //The expected total number of data records is saved in S503 field. - } - - // Reading chunk data - for(i = 8; i < strlen(line) - 1; i +=2) { - if(sscanf(&(line[i]), "%02x", &byte) != 1) { - free(buf); - ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); - } - - if(!is_data_type(chunk_type)) { - // The only data records have to be processed - data_record = false; - continue; - } - if((i - 8) / 2 >= chunk_len) { - // Respect chunk_len and do not capture checksum as data - break; - } - if(chunk_addr < start) { - free(buf); - ERROR2("Address %04x is out of range at line %d\n", chunk_addr, line_no); - } - if(chunk_addr + chunk_len > end) { - free(buf); - ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, chunk_len, line_no); - } - if(chunk_addr + chunk_len > greatest_addr) { - greatest_addr = chunk_addr + chunk_len; - } - buf[chunk_addr - start + (i - 8) / 2] = byte; - } - if(data_record) { //We found a data record. Remember this. - number_of_records++; - } - } - - //Check to see if the number of data records expected is the same as we actually read. - if(number_of_records != expected_data_records) { - ERROR2("Error while comparing S5 record (number of data records: %d) with the number actually read: %d\n", expected_data_records, number_of_records); - } - - return(greatest_addr - start); - +void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, + unsigned int end) { + ERROR("srec_write is not implemented!"); + +unsigned int chunk_len, chunk_start, chunk_type, i, byte, line_no = 0, + greatest_addr = 0; +chunk_start = start; +while (chunk_start < end) { + chunk_len = end - chunk_start; + if (chunk_len > 32) { + chunk_len = 32; + } + fprintf(pFile, "S3%02X0000%04X", chunk_len + 6, chunk_start); + for (i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) { + fprintf(pFile, "%02X", buf[i]); + } + fprintf(pFile, "%02X\n", checksum(&buf[chunk_start - start], chunk_len, + chunk_len, chunk_start, 0)); + + chunk_start += chunk_len; } +fprintf(pFile, "S9030000FC\n"); -//TODO This function has just been copied from ihex.c and does not work as intended. -void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { - unsigned int chunk_len, chunk_start, chunk_type, i, byte, line_no = 0, greatest_addr = 0; - chunk_start = start; - while(chunk_start < end) - { - chunk_len = end - chunk_start; - if (chunk_len > 32) - { - chunk_len = 32; - } - // TODO Check if S1 is good to assume. Might not be correct, might be 1,2 or 3 here as a data record. - fprintf(pFile, "S1%02X%04X",chunk_len,chunk_start); - for(i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) - { - fprintf(pFile, "%02X",buf[i]); - } - fprintf(pFile, "%02X\n", checksum( &buf[chunk_start - start], chunk_len, chunk_len, chunk_start, 0)); - - chunk_start += chunk_len; - } - fprintf(pFile,":00000001FF\n"); } From 7e80dc394d26005f7a4b0adcf4545b68de1449ff Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Mon, 9 Jan 2017 20:52:35 +0100 Subject: [PATCH 5/7] Spelling mistake --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index e10c428..72de435 100644 --- a/main.c +++ b/main.c @@ -328,7 +328,7 @@ int main(int argc, char **argv) { "Reading from Motorola S-record files are not implemented (yet)\n"); printf("Exiting...\n"); exit(0); - fprintf(stderr, "Reading form Motorola S-record file "); + fprintf(stderr, "Reading from Motorola S-record file "); srec_write(f, buf, start, start + bytes_count); } else { fwrite(buf, 1, bytes_count, f); From 1dd9333618c0e0e69c8d8733e30425af2fad5e2e Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Mon, 9 Jan 2017 21:10:16 +0100 Subject: [PATCH 6/7] Fixed issues that clang-format introduced. I'm terrible at Git for the moment. Apologies! --- main.c | 786 ++++++++++++++++++++++++++++----------------------------- srec.c | 150 +++++------ 2 files changed, 449 insertions(+), 487 deletions(-) diff --git a/main.c b/main.c index 72de435..2c5874d 100644 --- a/main.c +++ b/main.c @@ -1,19 +1,19 @@ /* stlink/v2 stm8 memory programming utility (c) Valentin Dudouyt, 2012 - 2014 */ -#include "ihex.h" -#include "pgm.h" -#include "srec.h" -#include "stlink.h" -#include "stlinkv2.h" -#include "stm8.h" -#include -#include #include #include #include #include #include +#include +#include +#include "pgm.h" +#include "stlink.h" +#include "stlinkv2.h" +#include "stm8.h" +#include "ihex.h" +#include "srec.h" #ifdef __APPLE__ extern char *optarg; @@ -24,434 +24,420 @@ extern int optreset; #endif programmer_t pgms[] = { - { - "stlink", - 0x0483, // USB vid - 0x3744, // USB pid - stlink_open, stlink_close, stlink_swim_srst, stlink_swim_read_range, - stlink_swim_write_range, - }, - { - "stlinkv2", 0x0483, 0x3748, stlink2_open, stlink_close, stlink2_srst, - stlink2_swim_read_range, stlink2_swim_write_range, - }, - {NULL}, + { "stlink", + 0x0483, // USB vid + 0x3744, // USB pid + stlink_open, + stlink_close, + stlink_swim_srst, + stlink_swim_read_range, + stlink_swim_write_range, + }, + { + "stlinkv2", + 0x0483, + 0x3748, + stlink2_open, + stlink_close, + stlink2_srst, + stlink2_swim_read_range, + stlink2_swim_write_range, + }, + { NULL }, }; void print_help_and_exit(const char *name, bool err) { - FILE *stream = err ? stderr : stdout; - fprintf(stream, "Usage: %s [-c programmer] [-p partno] [-s memtype] [-b " - "bytes] [-r|-w|-v] \n", - name); - fprintf(stream, "Options:\n"); - fprintf(stream, "\t-? Display this help\n"); - fprintf(stream, - "\t-c programmer Specify programmer used (stlink or stlinkv2)\n"); - fprintf(stream, "\t-p partno Specify STM8 device\n"); - fprintf(stream, "\t-l List supported STM8 devices\n"); - fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, " - "opt or explicit address)\n"); - fprintf(stream, "\t-b bytes Specify number of bytes\n"); - fprintf(stream, "\t-r Read data from device to file\n"); - fprintf(stream, "\t-w Write data from file to device\n"); - fprintf(stream, "\t-v Verify data in device against file\n"); - fprintf(stream, "\t-u Unlock. Reset option bytes to factory " - "default to remove write protection.\n"); - exit(-err); + FILE *stream = err ? stderr : stdout; + fprintf(stream, "Usage: %s [-c programmer] [-p partno] [-s memtype] [-b bytes] [-r|-w|-v] \n", name); + fprintf(stream, "Options:\n"); + fprintf(stream, "\t-? Display this help\n"); + fprintf(stream, "\t-c programmer Specify programmer used (stlink or stlinkv2)\n"); + fprintf(stream, "\t-p partno Specify STM8 device\n"); + fprintf(stream, "\t-l List supported STM8 devices\n"); + fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, opt or explicit address)\n"); + fprintf(stream, "\t-b bytes Specify number of bytes\n"); + fprintf(stream, "\t-r Read data from device to file\n"); + fprintf(stream, "\t-w Write data from file to device\n"); + fprintf(stream, "\t-v Verify data in device against file\n"); + fprintf(stream, "\t-u Unlock. Reset option bytes to factory default to remove write protection.\n"); + exit(-err); } void spawn_error(const char *msg) { - fprintf(stderr, "%s\n", msg); - exit(-1); + fprintf(stderr, "%s\n", msg); + exit(-1); } void dump_pgms(programmer_t *pgms) { - // Dump programmers list in stderr - int i; - for (i = 0; pgms[i].name; i++) - fprintf(stderr, "%s\n", pgms[i].name); + // Dump programmers list in stderr + int i; + for(i = 0; pgms[i].name; i++) + fprintf(stderr, "%s\n", pgms[i].name); } bool is_ext(const char *filename, const char *ext) { - char *ext_begin = strrchr(filename, '.'); - return (ext_begin && strcmp(ext_begin, ext) == 0); + char *ext_begin = strrchr(filename, '.'); + return(ext_begin && strcmp(ext_begin, ext) == 0); } bool usb_init(programmer_t *pgm, unsigned int vid, unsigned int pid) { - libusb_device **devs; - libusb_context *ctx = NULL; + libusb_device **devs; + libusb_context *ctx = NULL; - int r; - ssize_t cnt; - r = libusb_init(&ctx); - if (r < 0) - return (false); + int r; + ssize_t cnt; + r = libusb_init(&ctx); + if(r < 0) return(false); #ifdef STM8FLASH_LIBUSB_QUIET - libusb_set_debug(ctx, 0); + libusb_set_debug(ctx, 0); #else - libusb_set_debug(ctx, 3); + libusb_set_debug(ctx, 3); #endif - cnt = libusb_get_device_list(ctx, &devs); - if (cnt < 0) - return (false); + cnt = libusb_get_device_list(ctx, &devs); + if(cnt < 0) return(false); - pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); - pgm->ctx = ctx; - if (!pgm->dev_handle) - spawn_error("Could not open USB device."); - // assert(pgm->dev_handle); + pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); + pgm->ctx = ctx; + if (!pgm->dev_handle) spawn_error("Could not open USB device."); + // assert(pgm->dev_handle); - libusb_free_device_list(devs, 1); // free the list, unref the devices in it + libusb_free_device_list(devs, 1); //free the list, unref the devices in it - if (libusb_kernel_driver_active(pgm->dev_handle, 0) == - 1) { // find out if kernel driver is attached - int r = libusb_detach_kernel_driver(pgm->dev_handle, 0); - assert(r == 0); - } + if(libusb_kernel_driver_active(pgm->dev_handle, 0) == 1) { //find out if kernel driver is attached + int r = libusb_detach_kernel_driver(pgm->dev_handle, 0); + assert(r == 0); + } #if defined(__APPLE__) || defined(WIN32) - r = libusb_claim_interface(pgm->dev_handle, 0); - assert(r == 0); + r = libusb_claim_interface(pgm->dev_handle, 0); + assert(r == 0); #endif - return (true); + return(true); } -const stm8_device_t *get_part(const char *name) { - for (unsigned int i = 0; stm8_devices[i].name; i++) { - const char *e = stm8_devices[i].name; - const char *s = name; - for (e = stm8_devices[i].name, s = name; *s && (*e == *s || *e == '?'); - e++, s++) - ; - if (!*e) - return (&stm8_devices[i]); - } - return (0); +const stm8_device_t *get_part(const char *name) +{ + for(unsigned int i = 0; stm8_devices[i].name; i++) + { + const char *e = stm8_devices[i].name; + const char *s = name; + for(e = stm8_devices[i].name, s = name; *s && (*e == *s || *e == '?'); e++, s++); + if(!*e) + return(&stm8_devices[i]); + } + return(0); } int main(int argc, char **argv) { - unsigned int start; - int bytes_count = 0; - char filename[256]; - memset(filename, 0, sizeof(filename)); - // Parsing command line - char c; - action_t action = NONE; - bool start_addr_specified = false, pgm_specified = false, - part_specified = false, bytes_count_specified = false; - memtype_t memtype = FLASH; - int i; - programmer_t *pgm = NULL; - const stm8_device_t *part = NULL; - while ((c = getopt(argc, argv, "r:w:v:nc:p:s:b:lu")) != (char)-1) { - switch (c) { - case 'c': - pgm_specified = true; - for (i = 0; pgms[i].name; i++) { - if (!strcmp(optarg, pgms[i].name)) - pgm = &pgms[i]; - } - break; - case 'p': - part_specified = true; - part = get_part(optarg); - break; - case 'l': - for (i = 0; stm8_devices[i].name; i++) - printf("%s ", stm8_devices[i].name); - printf("\n"); - exit(0); - case 'r': - action = READ; - strcpy(filename, optarg); - break; - case 'w': - action = WRITE; - strcpy(filename, optarg); - break; - case 'v': - action = VERIFY; - strcpy(filename, optarg); - break; - case 'u': - action = UNLOCK; - start = 0x4800; - memtype = OPT; - strcpy(filename, "Workaround"); - break; - case 's': - // Start addr is depending on MCU type - if (strcasecmp(optarg, "flash") == 0) { - memtype = FLASH; - } else if (strcasecmp(optarg, "eeprom") == 0) { - memtype = EEPROM; - } else if (strcasecmp(optarg, "ram") == 0) { - memtype = RAM; - } else if (strcasecmp(optarg, "opt") == 0) { - memtype = OPT; - } else { - // Start addr is specified explicitely - memtype = UNKNOWN; - int success = sscanf(optarg, "%x", &start); - assert(success); - start_addr_specified = true; - } - break; - case 'b': - bytes_count = atoi(optarg); - bytes_count_specified = true; - break; - case '?': - print_help_and_exit(argv[0], false); - default: - print_help_and_exit(argv[0], true); - } - } - if (argc <= 1) - print_help_and_exit(argv[0], true); - if (pgm_specified && !pgm) { - fprintf(stderr, "No valid programmer specified. Possible values are:\n"); - dump_pgms((programmer_t *)&pgms); - exit(-1); - } - if (!pgm) - spawn_error("No programmer has been specified"); - if (part_specified && !part) { - fprintf(stderr, "No valid part specified. Use -l to see the list of " - "supported devices.\n"); - exit(-1); - } - if (!part) - spawn_error("No part has been specified"); - - // Try define memory type by address - if (memtype == UNKNOWN) { - if ((start >= 0x4800) && (start < 0x4880)) { - memtype = OPT; - } - if ((start >= part->ram_start) && - (start < part->ram_start + part->ram_size)) { - memtype = RAM; - } else if ((start >= part->flash_start) && - (start < part->flash_start + part->flash_size)) { - memtype = FLASH; - } else if ((start >= part->eeprom_start) && - (start < part->eeprom_start + part->eeprom_size)) { - memtype = EEPROM; - } - } - - if (memtype != UNKNOWN) { - // Selecting start addr depending on - // specified part and memtype - switch (memtype) { - case RAM: - if (!start_addr_specified) { - start = part->ram_start; - } - if (!bytes_count_specified || bytes_count > part->ram_size) { - bytes_count = part->ram_size; - } - fprintf(stderr, "Determine RAM area\r\n"); - break; - case EEPROM: - if (!start_addr_specified) { - start = part->eeprom_start; - } - if (!bytes_count_specified || bytes_count > part->eeprom_size) { - bytes_count = part->eeprom_size; - } - fprintf(stderr, "Determine EEPROM area\r\n"); - break; - case FLASH: - if (!start_addr_specified) { - start = part->flash_start; - } - if (!bytes_count_specified || bytes_count > part->flash_size) { - bytes_count = part->flash_size; - } - fprintf(stderr, "Determine FLASH area\r\n"); - break; - case OPT: - if (!start_addr_specified) { - start = 0x4800; - } - size_t opt_size = (part->flash_size <= 8 * 1024 ? 0x40 : 0x80); - if (!bytes_count_specified || bytes_count > opt_size) { - bytes_count = opt_size; - } - fprintf(stderr, "Determine OPT area\r\n"); - break; - } - start_addr_specified = true; - } - if (!action) - spawn_error("No action has been specified"); - if (!start_addr_specified) - spawn_error("No memtype or start_addr has been specified"); - if (!strlen(filename)) - spawn_error("No filename has been specified"); - if (!action || !start_addr_specified || !strlen(filename)) - print_help_and_exit(argv[0], true); - if (!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) - spawn_error("Couldn't initialize stlink"); - if (!pgm->open(pgm)) - spawn_error( - "Error communicating with MCU. Please check your SWIM connection."); - - FILE *f; - if (action == READ) { - fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); - fflush(stderr); - int bytes_count_align = - ((bytes_count - 1) / 256 + 1) * - 256; // Reading should be done in blocks of 256 bytes - unsigned char *buf = malloc(bytes_count_align); - if (!buf) - spawn_error("malloc failed"); - int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); - if (recv < bytes_count_align) { - fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", - bytes_count_align, recv); - spawn_error("Failed to read MCU"); + unsigned int start; + int bytes_count = 0; + char filename[256]; + memset(filename, 0, sizeof(filename)); + // Parsing command line + char c; + action_t action = NONE; + bool start_addr_specified = false, + pgm_specified = false, + part_specified = false, + bytes_count_specified = false; + memtype_t memtype = FLASH; + int i; + programmer_t *pgm = NULL; + const stm8_device_t *part = NULL; + while((c = getopt (argc, argv, "r:w:v:nc:p:s:b:lu")) != (char)-1) { + switch(c) { + case 'c': + pgm_specified = true; + for(i = 0; pgms[i].name; i++) { + if(!strcmp(optarg, pgms[i].name)) + pgm = &pgms[i]; + } + break; + case 'p': + part_specified = true; + part = get_part(optarg); + break; + case 'l': + for(i = 0; stm8_devices[i].name; i++) + printf("%s ", stm8_devices[i].name); + printf("\n"); + exit(0); + case 'r': + action = READ; + strcpy(filename, optarg); + break; + case 'w': + action = WRITE; + strcpy(filename, optarg); + break; + case 'v': + action = VERIFY; + strcpy(filename, optarg); + break; + case 'u': + action = UNLOCK; + start = 0x4800; + memtype = OPT; + strcpy(filename, "Workaround"); + break; + case 's': + // Start addr is depending on MCU type + if(strcasecmp(optarg, "flash") == 0) { + memtype = FLASH; + } else if(strcasecmp(optarg, "eeprom") == 0) { + memtype = EEPROM; + } else if(strcasecmp(optarg, "ram") == 0) { + memtype = RAM; + } else if(strcasecmp(optarg, "opt") == 0) { + memtype = OPT; + } else { + // Start addr is specified explicitely + memtype = UNKNOWN; + int success = sscanf(optarg, "%x", &start); + assert(success); + start_addr_specified = true; + } + break; + case 'b': + bytes_count = atoi(optarg); + bytes_count_specified = true; + break; + case '?': + print_help_and_exit(argv[0], false); + default: + print_help_and_exit(argv[0], true); + } + } + if(argc <= 1) + print_help_and_exit(argv[0], true); + if(pgm_specified && !pgm) { + fprintf(stderr, "No valid programmer specified. Possible values are:\n"); + dump_pgms( (programmer_t *) &pgms); + exit(-1); + } + if(!pgm) + spawn_error("No programmer has been specified"); + if(part_specified && !part) { + fprintf(stderr, "No valid part specified. Use -l to see the list of supported devices.\n"); + exit(-1); + } + if(!part) + spawn_error("No part has been specified"); + + // Try define memory type by address + if(memtype == UNKNOWN) { + if((start >= 0x4800) && (start < 0x4880)) { + memtype = OPT; + } + if((start >= part->ram_start) && (start < part->ram_start + part->ram_size)) { + memtype = RAM; + } + else if((start >= part->flash_start) && (start < part->flash_start + part->flash_size)) { + memtype = FLASH; + } + else if((start >= part->eeprom_start) && (start < part->eeprom_start + part->eeprom_size)) { + memtype = EEPROM; + } } - if (!(f = fopen(filename, "w"))) - spawn_error("Failed to open file"); - if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { - fprintf(stderr, "Reading from Intel hex file "); - ihex_write(f, buf, start, start + bytes_count); - } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || - is_ext(filename, ".srec")) { - printf( - "Reading from Motorola S-record files are not implemented (yet)\n"); + + if(memtype != UNKNOWN) { + // Selecting start addr depending on + // specified part and memtype + switch(memtype) { + case RAM: + if(!start_addr_specified) { + start = part->ram_start; + } + if(!bytes_count_specified || bytes_count > part->ram_size) { + bytes_count = part->ram_size; + } + fprintf(stderr, "Determine RAM area\r\n"); + break; + case EEPROM: + if(!start_addr_specified) { + start = part->eeprom_start; + } + if(!bytes_count_specified || bytes_count > part->eeprom_size) { + bytes_count = part->eeprom_size; + } + fprintf(stderr, "Determine EEPROM area\r\n"); + break; + case FLASH: + if(!start_addr_specified) { + start = part->flash_start; + } + if(!bytes_count_specified || bytes_count > part->flash_size) { + bytes_count = part->flash_size; + } + fprintf(stderr, "Determine FLASH area\r\n"); + break; + case OPT: + if(!start_addr_specified) { + start = 0x4800; + } + size_t opt_size = (part->flash_size <= 8*1024 ? 0x40 : 0x80); + if(!bytes_count_specified || bytes_count > opt_size) { + bytes_count = opt_size; + } + fprintf(stderr, "Determine OPT area\r\n"); + break; + } + start_addr_specified = true; + } + if(!action) + spawn_error("No action has been specified"); + if(!start_addr_specified) + spawn_error("No memtype or start_addr has been specified"); + if (!strlen(filename)) + spawn_error("No filename has been specified"); + if(!action || !start_addr_specified || !strlen(filename)) + print_help_and_exit(argv[0], true); + if(!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) + spawn_error("Couldn't initialize stlink"); + if(!pgm->open(pgm)) + spawn_error("Error communicating with MCU. Please check your SWIM connection."); + + + FILE *f; + if(action == READ) { + fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); + fflush(stderr); + int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes + unsigned char *buf = malloc(bytes_count_align); + if(!buf) spawn_error("malloc failed"); + int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); + if(recv < bytes_count_align) { + fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); + spawn_error("Failed to read MCU"); + } + if(!(f = fopen(filename, "w"))) + spawn_error("Failed to open file"); + if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) + { + fprintf(stderr, "Reading from Intel hex file "); + ihex_write(f, buf, start, start+bytes_count); + } + else if(is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) + { + printf("Reading from Motorola S-record files are not implemented (yet)\n"); printf("Exiting...\n"); - exit(0); - fprintf(stderr, "Reading from Motorola S-record file "); - srec_write(f, buf, start, start + bytes_count); - } else { - fwrite(buf, 1, bytes_count, f); - } - fclose(f); - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes received: %d\n", bytes_count); - } else if (action == VERIFY) { - fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); - fflush(stderr); - - int bytes_count_align = - ((bytes_count - 1) / 256 + 1) * - 256; // Reading should be done in blocks of 256 bytes - unsigned char *buf = malloc(bytes_count_align); - if (!buf) - spawn_error("malloc failed"); - int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); - if (recv < bytes_count_align) { - fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", - bytes_count_align, recv); - spawn_error("Failed to read MCU"); - } + fprintf(stderr, "Reading from Motorola S-record file "); + srec_write(f, buf, start, start+bytes_count); + } + else + { + fwrite(buf, 1, bytes_count, f); + } + fclose(f); + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes received: %d\n", bytes_count); + } else if (action == VERIFY) { + fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); + fflush(stderr); - if (!(f = fopen(filename, "r"))) - spawn_error("Failed to open file"); - unsigned char *buf2 = malloc(bytes_count); - if (!buf2) - spawn_error("malloc failed"); - int bytes_to_verify; - /* reading bytes to RAM */ - if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { - bytes_to_verify = ihex_read(f, buf, start, start + bytes_count); - } else { - fseek(f, 0L, SEEK_END); - bytes_to_verify = ftell(f); - if (bytes_count_specified) { - bytes_to_verify = bytes_count; - } else if (bytes_count < bytes_to_verify) { - bytes_to_verify = bytes_count; - } - fseek(f, 0, SEEK_SET); - fread(buf2, 1, bytes_to_verify, f); - } - fclose(f); - - if (memcmp(buf, buf2, bytes_to_verify) == 0) { - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); - } else { - fprintf(stderr, "FAILED\n"); - exit(-1); - } + int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes + unsigned char *buf = malloc(bytes_count_align); + if(!buf) spawn_error("malloc failed"); + int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); + if(recv < bytes_count_align) { + fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); + spawn_error("Failed to read MCU"); + } - } else if (action == WRITE) { - if (!(f = fopen(filename, "r"))) - spawn_error("Failed to open file"); - int bytes_count_align = ((bytes_count - 1) / part->flash_block_size + 1) * - part->flash_block_size; - unsigned char *buf = malloc(bytes_count_align); - if (!buf) - spawn_error("malloc failed"); - memset(buf, 0, bytes_count_align); // Clean aligned buffer - int bytes_to_write; - - /* reading bytes to RAM */ - if (is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { - fprintf(stderr, "Writing Intel hex file "); - bytes_to_write = ihex_read(f, buf, start, start + bytes_count); - } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || - is_ext(filename, ".srec")) { - fprintf(stderr, "Writing Motorola S-record file "); - bytes_to_write = srec_read(f, buf, start, start + bytes_count); - } else { - fprintf(stderr, "Writing binary file "); - fseek(f, 0L, SEEK_END); - bytes_to_write = ftell(f); - if (bytes_count_specified) { - bytes_to_write = bytes_count; - } else if (bytes_count < bytes_to_write) { - bytes_to_write = bytes_count; - } - fseek(f, 0, SEEK_SET); - fread(buf, 1, bytes_to_write, f); - } - fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); + if(!(f = fopen(filename, "r"))) + spawn_error("Failed to open file"); + unsigned char *buf2 = malloc(bytes_count); + if(!buf2) spawn_error("malloc failed"); + int bytes_to_verify; + /* reading bytes to RAM */ + if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { + bytes_to_verify = ihex_read(f, buf, start, start + bytes_count); + } else { + fseek(f, 0L, SEEK_END); + bytes_to_verify = ftell(f); + if(bytes_count_specified) { + bytes_to_verify = bytes_count; + } else if(bytes_count < bytes_to_verify) { + bytes_to_verify = bytes_count; + } + fseek(f, 0, SEEK_SET); + fread(buf2, 1, bytes_to_verify, f); + } + fclose(f); - /* flashing MCU */ - int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); - if (pgm->reset) { - // Restarting core (if applicable) - pgm->reset(pgm); - } - fprintf(stderr, "OK\n"); - fprintf(stderr, "Bytes written: %d\n", sent); - fclose(f); - } else if (action == UNLOCK) { - int bytes_to_write = part->option_bytes_size; - - if (part->read_out_protection_mode == ROP_UNKNOWN) - spawn_error("No unlocking mode defined for this device. You may need to " - "edit the file stm8.c"); - - unsigned char *buf = malloc(bytes_to_write); - if (!buf) - spawn_error("malloc failed"); - - if (part->read_out_protection_mode == ROP_STM8S_STD) { - for (int i = 0; i < bytes_to_write; i++) { - buf[i] = 0; - if ((i > 0) && ((i & 1) == 0)) - buf[i] = 0xff; - } - } + if(memcmp(buf, buf2, bytes_to_verify) == 0) { + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); + } else { + fprintf(stderr, "FAILED\n"); + exit(-1); + } - /* flashing MCU */ - int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); - if (pgm->reset) { - // Restarting core (if applicable) - pgm->reset(pgm); - } - fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); - fprintf(stderr, "Bytes written: %d\n", sent); - } - return (0); + + } else if (action == WRITE) { + if(!(f = fopen(filename, "r"))) + spawn_error("Failed to open file"); + int bytes_count_align = ((bytes_count-1)/part->flash_block_size+1)*part->flash_block_size; + unsigned char *buf = malloc(bytes_count_align); + if(!buf) spawn_error("malloc failed"); + memset(buf, 0, bytes_count_align); // Clean aligned buffer + int bytes_to_write; + + /* reading bytes to RAM */ + if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { + fprintf(stderr, "Writing Intel hex file "); + bytes_to_write = ihex_read(f, buf, start, start + bytes_count); + } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) { + fprintf(stderr, "Writing Motorola S-record file "); + bytes_to_write = srec_read(f, buf, start, start + bytes_count); + } else { + fprintf(stderr, "Writing binary file "); + fseek(f, 0L, SEEK_END); + bytes_to_write = ftell(f); + if(bytes_count_specified) { + bytes_to_write = bytes_count; + } else if(bytes_count < bytes_to_write) { + bytes_to_write = bytes_count; + } + fseek(f, 0, SEEK_SET); + fread(buf, 1, bytes_to_write, f); + } + fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); + + /* flashing MCU */ + int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); + if(pgm->reset) { + // Restarting core (if applicable) + pgm->reset(pgm); + } + fprintf(stderr, "OK\n"); + fprintf(stderr, "Bytes written: %d\n", sent); + fclose(f); + } else if (action == UNLOCK) { + int bytes_to_write=part->option_bytes_size; + + if (part->read_out_protection_mode==ROP_UNKNOWN) spawn_error("No unlocking mode defined for this device. You may need to edit the file stm8.c"); + + unsigned char *buf=malloc(bytes_to_write); + if(!buf) spawn_error("malloc failed"); + + if (part->read_out_protection_mode==ROP_STM8S_STD) { + for (int i=0; i0)&&((i&1)==0)) buf[i]=0xff; + } + } + + /* flashing MCU */ + int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); + if(pgm->reset) { + // Restarting core (if applicable) + pgm->reset(pgm); + } + fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); + fprintf(stderr, "Bytes written: %d\n", sent); + } + return(0); } diff --git a/srec.c b/srec.c index fc8ed88..8587bc4 100644 --- a/srec.c +++ b/srec.c @@ -1,21 +1,20 @@ /* stlink/v2 stm8 memory programming utility (c) Valentin Dudouyt, 2012 - 2014 */ -#include "byte_utils.h" -#include "error.h" -#include "srec.h" -#include #include #include #include +#include +#include "srec.h" +#include "error.h" +#include "byte_utils.h" char line[256]; -static unsigned char checksum(unsigned char *buf, unsigned int length, - int chunk_len, int chunk_addr, int chunk_type) { +static unsigned char checksum(unsigned char *buf, unsigned int length, int chunk_len, int chunk_addr, int chunk_type) { int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; unsigned int i; - for (i = 0; i < length; i++) { + for(i = 0; i < length; i++) { sum += buf[i]; } @@ -23,15 +22,17 @@ static unsigned char checksum(unsigned char *buf, unsigned int length, return complement & 0xff; } -static bool is_data_type(unsigned int chunk_type) { + +static bool is_data_type(unsigned int chunk_type) +{ return (chunk_type == 0x01 || chunk_type == 0x02 || chunk_type == 0x03); } -int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, - unsigned int end) { + + +int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { fseek(pFile, 0, SEEK_SET); - unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, - greatest_addr = 0; + unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; unsigned int number_of_records = 0; bool data_record = false; @@ -39,108 +40,83 @@ int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int expected_data_records = 0; unsigned int data_len = 0; - while (fgets(line, sizeof(line), pFile)) { - data_record = true; // Assume that the read data is a data record. Set to - // false if not. + while(fgets(line, sizeof(line), pFile)) { + data_record = true; //Assume that the read data is a data record. Set to false if not. line_no++; // Reading chunk header - if (sscanf(line, "S%01x%02x%04x", &chunk_type, &chunk_len, &chunk_addr) != 3) { + if(sscanf(line, "S%01x%02x%04x", &chunk_type, &chunk_len, &chunk_addr) != 3) { free(buf); ERROR2("Error while parsing SREC at line %d\n", line_no); } - if (chunk_type == 0x00 || - chunk_type == 0x04) // Header type record or reserved. Skip! - { - continue; - } else if (chunk_type == 0x05) { // This will contain the total expected - // number of data records. Save for error - // checking later - found_S5_rec = true; - if (chunk_len != - 3) { // Length field must contain a 3 to be a valid S5 record. - ERROR2("Error while parsing S5 Record at line %d\n", line_no); + if(chunk_type == 0x00 || chunk_type == 0x04) //Header type record or reserved. Skip! + { + continue; + } + else if(chunk_type == 0x05) + { //This will contain the total expected number of data records. Save for error checking later + found_S5_rec = true; + if (chunk_len != 3) { // Length field must contain a 3 to be a valid S5 record. + ERROR2("Error while parsing S5 Record at line %d\n", line_no); + } + expected_data_records = chunk_addr; //The expected total number of data records is saved in S503 field. + } + else if(is_data_type(chunk_type)) + { + data_len = chunk_len - chunk_type - 2; // See https://en.wikipedia.org/wiki/SREC_(file_format)#Record_types + } + else + { + continue; } - expected_data_records = chunk_addr; // The expected total number of data - // records is saved in S503 - // field. - } else if (is_data_type(chunk_type)) { - // See https://en.wikipedia.org/wiki/SREC_(file_format)#Record_types - data_len = chunk_len - chunk_type - 2; //Addr field differs with record type - } else { - continue; - } // Reading chunk data - for (i = 6 + 2 * chunk_type; i < 2 * data_len + 8; i += 2) { - if (sscanf(&(line[i]), "%02x", &byte) != 1) { - free(buf); - ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); + for(i = 6 + 2*chunk_type; i < 2*data_len + 8; i +=2) { + if(sscanf(&(line[i]), "%02x", &byte) != 1) { + free(buf); + ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); } - if (!is_data_type(chunk_type)) { - // The only data records have to be processed - data_record = false; - continue; + if(!is_data_type(chunk_type)) { + // The only data records have to be processed + data_record = false; + continue; } - if ((i - 8) / 2 >= chunk_len) { - // Respect chunk_len and do not capture checksum as data - break; + if((i - 8) / 2 >= chunk_len) { + // Respect chunk_len and do not capture checksum as data + break; } - if (chunk_addr < start) { - free(buf); - ERROR2("Address %04x is out of range at line %d\n", chunk_addr, - line_no); + if(chunk_addr < start) { + free(buf); + ERROR2("Address %04x is out of range at line %d\n", chunk_addr, line_no); } - if (chunk_addr + chunk_len > end) { - free(buf); - ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, - chunk_len, line_no); + if(chunk_addr + chunk_len > end) { + free(buf); + ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, chunk_len, line_no); } - if (chunk_addr + chunk_len > greatest_addr) { - greatest_addr = chunk_addr + chunk_len; + if(chunk_addr + chunk_len > greatest_addr) { + greatest_addr = chunk_addr + chunk_len; } buf[chunk_addr - start + (i - 8) / 2] = byte; } - if (data_record) { // We found a data record. Remember this. + if(data_record) { //We found a data record. Remember this. number_of_records++; } } - // Check to see if the number of data records expected is the same as we - // actually read. - if (found_S5_rec && number_of_records != expected_data_records) { - ERROR2("Error while comparing S5 record (number of data records: %d) with " - "the number actually read: %d\n", - expected_data_records, number_of_records); + //Check to see if the number of data records expected is the same as we actually read. + if(found_S5_rec && number_of_records != expected_data_records) { + ERROR2("Error while comparing S5 record (number of data records: %d) with the number actually read: %d\n", expected_data_records, number_of_records); } - return (greatest_addr - start); -} - -void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, - unsigned int end) { - ERROR("srec_write is not implemented!"); + return(greatest_addr - start); -unsigned int chunk_len, chunk_start, chunk_type, i, byte, line_no = 0, - greatest_addr = 0; -chunk_start = start; -while (chunk_start < end) { - chunk_len = end - chunk_start; - if (chunk_len > 32) { - chunk_len = 32; - } - fprintf(pFile, "S3%02X0000%04X", chunk_len + 6, chunk_start); - for (i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) { - fprintf(pFile, "%02X", buf[i]); - } - fprintf(pFile, "%02X\n", checksum(&buf[chunk_start - start], chunk_len, - chunk_len, chunk_start, 0)); - - chunk_start += chunk_len; } -fprintf(pFile, "S9030000FC\n"); + +void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { + ERROR("srec_write is not implemented!"); + /* Ducplicate most of the code from ihex.c ihex_write. */ } From 81cdfefee77650ec8337cb581c4a2d5041430edf Mon Sep 17 00:00:00 2001 From: Janne Virsunen Date: Sat, 28 Jan 2017 00:27:27 +0100 Subject: [PATCH 7/7] Fixed so that the program exits correctly when trying to use unimplemented S-record read --- main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.c b/main.c index 2c5874d..c54e481 100644 --- a/main.c +++ b/main.c @@ -323,6 +323,9 @@ int main(int argc, char **argv) { { printf("Reading from Motorola S-record files are not implemented (yet)\n"); printf("Exiting...\n"); + exit(-1); + + //TODO Remove the above message and exit, and implement reading from S-record. fprintf(stderr, "Reading from Motorola S-record file "); srec_write(f, buf, start, start+bytes_count); }