From 9c66c9ff7f982cf6096dcf8cf852848fc84c7c3c Mon Sep 17 00:00:00 2001 From: Justin Mitchell Date: Fri, 27 Sep 2013 17:13:44 +0100 Subject: [PATCH] Initial import of the bootloader code --- cli/Makefile | 19 + cli/boot.c | 237 +++++++++++++ cli/devices.c | 41 +++ cli/devices.h | 15 + cli/log.c | 36 ++ cli/log.h | 13 + cli/memory.c | 266 ++++++++++++++ cli/memory.h | 21 ++ cli/protocol.c | 267 ++++++++++++++ cli/protocol.h | 6 + cli/serial.c | 117 +++++++ cli/serial.h | 14 + cli/test.c | 75 ++++ mybootload.X/Makefile | 108 ++++++ mybootload.X/main.asm | 382 +++++++++++++++++++++ mybootload.X/nbproject/Makefile-default.mk | 132 +++++++ mybootload.X/nbproject/Makefile-genesis.properties | 8 + mybootload.X/nbproject/Makefile-impl.mk | 69 ++++ mybootload.X/nbproject/Makefile-local-default.mk | 36 ++ mybootload.X/nbproject/Makefile-variables.mk | 13 + mybootload.X/nbproject/Package-default.bash | 73 ++++ mybootload.X/nbproject/configurations.xml | 116 +++++++ .../private/SuppressibleMessageMemo.properties | 22 ++ mybootload.X/nbproject/private/configurations.xml | 25 ++ mybootload.X/nbproject/private/private.properties | 0 mybootload.X/nbproject/private/private.xml | 3 + mybootload.X/nbproject/project.properties | 0 mybootload.X/nbproject/project.xml | 15 + mybootload.X/spbrgselect.inc | 33 ++ 29 files changed, 2162 insertions(+) create mode 100644 cli/Makefile create mode 100644 cli/boot.c create mode 100644 cli/devices.c create mode 100644 cli/devices.h create mode 100644 cli/log.c create mode 100644 cli/log.h create mode 100644 cli/memory.c create mode 100644 cli/memory.h create mode 100644 cli/protocol.c create mode 100644 cli/protocol.h create mode 100644 cli/serial.c create mode 100644 cli/serial.h create mode 100644 cli/test.c create mode 100644 mybootload.X/Makefile create mode 100644 mybootload.X/main.asm create mode 100644 mybootload.X/nbproject/Makefile-default.mk create mode 100644 mybootload.X/nbproject/Makefile-genesis.properties create mode 100644 mybootload.X/nbproject/Makefile-impl.mk create mode 100644 mybootload.X/nbproject/Makefile-local-default.mk create mode 100644 mybootload.X/nbproject/Makefile-variables.mk create mode 100644 mybootload.X/nbproject/Package-default.bash create mode 100644 mybootload.X/nbproject/configurations.xml create mode 100644 mybootload.X/nbproject/private/SuppressibleMessageMemo.properties create mode 100644 mybootload.X/nbproject/private/configurations.xml create mode 100644 mybootload.X/nbproject/private/private.properties create mode 100644 mybootload.X/nbproject/private/private.xml create mode 100644 mybootload.X/nbproject/project.properties create mode 100644 mybootload.X/nbproject/project.xml create mode 100644 mybootload.X/spbrgselect.inc diff --git a/cli/Makefile b/cli/Makefile new file mode 100644 index 0000000..08de8b6 --- /dev/null +++ b/cli/Makefile @@ -0,0 +1,19 @@ +CFLAGS= -g -fstack-protector-all -Wall -pedantic -std=gnu99 -fPIC -D_GNU_SOURCE +LDFLAGS= $(CFLAGS) + +SRC=serial.c log.c boot.c protocol.c devices.c memory.c + +OBJS=$(SRC:%.c=%.o) + +all: boot test + +test: test.o + +boot: $(OBJS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJS) boot test + diff --git a/cli/boot.c b/cli/boot.c new file mode 100644 index 0000000..564bfbf --- /dev/null +++ b/cli/boot.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "serial.h" +#include "protocol.h" +#include "devices.h" +#include "memory.h" + +#define BAUD_RATE 19200 +#define PORT_NAME "/dev/ttyUSB0" + + +void usage(const char * name) +{ + loge("Usage: %s [-b baud] [-p port] [-i] [-v] {file.hex}\n", name); + loge("-b baud Set baudrate (default: %d)\n", BAUD_RATE); + loge("-p port Set serial port (default: %s)\n", PORT_NAME); + loge("-i ID Only mode.\n"); + loge("-v Verify after write\n"); +} + + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +int bitmask(int value) +{ + int out = 0; + if (value >= (1<<1)) out |= 1; + if (value >= (1<<2)) out |= 1<<1; + if (value >= (1<<3)) out |= 1<<2; + if (value >= (1<<4)) out |= 1<<3; + if (value >= (1<<5)) out |= 1<<4; + if (value >= (1<<6)) out |= 1<<5; + if (value >= (1<<7)) out |= 1<<6; + if (value >= (1<<8)) out |= 1<<7; + if (value >= (1<<9)) out |= 1<<8; + if (value >= (1<<10)) out |= 1<<9; + + return out; +} +/* + * This routine writes a memory plan out to the device + */ +int update_mem(port_t * pt, const devid_t * dev, uint16_t maxmem, mem_t * ram, int verify) +{ + mem_t * block = ram; + uint8_t buff[1024]; // scratch space + + for (block=ram; block != NULL; block=block->next) { + int bstart = block->start / 2; + + /* skip config words, we cant write them anyway */ + if (bstart >= 0x8000) { + logd("UpdateMem: skip config block @ %04x", bstart); + continue; + } + + + uint8_t * p = block->bytes; + int left = block->len; + uint16_t addr = bstart; + int rowlen = dev->rowsize * 2; + logd("UpdateMem: new block %d bytes @ %04x", block->len, bstart); + + while (left > 0) { + int off = 0; + int len = rowlen; + + memset(buff, 255, sizeof(buff)); + if (addr == bstart) { + /* first row, align the start */ + if (addr % dev->rowsize != 0) { + addr &= ~bitmask(dev->rowsize); + off = (bstart - addr) * 2; + len -= off; + logd("UpdateMem: realigning %04X to %04X", bstart, addr); + } + } + + len = MIN(len, left); + + logd("UpdateMem: Preparing %d bytes @ %04X", len, addr); + + /* partial row write, read first */ + if (off != 0 || len < rowlen) { + logd("UpdateMem: Read %d words @ %04x", dev->rowsize, addr); + if (loader_readmem(pt, addr, buff, dev->rowsize)) { + loge("UpdateMem: Aborting on failed read"); + return 1; + } + print_memory(addr, buff, dev->rowsize); + } + + /* update with new values */ + memcpy(&buff[off], p, len); + + /* write the row */ + logd("UpdateMem: Writing %d words @ %04x", dev->rowsize, addr); + print_memory(addr, buff, dev->rowsize); + if (loader_writemem(pt, addr, buff, dev->rowsize)) { + loge("UpdateMem: Aborting on failed write"); + return 1; + } + + if (verify) { + uint8_t again[1024]; + sleep(1); + logd("UpdateMem: Verify %d words @ %04x", dev->rowsize, addr); + if (loader_readmem(pt, addr, again, dev->rowsize)) { + loge("UpdateMem: Aborting on failed read"); + return 1; + } + print_memory(addr, again, dev->rowsize); + for (int i=0; irowsize; + } + } + return 0; +} + +int main(int argc, char **argv) +{ + int opt; + char * port = NULL; + int baud = BAUD_RATE; + int verify = 0; + int idonly = 0; + + while ((opt=getopt(argc, argv, "h?b:p:ivd"))!=-1) { + switch (opt) { + case 'b': + baud = atoi(optarg); + break; + case 'p': + if (port) free(port); + port = strdup(optarg); + break; + case 'v': + verify=1; + break; + case 'i': + idonly=1; + break; + case 'd': + debug++; + break; + case 'h': + case '?': + default: + usage(argv[0]); + return 1; + } + } + + if (port == NULL) port = PORT_NAME; + + if (!idonly && optind >= argc) { + loge("Error: missing hexfile"); + return 1; + } + + mem_t * ram = NULL; + + if (!idonly) { + FILE * fd = NULL; + if ((fd = fopen(argv[optind], "r"))==NULL) { + loge("Error opening %s: %s", argv[optind], strerror(errno)); + return 1; + } + ram = load_ihex(fd); + fclose(fd); + + logd("Memory Summary :-"); + list_mem(ram); + } + + logd("open serial port %s at %d baud", port, baud); + port_t * pt = serial_open(port, baud); + if (pt == NULL) return 1; + + uint16_t maxmem; + uint16_t devid; + if (loader_connect(pt, &maxmem, &devid)) { + return 1; + } + + const devid_t * dev = devid_to_info(devid); + + if (idonly) { + logi("Device ID: %04X", devid); + logi(" Free Mem: %d words available", maxmem); + if (dev != NULL) { + logi(" Dev Name: %s", dev->name ); + logi(" Max Mem: %d", dev->memsize ); + } + + return 0; + } + if (dev) logd("Device Name: %s", dev->name); + + /* check that the selected program will fit on this device */ + if (makesafe_mem(&ram, maxmem)) { + serial_close(pt); + return 1; + } + logd("After re-organisation"); + list_mem(ram); + + /* now write the updated memory plan to the device */ + if (!update_mem(pt, dev, maxmem, ram, verify)) { + if (verify) + logi("Device Write (and Verify) Complete"); + else + logi("Device Write Complete"); + } + + /* finished */ + serial_close(pt); + logd("done."); + return 0; + +} diff --git a/cli/devices.c b/cli/devices.c new file mode 100644 index 0000000..d3e949d --- /dev/null +++ b/cli/devices.c @@ -0,0 +1,41 @@ +#include +#include +#include "devices.h" + +/* list of devices we know the ID of */ +static const devid_t device_list[] = { + /* { devid, devmask, name, memwords, rowsize } */ + { 0x3020, 0x3FFF, "PIC16F1454", 0x2000, 32 }, + { 0x3024, 0x3FFF, "PIC16LF1454", 0x2000, 32 }, + { 0x3021, 0x3FFF, "PIC16F1455", 0x2000, 32 }, + { 0x3025, 0x3FFF, "PIC16LF1455", 0x2000, 32 }, + { 0x3023, 0x3FFF, "PIC16F1459", 0x2000, 32 }, + { 0x3027, 0x3FFF, "PIC16LF1459", 0x2000, 32 }, + { 0x1480, 0x3FE0, "PIC16F1847", 0x2000, 32 }, + { 0x14A0, 0x3FE0, "PIC16LF1847", 0x2000, 32 }, + { 0x1B80, 0x3FE0, "PIC12F1840", 0x1000, 32 }, + { 0x1BC0, 0x3FE0, "PIC12LF1840", 0x1000, 32 }, + { 0, 0, NULL, 0, 0} +}; + +const char *devidtoname(uint16_t devid) +{ + const devid_t *d = device_list; + while (d->name != NULL) { + if ((devid & d->mask) == d->id) + return d->name; + d++; + } + return "Unknown"; +} + +const devid_t * devid_to_info(uint16_t devid) +{ + const devid_t *d = device_list; + while (d->name != NULL) { + if ((devid & d->mask) == d->id) + return d; + d++; + } + return NULL; +} diff --git a/cli/devices.h b/cli/devices.h new file mode 100644 index 0000000..03b7272 --- /dev/null +++ b/cli/devices.h @@ -0,0 +1,15 @@ +#ifndef DEVICE_INFO_H +#define DEVICE_INFO_H + +typedef struct device_info { + uint16_t id; + uint16_t mask; + const char *name; + uint16_t memsize; + uint8_t rowsize; +} devid_t; + +const char *devidtoname(uint16_t devid); +const devid_t * devid_to_info(uint16_t devid); + +#endif diff --git a/cli/log.c b/cli/log.c new file mode 100644 index 0000000..ff27062 --- /dev/null +++ b/cli/log.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +#include "log.h" + +int debug = 0; + +void logit(int type, const char * format, ...) +{ + va_list va; + va_start(va, format); + + struct timeval now; + gettimeofday(&now, NULL); + + struct tm * now_tm = localtime(&(now.tv_sec)); + + if (type == LOG_INFO) { + vfprintf(stdout, format, va); + fprintf(stdout, "\n"); + } else + if (type == LOG_DEBUG) { + if (debug > 0) { + fprintf(stderr, "%02d:%02d:%02d.%03d ", now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, (int)(now.tv_usec / 1000)); + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); + } + } else { + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); + } + + va_end(va); +} diff --git a/cli/log.h b/cli/log.h new file mode 100644 index 0000000..c5d9f31 --- /dev/null +++ b/cli/log.h @@ -0,0 +1,13 @@ +/* log.c */ + +enum log_types { + LOG_DEBUG, LOG_ERROR, LOG_INFO +}; + +#define logd(...) logit(LOG_DEBUG, __VA_ARGS__) +#define loge(...) logit(LOG_ERROR, __VA_ARGS__) +#define logi(...) logit(LOG_INFO, __VA_ARGS__) + +extern int debug; + +void logit(int type, const char *format, ...); diff --git a/cli/memory.c b/cli/memory.c new file mode 100644 index 0000000..acc16e7 --- /dev/null +++ b/cli/memory.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include + +#include "log.h" +#include "memory.h" +#include "serial.h" +#include "devices.h" +#include "protocol.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +/* return 0 for end of file. -1 for error */ +int parse_ihex16(const char *line, uint8_t *bytes, int *addr, int *code) +{ + unsigned int sum, len, cksum; + unsigned int laddr, lcode; + int i; + const char *p; + + if (line[0] != ':') return -1; + if (strlen(line) < 11) return -1; + p = &line[1]; + if (!sscanf(p, "%02x", &len)) return -1; + p+=2; + if (strlen(line) < (11 + (len * 2))) return -1; + if (!sscanf(p, "%04x", &laddr)) return -1; + p += 4; + *addr = laddr; // little endian address record + if (!sscanf(p, "%02x", &lcode)) return -1; + p+=2; + *code = lcode & 0xFF; + + /* end of file record */ + if (*code == 1) return 0; + + sum = (len & 0xFF) + ((*addr >> 8) & 0xFF) + (*addr & 0xFF) + (*code & 0xFF); + + i = 0; + while (i < len) { + unsigned int byte; + /* files are little-endian */ + if (!sscanf(p, "%02x", &byte)) return -1; + bytes[i+1] = byte & 0xFF; + sum += byte & 0xFF; + p += 2; + + if (!sscanf(p, "%02x", &byte)) return -1; + bytes[i] = byte & 0xFF; + sum += byte & 0xFF; + i += 2; + p += 2; + } + if (!sscanf(p, "%02x", &cksum)) return -1; + if ( ((sum & 0xFF) + (cksum & 0xFF)) & 0xFF ) return -1; + return len; +} + +static void mem_add(mem_t **head, uint32_t start, uint8_t * bytes, int len) +{ + /* look for an existing block this overlaps/adjoins */ + mem_t * block = *head; + uint32_t end = start + len; + + for(block = *head; block!=NULL; block=block->next) { + int bend = block->start + block->len; + /* before and not touching */ + if (start < block->start && end+1 < block->start) continue; + /* after and not touching */ + if (start > bend+1) continue; + + /* therefore it at least touches */ + + /* starts before or on old block */ + if (start <= block->start) { + int pre=0, lap=0, post=0; + pre = block->start - start; // bytes before the old block + lap = len - pre; // bytes overlapping, from start + if (lap > block->len) { + post = lap - block->len; + lap = block->len; + } + int newsize = block->len + pre + post; + uint8_t * newbytes = malloc(newsize); + memcpy(&newbytes[pre], block->bytes, block->len); + memcpy(newbytes, bytes, len); + free(block->bytes); + block->bytes = newbytes; + block->len = newsize; + block->start -= pre; + } else { + /* starts part way down / at end */ + int pre=0, /*lap=0, */ post=0; + pre = start - block->start; // gap from start + //lap = MIN(block->len - pre, len); + if (end > bend) post = end - bend; + int newsize = block->len + post; + uint8_t * newbytes = malloc(newsize); + memcpy(newbytes, block->bytes, block->len); + memcpy(&newbytes[pre], bytes, len); + block->bytes = newbytes; + block->len = newsize; + } + return; + } + + block = calloc(1, sizeof(mem_t)); + block->start = start; + block->len = len; + block->bytes = malloc(len); + memcpy(block->bytes, bytes, len); + block->next = *head; + *head = block; +} + +mem_t * load_ihex(FILE *in) +{ + uint32_t addrh = 0; + + char buff[1024]; + + mem_t * ram = NULL; + + while (!feof(in) && fgets(buff, sizeof(buff), in)!=NULL) { + if (buff[0] == '#') continue; + + unsigned char bytes[80]; + int len, addr, code; + + if ((len=parse_ihex16(buff, bytes, &addr, &code)) <= 0) { + if (len < 0) loge("LoadIHEX: Bad line: %s\n", buff); + continue; + } + + if (code == 4) { + addrh = ((bytes[0] << 8) | bytes[1]) << 16; + logd("LoadIHEX: Setting high addr 0x%02X%02X", bytes[0], bytes[1]); + } else + if (code == 1) { + /* end of file marker */ + break; + } else + if (code == 0) { + /* normal code block */ + uint32_t fulladdr = addrh | addr; + mem_add(&ram, fulladdr, bytes, len); + } + } + return ram; +} + +/* summary of the memory blocks in this list */ +void list_mem(const mem_t * head) +{ + const mem_t *p = head; + while (p!=NULL) { + logd("%6X : %d bytes", p->start, p->len); + p = p->next; + } +} + +/* check that the program will fit */ +int validate_mem(mem_t * head, uint16_t maxmem) +{ + if (head == NULL) { + loge("MemValidate: No program!"); + return 1; + } + + mem_t * p; + int used = 0; + + /* test that all the memory blocks will fit */ + for (p=head; p!=NULL; p=p->next) { + /* just ignore config bytes, we cant write them anyway */ + if (p->start / 2 >= 0x8000) continue; + + used += p->len / 2; + + if (p->start / 2 >= maxmem || (p->start+p->len)/2 >= maxmem) { + loge("MemValidate: Program too large, overlaps bootloader."); + return 1; + } + } + + logd("MemValidate: Used %d of %d leaving %d free.", used, maxmem, maxmem-used); + + return 0; +} + +/* reorganise bytes to work with the boot loader */ +int makesafe_mem(mem_t **head, uint16_t maxmem) +{ + /* it must fit safely first */ + if (validate_mem(*head, maxmem)) return 1; + + mem_t * new = malloc(sizeof(mem_t)); + new->start = maxmem * 2; + new->len = 8; + new->bytes = malloc(8); + memset(new->bytes, 255, 8); + + int found = 0; + /* find the code that goes in words 0-3 and move it */ + mem_t * p = NULL; + for (p = *head; p!=NULL; p=p->next) { + if (p->start >= 0 && p->start <= 7) { + int pre = p->start; + int lap = MIN(8-pre, p->len); + memcpy(&new->bytes[pre], p->bytes, lap); + p->start += lap; + p->len -= lap; + memmove(p->bytes, &p->bytes[lap], p->len); + found++; + } + } + + if (!found) { + loge("MakeSafeMem: Could not find start vector"); + free(new); + return 1; + } + + /* check that there is something sane in here + * Warning: this is very enhanced-midrange dependant */ + found = 0; + uint8_t * m = new->bytes; + uint16_t lath = 0; + for (int i=0; i<4; i++) { + uint16_t in = (m[0] << 8) | m[1]; + if ((in & 0x3F80) == 0x3180) { // MOVLP + lath = in & 0x007F; + logd("MakeSafeMem: 0x%04X MOVLP 0x%02X", i, lath); + }else + if ((in & 0x3800) == 0x2800) { // GOTO + uint16_t addr = in & 0x07FF; + addr |= lath << 8; + logd("MakeSafeMem: 0x%04X GOTO 0x%02X", i, addr); + + if ( addr < 4) { + // an absolute goto within the reset vector + // this is silly and wrong, replace with NOP + logd("MakeSafeMem: Rewriting bad 'GOTO 0x%02X' to NOP", addr); + m[0] = 0; + m[1] = 0; + } else { + // there is a sane GOTO, hurrah + found = 1; + } + } + m += 2; + } + + if (!found) { + loge("Start Vector did not contain a GOTO"); + free(new); + return 1; + } + + new->next = *head; + *head = new; + + return 0; +} diff --git a/cli/memory.h b/cli/memory.h new file mode 100644 index 0000000..444f238 --- /dev/null +++ b/cli/memory.h @@ -0,0 +1,21 @@ +#ifndef MEMORY_BLOCK_H +#define MEMORY_BLOCK_H + +typedef struct memory { + uint32_t start; + uint16_t len; + uint8_t * bytes; + struct memory * next; +} mem_t; + +mem_t *load_ihex(FILE *in); +void list_mem(const mem_t * head); +int validate_mem(mem_t * head, uint16_t maxmem); +int makesafe_mem(mem_t **head, uint16_t maxmem); + + + + + + +#endif diff --git a/cli/protocol.c b/cli/protocol.c new file mode 100644 index 0000000..5d6e028 --- /dev/null +++ b/cli/protocol.c @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "serial.h" +#include "protocol.h" + +static uint8_t checksum(uint8_t * buff, int len) +{ + int sum = 0; + int i; + + for (i=0;i> 8; + buff[2] = addr & 0xFF; + buff[3] = checksum(buff, 3); + + int ret = serial_write(pt, buff, 4); + if (ret <= 0) return 1; + + bzero(buff, len); + + /* read the response */ + if (serial_read(pt, buff, 1)<=0) return 1; + + if (buff[0] == 'E') { + loge("ReadMem %04X: Loader gave error", addr); + return 2; + } + + if (buff[0] != 'R') { + loge("ReadMem %04X: Unknown response to read 0x%02X '%c'", addr, buff[0], buff[0]); + return 3; + } + + /* now read the address, and check it matches */ + ret = serial_read(pt, &buff[1], len-1); + if (ret < 1) { + loge("ReadMem %04X: Error read response", addr); + return 4; + } + if (ret < len-1) { + loge("ReadMem %04X: Short read %d of %d", addr, ret, len-1); + return 5; + } + + int sum = checksum(buff, len-1); + if ((sum & 0xFF) != buff[len-1]) { + loge("ReadMem %04X: Bad checksum. %02X != %02X", addr, sum & 0xFF, buff[len-1]); + return 6; + } + + uint16_t realaddr = (buff[1]<<8) | buff[2]; + if (realaddr != addr) { + loge("ReadMem %04X: Actual Address %04X", addr, realaddr); + return 7; + } + logd("ReadMem %04X: Read Successful", realaddr); + + memcpy(memory, &buff[3], (words * 2)); + free(buff); + + return 0; +} + + +int loader_writemem(port_t * pt, uint16_t addr, uint8_t * memory, int words) +{ + int len = (words * 2) + 4; + uint8_t * buff = malloc((words * 2) + 4); + + /* request to read memory block */ + buff[0] = 'W'; + buff[1] = addr >> 8; + buff[2] = addr & 0xFF; + + unsigned char * p = memory; + unsigned char * q = &buff[3]; + for (int i=0; i 0) { + if (buff[0] == 06) { + break; + } else { + logd("Connect: Want ESC (0x06) got 0x%02X ret=%d", buff[0], ret); + usleep(100000); + } + } + + if (ret <= 0) { + if (ret == 0) + loge("Connect: Serial port closed"); + else + loge("Connect: read error: %s", strerror(errno)); + return 1; + } + + /* Next we should see 'B' 'L' */ + while ((ret=serial_read(pt, &buff[1], 2))> 0) { + if (buff[1] == 'B' && buff[2] == 'L') { + bootload = 1; + break; + } else { + logd("Connect: Want 'BL' got '%c%c' ret=%d", buff[1], buff[2], ret); + } + bzero(buff,3); + } + + if (ret <= 0) { + if (ret == 0) + loge("Connect: Serial port closed"); + else + loge("Connect: read error: %s", strerror(errno)); + return 1; + } + + /* turn break off now we are in bootloader mode */ + serial_break(pt, 0); + + if (!bootload) { + serial_close(pt); + loge("Connect: Could not find bootloader"); + return 1; + } + + logd("Connect: Release break. Read memory size."); + + /* now read the bootloaders location, and thus mem size */ + ret=serial_read(pt, &buff[3], 5); + + if (ret < 3) { + if (ret == 0) + loge("Connect: Serial port closed"); + else + loge("Connect: read error: %s", strerror(errno)); + return 1; + } + + if (buff[7] != (checksum(buff,7) & 0xFF)) { + loge("Connect: Bad checksum"); + return 1; + } + + *devid = (buff[3] << 8) | buff[4]; + logd("Connect: Device ID: 0x%04X", *devid); + + *maxmem = (buff[5] << 8) | buff[6]; + logd("Connect: Memory Size: 0x%04X", *maxmem); + + return 0; +} diff --git a/cli/protocol.h b/cli/protocol.h new file mode 100644 index 0000000..4674ce0 --- /dev/null +++ b/cli/protocol.h @@ -0,0 +1,6 @@ +/* proto.c */ +void print_memory(uint16_t addr, const unsigned char *buff, int words); +void dumpbuff(const unsigned char *buff, int charlen); +int loader_readmem(port_t *pt, uint16_t addr, uint8_t *memory, int words); +int loader_writemem(port_t *pt, uint16_t addr, uint8_t *memory, int words); +int loader_connect(port_t *pt, uint16_t *maxmem, uint16_t *devid); diff --git a/cli/serial.c b/cli/serial.c new file mode 100644 index 0000000..6fb682a --- /dev/null +++ b/cli/serial.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "serial.h" + +struct serial_port { + int fd; +}; + +static speed_t baud(int speed) +{ + if (speed == 230400) return B230400; else + if (speed == 115200) return B115200; else + if (speed == 57600) return B57600; else + if (speed == 38400) return B38400; else + if (speed == 19200) return B19200; else + if (speed == 9600) return B9600; else + if (speed == 4800) return B4800; else + if (speed == 2400) return B2400; else + if (speed == 1200) return B1200; else { + loge("Error setting baud rate: %d not recognised.", speed); + return B0; + } + +} + +port_t * serial_open(const char *name, int speed) +{ + port_t *pt = NULL; + int fd; + + if ((fd = open(name, O_RDWR | O_NOCTTY))<0) { + loge("Error: opening %s: %s", name, strerror(errno)); + return NULL; + } + + struct termios adtio; + bzero(&adtio, sizeof(adtio)); + + tcgetattr(fd, &adtio); + adtio.c_cflag = CS8 | CLOCAL | CREAD; + adtio.c_iflag = IGNPAR | IGNBRK; + adtio.c_oflag = 0; + adtio.c_lflag = 0; // non-canon, no echo + + cfmakeraw(&adtio); + + adtio.c_cc[VTIME] = 0; + adtio.c_cc[VMIN] = 1; + + cfsetispeed(&adtio, baud(speed)); + cfsetospeed(&adtio, baud(speed)); + + tcsetattr(fd, TCSANOW, &adtio); + + pt = malloc(sizeof(port_t)); + pt->fd = fd; + + return pt; + +} + +void serial_close(port_t * pt) +{ + if (pt == NULL) return; + if (pt->fd < 0) return; + + close(pt->fd); + pt->fd = -1; + + return; +} + +int serial_read(port_t * pt, unsigned char * buff, size_t len) +{ + if (pt == NULL || pt->fd < 0) return -1; + + int ret = 0; + int count = 0; + unsigned char * p = buff; + while (count < len) { + ret = read(pt->fd, p, len-count); + if (ret <= 0) return ret; + p += ret; + count += ret; + } + return count; +} + +int serial_write(port_t * pt, unsigned char * buff, size_t len) +{ + if (pt == NULL || pt->fd < 0) return -1; + + return write(pt->fd, buff, len); +} + +int serial_break(port_t * pt, int set) +{ + if (pt == NULL || pt->fd < 0) return -1; + + if (set) + ioctl(pt->fd, TIOCSBRK, 0); + else + ioctl(pt->fd, TIOCCBRK, 0); + + return 0; +} + diff --git a/cli/serial.h b/cli/serial.h new file mode 100644 index 0000000..1baf110 --- /dev/null +++ b/cli/serial.h @@ -0,0 +1,14 @@ +/* Serial port controls */ + +struct serial_port; +typedef struct serial_port port_t; + +#define ACK 0x06 +#define NACK 0x15 + +/* serial.c */ +port_t *serial_open(const char *name, int speed); +void serial_close(port_t *pt); +int serial_read(port_t *pt, unsigned char *buff, size_t len); +int serial_write(port_t *pt, unsigned char *buff, size_t len); +int serial_break(port_t *pt, int set); diff --git a/cli/test.c b/cli/test.c new file mode 100644 index 0000000..d7d72ea --- /dev/null +++ b/cli/test.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +/* return 0 for end of file. -1 for error */ +int parse_ihex16(const char *line, uint8_t *bytes, int *addr, int *code) +{ + unsigned int sum, len, cksum; + unsigned int laddr, lcode; + int i; + const char *p; + + if (line[0] != ':') return -1; + if (strlen(line) < 11) return -1; + p = &line[1]; + if (!sscanf(p, "%02x", &len)) return -1; + p+=2; + if (strlen(line) < (11 + (len * 2))) return -1; + if (!sscanf(p, "%04x", &laddr)) return -1; + p += 4; + *addr = laddr; // little endian address record + if (!sscanf(p, "%02x", &lcode)) return -1; + p+=2; + *code = lcode & 0xFF; + + /* end of file record */ + if (*code == 1) return 0; + + sum = (len & 0xFF) + ((*addr >> 8) & 0xFF) + (*addr & 0xFF) + (*code & 0xFF); + + i = 0; + while (i < len) { + unsigned int byte; + if (!sscanf(p, "%02x", &byte)) return -1; + bytes[i++] = byte & 0xFF; + sum += byte & 0xFF; + p += 2; + } + if (!sscanf(p, "%02x", &cksum)) return -1; + if ( ((sum & 0xFF) + (cksum & 0xFF)) & 0xFF ) return -1; + return len; +} + +int main(int argc, char **argv) +{ + FILE *in; + + if (argc < 2) return 1; + + if ((in=fopen(argv[1], "r"))==NULL) { + fprintf(stderr, "Failed opening %s: %s\n", argv[1], strerror(errno)); + return 1; + } + + char buff[1024]; + + while (!feof(in) && fgets(buff, sizeof(buff), in)!=NULL) { + if (buff[0] == '#') continue; + + unsigned char bytes[80]; + int len, addr, code; + + if ((len=parse_ihex16(buff, bytes, &addr, &code)) <= 0) { + if (len < 0) fprintf(stderr, "Bad line: %s\n", buff); + continue; + } + + printf("Addr: %04X +%2d code=%d :", addr, len, code); + for (int i=0; i.dep.inc +# @if [ -n "${MAKE_VERSION}" ]; then \ +# echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES}))" >>.dep.inc; \ +# echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ +# echo "include \$${DEPFILES}" >>.dep.inc; \ +# echo "endif" >>.dep.inc; \ +# else \ +# echo ".KEEP_STATE:" >>.dep.inc; \ +# echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ +# fi diff --git a/mybootload.X/nbproject/Makefile-local-default.mk b/mybootload.X/nbproject/Makefile-local-default.mk new file mode 100644 index 0000000..ee6b645 --- /dev/null +++ b/mybootload.X/nbproject/Makefile-local-default.mk @@ -0,0 +1,36 @@ +# +# Generated Makefile - do not edit! +# +# +# This file contains information about the location of compilers and other tools. +# If you commmit this file into your revision control server, you will be able to +# to checkout the project and build it from the command line with make. However, +# if more than one person works on the same project, then this file might show +# conflicts since different users are bound to have compilers in different places. +# In that case you might choose to not commit this file and let MPLAB X recreate this file +# for each user. The disadvantage of not commiting this file is that you must run MPLAB X at +# least once so the file gets created and the project can be built. Finally, you can also +# avoid using this file at all if you are only building from the command line with make. +# You can invoke make with the values of the macros: +# $ makeMP_CC="/opt/microchip/mplabc30/v3.30c/bin/pic30-gcc" ... +# +PATH_TO_IDE_BIN=/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/ +# Adding MPLAB X bin directory to path. +PATH:=/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/:$(PATH) +# Path to java used to run MPLAB X when this makefile was created +MP_JAVA_PATH="/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/jre/bin/" +OS_CURRENT="$(shell uname -s)" +# MP_CC is not defined +# MP_CPPC is not defined +# MP_BC is not defined +MP_AS="/opt/microchip/mplabx/mpasmx/mpasmx" +MP_LD="/opt/microchip/mplabx/mpasmx/mplink" +MP_AR="/opt/microchip/mplabx/mpasmx/mplib" +DEP_GEN=${MP_JAVA_PATH}java -jar "/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/extractobjectdependencies.jar" +# MP_CC_DIR is not defined +# MP_CPPC_DIR is not defined +# MP_BC_DIR is not defined +MP_AS_DIR="/opt/microchip/mplabx/mpasmx" +MP_LD_DIR="/opt/microchip/mplabx/mpasmx" +MP_AR_DIR="/opt/microchip/mplabx/mpasmx" +# MP_BC_DIR is not defined diff --git a/mybootload.X/nbproject/Makefile-variables.mk b/mybootload.X/nbproject/Makefile-variables.mk new file mode 100644 index 0000000..9db2045 --- /dev/null +++ b/mybootload.X/nbproject/Makefile-variables.mk @@ -0,0 +1,13 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +CND_BASEDIR=`pwd` +# default configuration +CND_ARTIFACT_DIR_default=dist/default/production +CND_ARTIFACT_NAME_default=mybootload.X.production.hex +CND_ARTIFACT_PATH_default=dist/default/production/mybootload.X.production.hex +CND_PACKAGE_DIR_default=${CND_DISTDIR}/default/package +CND_PACKAGE_NAME_default=mybootload.x.tar +CND_PACKAGE_PATH_default=${CND_DISTDIR}/default/package/mybootload.x.tar diff --git a/mybootload.X/nbproject/Package-default.bash b/mybootload.X/nbproject/Package-default.bash new file mode 100644 index 0000000..c01315f --- /dev/null +++ b/mybootload.X/nbproject/Package-default.bash @@ -0,0 +1,73 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_CONF=default +CND_DISTDIR=dist +TMPDIR=build/${CND_CONF}/${IMAGE_TYPE}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} +OUTPUT_BASENAME=mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} +PACKAGE_TOP_DIR=mybootload.x/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/package +rm -rf ${TMPDIR} +mkdir -p ${TMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory ${TMPDIR}/mybootload.x/bin +copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/package/mybootload.x.tar +cd ${TMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/package/mybootload.x.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${TMPDIR} diff --git a/mybootload.X/nbproject/configurations.xml b/mybootload.X/nbproject/configurations.xml new file mode 100644 index 0000000..ef190a3 --- /dev/null +++ b/mybootload.X/nbproject/configurations.xml @@ -0,0 +1,116 @@ + + + + + spbrgselect.inc + + + + + main.asm + + + Makefile + + + Makefile + + + + localhost + PIC16F1455 + + + ICD3PlatformTool + MPASMWIN + 5.52 + 2 + + + + + + + + false + + + + + false + + false + + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mybootload.X/nbproject/private/SuppressibleMessageMemo.properties b/mybootload.X/nbproject/private/SuppressibleMessageMemo.properties new file mode 100644 index 0000000..832d3ca --- /dev/null +++ b/mybootload.X/nbproject/private/SuppressibleMessageMemo.properties @@ -0,0 +1,22 @@ +# +#Fri Sep 27 11:32:28 BST 2013 +mdbDebugger/MEMORY_VIEW_LAST_HW_BP_RESOURCE_WARN=false +pkobskde/CHECK_4_HIGH_VOLTAGE_VPP=false +pk3/DEVID_MISMATCH=false +mdbDebugger/NO_HW_COMBINER_RESOURCES_WARNING=false +mdbDebugger/NO_HW_BP_RESOURCES_WARN=false +mdbDebugger/MEMORY_VIEW_NO_HW_BP_RESOURCES_WARN=false +pk3/CHECK_CLOCK=false +mdbDebugger/LAST_HW_BP_RESOURCE_WARN=false +pk3/CHECK_4_HIGH_VOLTAGE_VPP=false +icd3/DEVID_MISMATCH=false +realice/DEVID_MISMATCH=false +realice/CHECK_CLOCK=false +pkoblicdbgr/DEVID_MISMATCH=false +pkoblicdbgr/CHECK_CLOCK=false +pkobskde/DEVID_MISMATCH=false +icd3/CHECK_CLOCK=false +realice/CHECK_4_HIGH_VOLTAGE_VPP=false +pkoblicdbgr/CHECK_4_HIGH_VOLTAGE_VPP=false +pkobskde/CHECK_CLOCK=false +icd3/CHECK_4_HIGH_VOLTAGE_VPP=true diff --git a/mybootload.X/nbproject/private/configurations.xml b/mybootload.X/nbproject/private/configurations.xml new file mode 100644 index 0000000..56374ed --- /dev/null +++ b/mybootload.X/nbproject/private/configurations.xml @@ -0,0 +1,25 @@ + + + Makefile + 0 + + + :=MPLABCommUSB:=04D8:=9009:=0100:=Microchip Technology, Inc. (www.microchip.com):=MPLAB ICD3 tm (www.microchip.com):=JIT123410560:=x:=en + /opt/microchip/mplabx/mpasmx + + place holder 1 + place holder 2 + + + + + true + 0 + 0 + 0 + + + + + + diff --git a/mybootload.X/nbproject/private/private.properties b/mybootload.X/nbproject/private/private.properties new file mode 100644 index 0000000..e69de29 diff --git a/mybootload.X/nbproject/private/private.xml b/mybootload.X/nbproject/private/private.xml new file mode 100644 index 0000000..e396670 --- /dev/null +++ b/mybootload.X/nbproject/private/private.xml @@ -0,0 +1,3 @@ + + + diff --git a/mybootload.X/nbproject/project.properties b/mybootload.X/nbproject/project.properties new file mode 100644 index 0000000..e69de29 diff --git a/mybootload.X/nbproject/project.xml b/mybootload.X/nbproject/project.xml new file mode 100644 index 0000000..f437b8e --- /dev/null +++ b/mybootload.X/nbproject/project.xml @@ -0,0 +1,15 @@ + + com.microchip.mplab.nbide.embedded.makeproject + + + mybootload + dc4e0df1-dbee-4df1-977e-9dfb5bf3e19a + 0 + + + + UTF-8 + + + + diff --git a/mybootload.X/spbrgselect.inc b/mybootload.X/spbrgselect.inc new file mode 100644 index 0000000..69c2a7e --- /dev/null +++ b/mybootload.X/spbrgselect.inc @@ -0,0 +1,33 @@ +RoundResult SET 0 ; Rounding function. RoundResult = Round(aa/bb) +Round macro aa,bb + LOCAL rr = aa/bb + LOCAL d1 = aa - rr*bb + LOCAL d2 = (rr+1)*bb - aa +RoundResult = rr + if d1 >= d2 +RoundResult++ + endif + endm + +AbsResult SET 0 +Abs macro nr + if nr>=0 +AbsResult = nr + else +AbsResult = -nr + endif + endm + + Round xtal,(16*baud) +spbrg_value EQU RoundResult-1 + + Round xtal,(16*(spbrg_value+1)) +baud_real EQU RoundResult + Abs(baud_real-baud) +errpercent EQU AbsResult*100/baud + if errpercent > 4 + ERROR big error in baudrate: #v(errpercent)% + endif + if errpercent >= 2 + messg baudrate not exact: #v(errpercent)% + endif \ No newline at end of file -- 1.8.3.1