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 643592d..2f13304 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; @@ -36,8 +37,8 @@ programmer_t pgms[] = { stlink_swim_read_range, stlink_swim_write_range, }, - { - "stlinkv2", + { + "stlinkv2", 0x0483, 0x3748, stlink2_open, @@ -142,7 +143,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 @@ -256,7 +258,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: @@ -311,6 +313,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); @@ -330,6 +334,16 @@ 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")) + { + 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); + } else { fwrite(buf, 1, bytes_count, f); @@ -362,9 +376,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); @@ -378,6 +392,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"); @@ -391,14 +407,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); @@ -426,7 +445,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..9f3e578 100644 --- a/pgm.h +++ b/pgm.h @@ -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 new file mode 100644 index 0000000..8587bc4 --- /dev/null +++ b/srec.c @@ -0,0 +1,122 @@ +/* stlink/v2 stm8 memory programming utility + (c) Valentin Dudouyt, 2012 - 2014 */ + +#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]; + } + + 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); +} + + + +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)) + { + data_len = chunk_len - chunk_type - 2; // See https://en.wikipedia.org/wiki/SREC_(file_format)#Record_types + } + 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); + +} + + +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. */ +} 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