diff --git a/Makefile b/Makefile index dff09cc..ee304c1 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,15 @@ CFLAGS=-Wall OBJS=\ $(OBJDIR)/p1load.o \ -$(OBJDIR)/ploader.o +$(OBJDIR)/port.o \ +$(OBJDIR)/ploader.o \ +$(OBJDIR)/packet.o + +EEPROM_OBJS=\ +$(OBJDIR)/eeprom.o \ +$(OBJDIR)/port.o \ +$(OBJDIR)/ploader.o \ +$(OBJDIR)/packet.o OS?=macosx @@ -29,22 +37,22 @@ ifeq ($(OS),raspberrypi) OS=linux CFLAGS+=-DLINUX -DRASPBERRY_PI EXT= -OSINT=osint_linux +OSINT=osint_linux.o LIBS= -OBJS+=$(OBJDIR)/gpio_sysfs.o +OSINT+=gpio_sysfs.o endif ifeq ($(OS),msys) CFLAGS+=-DMINGW EXT=.exe -OSINT=osint_mingw enumcom +OSINT=osint_mingw.o enumcom.o LIBS=-lsetupapi endif ifeq ($(OS),macosx) CFLAGS+=-DMACOSX EXT= -OSINT=osint_linux +OSINT=osint_linux.o LIBS= endif @@ -58,22 +66,28 @@ BINDIR=bin/$(OS) TARGET=$(BINDIR)/p1load$(EXT) +EEPROM_TARGET=$(BINDIR)/eeprom$(EXT) + HDRS=\ ploader.h -OBJS+=$(foreach x, $(OSINT), $(OBJDIR)/$(x).o) +OBJS+=$(foreach x, $(OSINT), $(OBJDIR)/$(x)) +EEPROM_OBJS+=$(foreach x, $(OSINT), $(OBJDIR)/$(x)) CFLAGS+=-Wall LDFLAGS=$(CFLAGS) .PHONY: default -default: $(TARGET) +default: $(TARGET) $(EEPROM_TARGET) DIRS=$(OBJDIR) $(BINDIR) $(TARGET): $(BINDIR) $(OBJDIR) $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) +$(EEPROM_TARGET): $(BINDIR) $(OBJDIR) $(EEPROM_OBJS) + $(CC) $(LDFLAGS) -o $@ $(EEPROM_OBJS) $(LIBS) + $(OBJDIR)/%.o: $(SRCDIR)/%.c $(HDRS) $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ diff --git a/eeprom.c b/eeprom.c new file mode 100644 index 0000000..a90f90d --- /dev/null +++ b/eeprom.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include +#include +#include "port.h" +#include "ploader.h" +#include "packet.h" +#include "osint.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* port prefix */ +#if defined(CYGWIN) || defined(WIN32) || defined(MINGW) + #define PORT_PREFIX "" +#elif defined(LINUX) + #ifdef RASPBERRY_PI + #define PORT_PREFIX "ttyAMA" + #else + #define PORT_PREFIX "ttyUSB" + #endif +#elif defined(MACOSX) + #define PORT_PREFIX "cu.usbserial-" +#else + #define PORT_PREFIX "" +#endif + +/* defaults */ +#define BAUD_RATE 115200 + +/* constants */ +#define HUB_MEMORY_SIZE 32768 + +static PL_state state; + +static void Usage(void); +static uint8_t *ReadEntireFile(char *name, long *pSize); + +int main(int argc, char *argv[]) +{ + char actualPort[PATH_MAX], *var, *val, *port, *p; + int baudRate, baudRate2, verbose, i; + char *file = NULL; + long imageSize; + uint8_t *image; + + /* initialize */ + baudRate = baudRate2 = BAUD_RATE; + verbose = FALSE; + port = NULL; + + /* initialize the loader port */ + InitPortState(&state); + + /* process the position-independent arguments */ + for (i = 1; i < argc; ++i) { + + /* handle switches */ + if (argv[i][0] == '-') { + switch (argv[i][1]) { + case 'b': + if (argv[i][2]) + p = &argv[i][2]; + else if (++i < argc) + p = argv[i]; + else + Usage(); + if (*p != ':') + baudRate = baudRate2 = atoi(p); + if ((p = strchr(p, ':')) != NULL) { + if (*++p != ':' && *p != '\0') + baudRate2 = atoi(p); + } + break; + case 'D': + if (argv[i][2]) + p = &argv[i][2]; + else if (++i < argc) + p = argv[i]; + else + Usage(); + if ((var = strtok(p, "=")) != NULL) { + if ((val = strtok(NULL, "")) != NULL) { + if (strcmp(var, "reset") == 0) + use_reset_method(val); + else + Usage(); + } + else + Usage(); + } + else + Usage(); + break; + case 'p': + if (argv[i][2]) + port = &argv[i][2]; + else if (++i < argc) + port = argv[i]; + else + Usage(); +#if defined(CYGWIN) || defined(WIN32) || defined(LINUX) + if (isdigit((int)port[0])) { +#if defined(CYGWIN) || defined(WIN32) + static char buf[10]; + sprintf(buf, "COM%d", atoi(port)); + port = buf; +#endif +#if defined(LINUX) + static char buf[64]; + sprintf(buf, "/dev/%s%d", PORT_PREFIX, atoi(port)); + port = buf; +#endif + } +#endif +#if defined(MACOSX) + if (port[0] != '/') { + static char buf[64]; + sprintf(buf, "/dev/%s-%s", PORT_PREFIX, port); + port = buf; + } +#endif + break; + case 'P': + ShowPorts(&state, PORT_PREFIX); + break; + case 'r': + break; + case 'v': + verbose = TRUE; + break; + case '?': + /* fall through */ + default: + Usage(); + break; + } + } + + /* handle the input filename */ + else { + if (file) + Usage(); + file = argv[i]; + } + } + + switch (InitPort(&state, PORT_PREFIX, port, baudRate, verbose, actualPort)) { + case CHECK_PORT_OK: + printf("Found propeller version %d on %s\n", state.version, actualPort); + break; + case CHECK_PORT_OPEN_FAILED: + printf("error: opening serial port '%s'\n", port); + perror("Error is "); + return 1; + case CHECK_PORT_NO_PROPELLER: + if (port) + printf("error: no propeller chip on port '%s'\n", port); + else + printf("error: can't find a port with a propeller chip\n"); + return 1; + } + +#define HELPER "pkt_test.binary" + + /* read the entire file into a buffer */ + if (!(image = ReadEntireFile(HELPER, &imageSize))) { + printf("error: reading '%s'\n", HELPER); + return 1; + } + + /* make sure the file isn't too big for hub memory */ + if (imageSize > HUB_MEMORY_SIZE) { + printf("error: image too big for hub memory\n"); + return 1; + } + + /* load the file from the memory buffer */ + printf("Loading '%s' (%ld bytes)\n", HELPER, imageSize); + switch (PL_LoadSpinBinary(&state, LOAD_TYPE_RUN, image, imageSize)) { + case LOAD_STS_OK: + printf("OK\n"); + break; + case LOAD_STS_ERROR: + printf("Error\n"); + return 1; + case LOAD_STS_TIMEOUT: + printf("Timeout\n"); + return 1; + default: + printf("Internal error\n"); + return 1; + } + +{ +enum { + OP_RESULT, + OP_ADD, + OP_SUB +}; + int32_t type, sts; + int32_t buf[2]; + while (1) { + printf("type and two arguments: "); + scanf("%d %d %d", &type, &buf[0], &buf[1]); + printf("%d %d %d\n", type, buf[0], buf[1]); + printf("sizeof(buf) = %lu\n", sizeof(buf)); + sts = SendPacket(type, (void *)buf, sizeof(buf)); + printf("SendPacket returned %d\n", sts); + if (sts == 0) { + sts = ReceivePacket(&type, (void *)buf, sizeof(buf)); + printf("ReceivePacket returned %d\n", sts); + if (sts >= 0) + printf("%d %d\n", type, buf[0]); + } + } +} + + return 0; +} + +/* Usage - display a usage message and exit */ +static void Usage(void) +{ +printf("\ +p1load - a simple loader for the propeller - %s, %s\n\ +usage: p1load\n\ + [ -b baud ] baud rate (default is %d)\n\ + [ -D var=val ] set variable value\n\ + [ -p port ] serial port (default is to auto-detect the port)\n\ + [ -P ] list available serial ports\n\ + [ -r addr:len ] read from eeprom\n\ + [ -v ] verbose output\n\ + [ -w addr write to eeprom\n\ + [ -? ] display a usage message and exit\n\ + file file to load\n", VERSION, __DATE__, BAUD_RATE); +#ifdef RASPBERRY_PI +printf("\ +\n\ +Supports resetting the Propeller with a GPIO pin with option: -Dreset=gpio,pin,level\n\ +where \"pin\" is the GPIO number to use and \"level\" is the logic level, 0 or 1. This\n\ +defaults to GPIO 17 and level 0.\n\ +"); +#endif + exit(1); +} + +/* ReadEntireFile - read an entire file into an allocated buffer */ +static uint8_t *ReadEntireFile(char *name, long *pSize) +{ + uint8_t *buf; + long size; + FILE *fp; + + /* open the file in binary mode */ + if (!(fp = fopen(name, "rb"))) + return NULL; + + /* get the file size */ + fseek(fp, 0L, SEEK_END); + size = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + /* allocate a buffer for the file contents */ + if (!(buf = (uint8_t *)malloc(size))) { + fclose(fp); + return NULL; + } + + /* read the contents of the file into the buffer */ + if (fread(buf, 1, size, fp) != size) { + free(buf); + fclose(fp); + return NULL; + } + + /* close the file ad return the buffer containing the file contents */ + *pSize = size; + fclose(fp); + return buf; +} diff --git a/p1load.c b/p1load.c index 113845d..affa87f 100644 --- a/p1load.c +++ b/p1load.c @@ -4,6 +4,7 @@ #include #include #include +#include "port.h" #include "ploader.h" #include "osint.h" @@ -33,80 +34,10 @@ /* constants */ #define HUB_MEMORY_SIZE 32768 -/* CheckPort state structure */ -typedef struct { - int baud; - int verbose; - char *actualport; -} CheckPortInfo; - -/* CheckPort result codes */ -enum { - CHECK_PORT_OK, - CHECK_PORT_OPEN_FAILED, - CHECK_PORT_NO_PROPELLER -}; - -static void cb_reset(void *data) -{ - hwreset(); -} - -static int cb_tx(void *data, uint8_t* buf, int n) -{ - return tx(buf, n); -} - -static int cb_rx_timeout(void *data, uint8_t* buf, int n, int timeout) -{ - return rx_timeout(buf, n, timeout); -} - -static void cb_msleep(void *data, int msecs) -{ - msleep(msecs); -} - -static void cb_progress(void *data, int phase) -{ - switch (phase) { - case LOAD_PHASE_HANDSHAKE: - break; - case LOAD_PHASE_RESPONSE: - break; - case LOAD_PHASE_VERSION: - break; - case LOAD_PHASE_HANDSHAKE_DONE: - break; - case LOAD_PHASE_PROGRAM: - printf("Loading hub memory ... "); - fflush(stdout); - break; - case LOAD_PHASE_EEPROM_WRITE: - printf("OK\nWriting EEPROM ... "); - fflush(stdout); - break; - case LOAD_PHASE_EEPROM_VERIFY: - printf("OK\nVerifying EEPROM ... "); - fflush(stdout); - break; - case LOAD_PHASE_DONE: - break; - default: - break; - } -} - static PL_state state; -static int version; static void Usage(void); static uint8_t *ReadEntireFile(char *name, long *pSize); -static int ShowPort(const char* port, void* data); -static void ShowPorts(char *prefix); -static int CheckPort(const char* port, void* data); -static int InitPort(char *prefix, char *port, int baud, int verbose, char *actualport); -static int OpenPort(const char* port, int baud); int main(int argc, char *argv[]) { @@ -123,20 +54,8 @@ int main(int argc, char *argv[]) verbose = terminalMode = pstMode = FALSE; port = NULL; - /* initialize the loader */ - PL_Init(&state); - state.reset = cb_reset; - state.tx = cb_tx; - state.rx_timeout = cb_rx_timeout; - state.progress = cb_progress; - state.msleep = cb_msleep; -#ifdef RASPBERRY_PI -{ - char cmd[20] = "gpio,17,0"; - // use_reset_method uses strtok to parse the string so it can't be a constant - use_reset_method(cmd); -} -#endif + /* initialize the loader port */ + InitPortState(&state); /* process the position-independent arguments */ for (i = 1; i < argc; ++i) { @@ -215,7 +134,7 @@ int main(int argc, char *argv[]) #endif break; case 'P': - ShowPorts(PORT_PREFIX); + ShowPorts(&state, PORT_PREFIX); break; case 'r': if (!loadTypeOptionSeen) { @@ -249,22 +168,24 @@ int main(int argc, char *argv[]) } } - switch (InitPort(PORT_PREFIX, port, baudRate, verbose, actualPort)) { - case CHECK_PORT_OK: - printf("Found propeller version %d on %s\n", version, actualPort); - break; - case CHECK_PORT_OPEN_FAILED: - printf("error: opening serial port '%s'\n", port); - perror("Error is "); - return 1; - case CHECK_PORT_NO_PROPELLER: - if (port) - printf("error: no propeller chip on port '%s'\n", port); - else - printf("error: can't find a port with a propeller chip\n"); - return 1; + if (file || terminalMode) { + switch (InitPort(&state, PORT_PREFIX, port, baudRate, verbose, actualPort)) { + case CHECK_PORT_OK: + printf("Found propeller version %d on %s\n", state.version, actualPort); + break; + case CHECK_PORT_OPEN_FAILED: + printf("error: opening serial port '%s'\n", port); + perror("Error is "); + return 1; + case CHECK_PORT_NO_PROPELLER: + if (port) + printf("error: no propeller chip on port '%s'\n", port); + else + printf("error: can't find a port with a propeller chip\n"); + return 1; + } } - + /* check for a file to load */ if (file) { @@ -372,69 +293,3 @@ static uint8_t *ReadEntireFile(char *name, long *pSize) fclose(fp); return buf; } - -static int ShowPort(const char* port, void* data) -{ - printf("%s\n", port); - return 1; -} - -static void ShowPorts(char *prefix) -{ - serial_find(prefix, ShowPort, NULL); -} - -static int CheckPort(const char* port, void* data) -{ - CheckPortInfo* info = (CheckPortInfo*)data; - int rc; - if (info->verbose) - printf("Trying %s \n", port); fflush(stdout); - if ((rc = OpenPort(port, info->baud)) != CHECK_PORT_OK) - return rc; - if (info->actualport) { - strncpy(info->actualport, port, PATH_MAX - 1); - info->actualport[PATH_MAX - 1] = '\0'; - } - return 0; -} - -static int InitPort(char *prefix, char *port, int baud, int verbose, char *actualport) -{ - int result; - - if (port) { - if (actualport) { - strncpy(actualport, port, PATH_MAX - 1); - actualport[PATH_MAX - 1] = '\0'; - } - result = OpenPort(port, baud); - } - else { - CheckPortInfo info; - info.baud = baud; - info.verbose = verbose; - info.actualport = actualport; - if (serial_find(prefix, CheckPort, &info) == 0) - result = CHECK_PORT_OK; - else - result = CHECK_PORT_NO_PROPELLER; - } - - return result; -} - -static int OpenPort(const char* port, int baud) -{ - /* open the port */ - if (serial_init(port, baud) == 0) - return CHECK_PORT_OPEN_FAILED; - - /* check for a propeller on this port */ - if (PL_HardwareFound(&state, &version) != LOAD_STS_OK) { - serial_done(); - return CHECK_PORT_NO_PROPELLER; - } - - return CHECK_PORT_OK; -} diff --git a/packet.c b/packet.c new file mode 100644 index 0000000..219afa5 --- /dev/null +++ b/packet.c @@ -0,0 +1,173 @@ +/* packet.c - an elf and spin binary loader for the Parallax Propeller microcontroller + Copyright (c) 2011 David Michael Betz + See license at the end of the file +*/ + +#include +#include +#include "packet.h" +#include "osint.h" + +/* packet format: SOH pkt# type length-lo length-hi hdrchk length*data crc1 crc2 */ +#define HDR_SOH 0 +#define HDR_TYPE 1 +#define HDR_LEN_HI 2 +#define HDR_LEN_LO 3 +#define HDR_CHK 4 + +/* packet header and crc lengths */ +#define PKTHDRLEN 5 +#define PKTCRCLEN 2 + +/* maximum length of a frame */ +#define FRAMELEN (PKTHDRLEN + PKTMAXLEN + PKTCRCLEN) + +/* protocol characters */ +#define SOH 0x01 /* start of a packet */ + +#define updcrc(crc, ch) (crctab[((crc) >> 8) & 0xff] ^ ((crc) << 8) ^ (ch)) + +static const uint16_t crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +int SendPacket(int type, uint8_t *buf, int len) +{ + uint8_t hdr[PKTHDRLEN], crc[PKTCRCLEN], *p; + uint16_t crc16 = 0; + int cnt; + + /* setup the frame header */ + hdr[HDR_SOH] = SOH; /* SOH */ + hdr[HDR_TYPE] = type; /* type type */ + hdr[HDR_LEN_HI] = (uint8_t)(len >> 8); /* data length - high byte */ + hdr[HDR_LEN_LO] = (uint8_t)len; /* data length - low byte */ + hdr[HDR_CHK] = hdr[1] + hdr[2] + hdr[3]; /* header checksum */ + printf("tx length %d\n", len); + printf("%02x %02x %02x\n", hdr[1], hdr[2], hdr[3]); + + /* compute the crc */ + for (p = buf, cnt = len; --cnt >= 0; ++p) + crc16 = updcrc(crc16, *p); + crc16 = updcrc(crc16, '\0'); + crc16 = updcrc(crc16, '\0'); + + /* add the crc to the frame */ + crc[0] = (uint8_t)(crc16 >> 8); + crc[1] = (uint8_t)crc16; + + /* send the packet */ + tx(hdr, PKTHDRLEN); + if (len > 0) + tx(buf, len); + tx(crc, PKTCRCLEN); + + return 0; +} + +int ReceivePacket(int *pType, uint8_t *buf, int len) +{ + uint8_t hdr[PKTHDRLEN], crc[PKTCRCLEN]; + int actual_len, chk; + uint16_t crc16 = 0; + int retries = 10; + printf("Looking for SOH\n"); + + /* look for start of packet */ + do { + rx_timeout(&hdr[HDR_SOH], 1, 100); + } while (hdr[HDR_SOH] != SOH && --retries >= 0); + printf(" retries %d\n", retries); + + /* check for a timeout waiting for the packet */ + if (retries < 0) + return -1; + + /* receive the rest of the header */ + rx(&hdr[HDR_TYPE], PKTHDRLEN - 1); + printf("%02x %02x %02x %02x %02x\n", hdr[0], hdr[1], hdr[2], hdr[3], hdr[4]); + + /* check the header checksum */ + chk = (hdr[1] + hdr[2] + hdr[3]) & 0xff; + if (hdr[HDR_CHK] != chk) + return -1; + printf("checksum okay\n"); + + /* make sure the buffer is big enough for the payload */ + actual_len = (hdr[HDR_LEN_HI] << 8) | hdr[HDR_LEN_LO]; + printf("rx length %d\n", actual_len); + if (actual_len > len) + return -1; + printf("length okay\n"); + + /* receive the packet payload */ + rx(buf, actual_len); + + /* compute the crc */ + for (len = actual_len; --len >= 0; ) + crc16 = updcrc(crc16, *buf++); + + /* receive the crc */ + rx(crc, PKTCRCLEN); + + /* check the crc */ + crc16 = updcrc(crc16, crc[0]); + crc16 = updcrc(crc16, crc[1]); + if (crc16 != 0) + return -1; + printf("crc okay\n"); + + /* return packet type and the length of the payload */ + *pType = hdr[HDR_TYPE]; + return actual_len; +} + +/* + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..1f0d565 --- /dev/null +++ b/packet.h @@ -0,0 +1,32 @@ +/* packet.h - an elf and spin binary loader for the Parallax Propeller microcontroller + +Copyright (c) 2011 David Michael Betz + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef __PACKET_H__ +#define __PACKET_H__ + +#include + +#define PKTMAXLEN 1024 + +int SendPacket(int type, uint8_t *buf, int len); +int ReceivePacket(int *pType, uint8_t *buf, int len); + +#endif diff --git a/packet_driver.spin b/packet_driver.spin new file mode 100644 index 0000000..8a6691e --- /dev/null +++ b/packet_driver.spin @@ -0,0 +1,409 @@ +''********************************************* +''* Bidirectional Packet Driver * +''* (C) 2011-2015 David Betz * +''* Based on: * +''* Full-Duplex Serial Driver v1.1 Extended * +''* (C) 2006 Parallax, Inc. * +''********************************************* + +CON + + ' command codes + #0 + CMD_IDLE ' must be zero + CMD_RXPACKET + CMD_TXPACKET + + ' status codes + #0 + STATUS_OK + STATUS_ERROR + + ' init offsets + #0 + INIT_MBOX ' zeroed by driver after init is done + INIT_RXPIN + INIT_TXPIN + INIT_BAUDRATE + _INIT_SIZE + + ' mailbox offsets + #0 + MBOX_CMD + MBOX_TYPE ' or pointer to type on rx + MBOX_BUFFER + MBOX_LENGTH ' or pointer to length on rx + MBOX_STATUS + MBOX_COG ' not really part of the mailbox + _MBOX_SIZE + + ' character codes + SOH = $01 ' start of a packet + +VAR + long mbox[_MBOX_SIZE] + +PUB start(rxpin, txpin, baudrate) | init[_INIT_SIZE], cogn + +'' Start packet driver - starts a cog +'' returns zero on success and non-zero if no cog is available +'' + + ' stop the driver if it's already running + stop + + ' start the driver cog + init[INIT_MBOX] := @mbox + init[INIT_RXPIN] := rxpin + init[INIT_TXPIN] := txpin + init[INIT_BAUDRATE] := clkfreq / baudrate + cogn := mbox[MBOX_COG] := cognew(@entry, @init) + 1 + + ' if the cog started okay wait for it to finish initializing + if cogn + repeat while init[INIT_MBOX] <> 0 + + return !cogn + +PUB stop + if mbox[MBOX_COG] + cogstop(mbox[MBOX_COG]~ - 1) + +PUB rx(ptype, buffer, plength) + + mbox[MBOX_BUFFER] := buffer + mbox[MBOX_LENGTH] := long[plength] + + mbox[MBOX_CMD] := CMD_RXPACKET + repeat while mbox[MBOX_CMD] <> CMD_IDLE + + long[ptype] := mbox[MBOX_TYPE] + long[plength] := mbox[MBOX_LENGTH] + + return mbox[MBOX_STATUS] + +PUB tx(type, buffer, length) + + mbox[MBOX_TYPE] := type + mbox[MBOX_BUFFER] := buffer + mbox[MBOX_LENGTH] := length + + mbox[MBOX_CMD] := CMD_TXPACKET + repeat while mbox[MBOX_CMD] <> CMD_IDLE + + return mbox[MBOX_STATUS] + +DAT + +'*********************************** +'* Assembly language serial driver * +'*********************************** + + org +' +' +' Entry +' +entry mov t1, par 'get init structure address + + rdlong t2, t1 'get the mailbox address + mov cmd_ptr, t2 'offset 0 - cmd + add t2, #4 + mov pkt_type_ptr, t2 'offset 1 - type + add t2, #4 + mov pkt_buffer_ptr, t2 'offset 2 - buffer + add t2, #4 + mov pkt_length_ptr, t2 'offset 3 - length + add t2, #4 + mov pkt_status_ptr, t2 'offset 4 - status + + add t1, #4 'get rx_pin + rdlong t2, t1 + mov rxmask, #1 + shl rxmask, t2 + + add t1, #4 'get tx_pin + rdlong t2, t1 + mov txmask, #1 + shl txmask, t2 + + add t1, #4 'get bit_ticks + rdlong bitticks, t1 + + or outa, txmask 'initialize the tx pin + or dira, txmask + andn dira, rxmask 'initialize the rx pin + + rdlong t1, #0 + add t1, cnt + waitcnt t1, #0 + + mov t1, #CMD_IDLE 'no command in progress + wrlong t1, cmd_ptr + + mov t1, #0 'signal end of initialization + wrlong t1, par + +next_cmd mov t1, #CMD_IDLE 'no command in progress + wrlong t1, cmd_ptr +:wait rdlong t1, cmd_ptr wz 'wait for a command + if_z jmp #:wait + add t1, #dispatch + jmp t1 + +dispatch jmp #next_cmd 'should never happen + jmp #do_rxpacket + jmp #do_txpacket + +' receive a packet +do_rxpacket rdlong rcv_ptr, pkt_buffer_ptr + rdlong t1, pkt_length_ptr + rdlong rcv_max, t1 + call #rxpacket + if_c wrlong ok_status, pkt_status_ptr + if_c wrlong rcv_type, pkt_type_ptr + if_c wrlong rcv_length, pkt_length_ptr + if_nc wrlong error_status, pkt_status_ptr + jmp #next_cmd + +' send a packet +do_txpacket rdlong xmt_type, pkt_type_ptr + rdlong xmt_ptr, pkt_buffer_ptr + rdlong xmt_length, pkt_length_ptr + call #txpacket + if_c wrlong ok_status, pkt_status_ptr + if_nc wrlong error_status, pkt_status_ptr + jmp #next_cmd + +ok_status long STATUS_OK +error_status long STATUS_ERROR + +' receive a packet +' input: +' rcv_ptr points to the receive buffer +' rcv_max is the maximum number of bytes to receive +' output: +' rcv_type is the packet type +' rcv_length is the length of the packet received +' C is set on return if the packet was received successfully +' C is clear on return if there was an error +rxpacket call #rxbyte + cmp rxdata, #SOH wz + if_nz jmp #rxpacket + call #rxbyte ' receive packet type + mov rcv_type, rxdata + mov rcv_chk, rxdata + call #rxbyte ' receive hi byte of packet length + mov rcv_length, rxdata + shl rcv_length, #8 + add rcv_chk, rxdata + call #rxbyte ' receive lo byte of packet length + or rcv_length, rxdata + add rcv_chk, rxdata + call #rxbyte ' receive header checksum + and rcv_chk, #$ff + cmp rxdata, rcv_chk wz + if_nz jmp #rxerror + cmp rcv_length, rcv_max wz, wc + if_a jmp #rxerror + mov crc, #0 + mov rcv_cnt, rcv_length wz + if_z jmp #:crc +:next call #rxbyte ' receive the next data byte + mov crcdata, rxdata + call #updcrc ' update the crc + wrbyte rxdata, rcv_ptr + add rcv_ptr, #1 + djnz rcv_cnt, #:next +:crc call #rxbyte + mov crcdata, rxdata + call #updcrc ' update the crc + call #rxbyte + mov crcdata, rxdata + call #updcrc ' update the crc + cmp crc, #0 wz ' check the crc + if_nz jmp #rxerror + test $, #1 wc ' set c to indicate success +rxpacket_ret ret + +rxerror test $, #0 wc ' clear c to indicate failure + jmp rxpacket_ret + +' transmit a packet +' input: +' xmt_type is the packet type +' xmt_ptr points to the packet data +' xmt_length is the number of bytes of data +' output: +' C is set on return if the packet was received successfully +' C is clear on return if there was an error +txpacket mov txdata, #SOH + call #txbyte + mov txdata, xmt_type + mov xmt_chk, txdata + call #txbyte + mov txdata, xmt_length + shr txdata, #8 + add xmt_chk, txdata + call #txbyte + mov txdata, xmt_length + and txdata, #$ff + add xmt_chk, txdata + call #txbyte + mov txdata, xmt_chk + and txdata, #$ff + call #txbyte + mov crc, #0 + mov xmt_cnt, xmt_length wz + if_z jmp #:crc +:next rdbyte txdata, xmt_ptr + add xmt_ptr, #1 + mov crcdata, txdata + call #updcrc + call #txbyte + djnz xmt_cnt, #:next +:crc mov crcdata, #0 + call #updcrc + call #updcrc + mov txdata, crc + shr txdata, #8 + call #txbyte + mov txdata, crc + and txdata, #$ff + call #txbyte + test $, #1 wc ' set c to indicate success +txpacket_ret ret + +' receive a byte +' output: +' rxdata is the byte received +rxbyte waitpne rxmask, rxmask ' wait for a start bit + mov rxcnt, bitticks ' wait until half way through the bit time + shr rxcnt, #1 + add rxcnt, bitticks + add rxcnt, cnt + mov rxbits, #9 ' receive 8 data bits and the stop bit +:next waitcnt rxcnt, bitticks ' wait until the center of the next bit + test rxmask, ina wc ' sample the rx pin + rcr rxdata, #1 ' add to the byte being received + djnz rxbits, #:next + shr rxdata, #32-9 ' shift the received data to the low bits + and rxdata, #$ff ' mask off the stop bit + waitpeq rxmask, rxmask ' wait for the end of the stop bit +rxbyte_ret ret + +' transmit a byte +' input: +' txdata is the byte to send (destroyed on return) +txbyte or txdata, #$100 ' or in a stop bit + shl txdata, #1 ' shift in a start bit + mov txcnt, cnt + add txcnt, bitticks + mov txbits, #10 +:next shr txdata, #1 wc + muxc outa, txmask + waitcnt txcnt, bitticks + djnz txbits, #:next + waitcnt txcnt, bitticks +txbyte_ret ret + +bitticks long 0 +rxmask long 0 +rxdata long 0 +rxbits long 0 +rxcnt long 0 +txmask long 0 +txdata long 0 +txbits long 0 +txcnt long 0 + +' update the crc +' input: +' crc the current crc +' crcdata the data to add to the crc +' output: +' crc the updated crc +updcrc mov t1, crc + test t1, #$100 wz + shr t1, #9 + add t1, #crctab + movs :load, t1 + shl crc, #8 +:load mov t1, 0-0 + if_nz shr t1, #16 + xor crc, t1 + xor crc, crcdata + and crc, word_mask +updcrc_ret ret + +crc long 0 +crcdata long 0 + +' +' +' Initialized data +' +' +zero long 0 +word_mask long $ffff + +crctab + word $0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7 + word $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef + word $1231, $0210, $3273, $2252, $52b5, $4294, $72f7, $62d6 + word $9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de + word $2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485 + word $a56a, $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d + word $3653, $2672, $1611, $0630, $76d7, $66f6, $5695, $46b4 + word $b75b, $a77a, $9719, $8738, $f7df, $e7fe, $d79d, $c7bc + word $48c4, $58e5, $6886, $78a7, $0840, $1861, $2802, $3823 + word $c9cc, $d9ed, $e98e, $f9af, $8948, $9969, $a90a, $b92b + word $5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50, $3a33, $2a12 + word $dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b, $ab1a + word $6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41 + word $edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49 + word $7e97, $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70 + word $ff9f, $efbe, $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78 + word $9188, $81a9, $b1ca, $a1eb, $d10c, $c12d, $f14e, $e16f + word $1080, $00a1, $30c2, $20e3, $5004, $4025, $7046, $6067 + word $83b9, $9398, $a3fb, $b3da, $c33d, $d31c, $e37f, $f35e + word $02b1, $1290, $22f3, $32d2, $4235, $5214, $6277, $7256 + word $b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c, $c50d + word $34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405 + word $a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c + word $26d3, $36f2, $0691, $16b0, $6657, $7676, $4615, $5634 + word $d94c, $c96d, $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab + word $5844, $4865, $7806, $6827, $18c0, $08e1, $3882, $28a3 + word $cb7d, $db5c, $eb3f, $fb1e, $8bf9, $9bd8, $abbb, $bb9a + word $4a75, $5a54, $6a37, $7a16, $0af1, $1ad0, $2ab3, $3a92 + word $fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b, $9de8, $8dc9 + word $7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0, $0cc1 + word $ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8 + word $6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0 + +' +' Uninitialized data +' +t1 res 1 +t2 res 1 + +xmt_type res 1 +xmt_length res 1 +xmt_chk res 1 +xmt_ptr res 1 +xmt_cnt res 1 + +rcv_type res 1 +rcv_length res 1 'packet length +rcv_chk res 1 'header checksum +rcv_max res 1 'maximum packet data length +rcv_ptr res 1 'data buffer pointer +rcv_cnt res 1 'data buffer count + +cmd_ptr res 1 +pkt_type_ptr res 1 +pkt_buffer_ptr res 1 +pkt_length_ptr res 1 +pkt_status_ptr res 1 + + fit 496 diff --git a/ploader.h b/ploader.h index 8ef1ff3..0c1cbbe 100644 --- a/ploader.h +++ b/ploader.h @@ -48,6 +48,9 @@ typedef struct { void (*msleep)(void *data, int msecs); void *serialData; + /* propeller version */ + int version; + /* load progress interface */ void (*progress)(void *data, int phase); void *progressData; diff --git a/port.c b/port.c new file mode 100644 index 0000000..3370748 --- /dev/null +++ b/port.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include "port.h" +#include "ploader.h" +#include "osint.h" + +/* CheckPort state structure */ +typedef struct { + PL_state *state; + int baud; + int verbose; + char *actualport; +} CheckPortInfo; + +void ShowPorts(PL_state *state, char *prefix); +int InitPort(PL_state *state, char *prefix, char *port, int baud, int verbose, char *actualport); + +static int ShowPort(const char *port, void *data); +static int CheckPort(const char *port, void *data); +static int OpenPort(PL_state *state, const char *port, int baud); +static void cb_reset(void *data); +static int cb_tx(void *data, uint8_t* buf, int n); +static int cb_rx_timeout(void *data, uint8_t* buf, int n, int timeout); +static void cb_msleep(void *data, int msecs); +static void cb_progress(void *data, int phase); + +void InitPortState(PL_state *state) +{ + PL_Init(state); + state->reset = cb_reset; + state->tx = cb_tx; + state->rx_timeout = cb_rx_timeout; + state->progress = cb_progress; + state->msleep = cb_msleep; +#ifdef RASPBERRY_PI +{ + char cmd[20] = "gpio,17,0"; + // use_reset_method uses strtok to parse the string so it can't be a constant + use_reset_method(cmd); +} +#endif +} + +void ShowPorts(PL_state *state, char *prefix) +{ + serial_find(prefix, ShowPort, state); +} + +int InitPort(PL_state *state, char *prefix, char *port, int baud, int verbose, char *actualport) +{ + int result; + + if (port) { + if (actualport) { + strncpy(actualport, port, PATH_MAX - 1); + actualport[PATH_MAX - 1] = '\0'; + } + result = OpenPort(state, port, baud); + } + else { + CheckPortInfo info; + info.state = state; + info.baud = baud; + info.verbose = verbose; + info.actualport = actualport; + if (serial_find(prefix, CheckPort, &info) == 0) + result = CHECK_PORT_OK; + else + result = CHECK_PORT_NO_PROPELLER; + } + + return result; +} + +static int ShowPort(const char *port, void *data) +{ + printf("%s\n", port); + return 1; +} + +static int CheckPort(const char *port, void *data) +{ + CheckPortInfo *info = (CheckPortInfo*)data; + int rc; + if (info->verbose) + printf("Trying %s \n", port); fflush(stdout); + if ((rc = OpenPort(info->state, port, info->baud)) != CHECK_PORT_OK) + return rc; + if (info->actualport) { + strncpy(info->actualport, port, PATH_MAX - 1); + info->actualport[PATH_MAX - 1] = '\0'; + } + return 0; +} + +static int OpenPort(PL_state *state, const char *port, int baud) +{ + /* open the port */ + if (serial_init(port, baud) == 0) + return CHECK_PORT_OPEN_FAILED; + + /* check for a propeller on this port */ + if (PL_HardwareFound(state, &state->version) != LOAD_STS_OK) { + serial_done(); + return CHECK_PORT_NO_PROPELLER; + } + + return CHECK_PORT_OK; +} + +static void cb_reset(void *data) +{ + hwreset(); +} + +static int cb_tx(void *data, uint8_t* buf, int n) +{ + return tx(buf, n); +} + +static int cb_rx_timeout(void *data, uint8_t* buf, int n, int timeout) +{ + return rx_timeout(buf, n, timeout); +} + +static void cb_msleep(void *data, int msecs) +{ + msleep(msecs); +} + +static void cb_progress(void *data, int phase) +{ + switch (phase) { + case LOAD_PHASE_HANDSHAKE: + break; + case LOAD_PHASE_RESPONSE: + break; + case LOAD_PHASE_VERSION: + break; + case LOAD_PHASE_HANDSHAKE_DONE: + break; + case LOAD_PHASE_PROGRAM: + printf("Loading hub memory ... "); + fflush(stdout); + break; + case LOAD_PHASE_EEPROM_WRITE: + printf("OK\nWriting EEPROM ... "); + fflush(stdout); + break; + case LOAD_PHASE_EEPROM_VERIFY: + printf("OK\nVerifying EEPROM ... "); + fflush(stdout); + break; + case LOAD_PHASE_DONE: + break; + default: + break; + } +} diff --git a/port.h b/port.h new file mode 100644 index 0000000..1966b04 --- /dev/null +++ b/port.h @@ -0,0 +1,18 @@ +#ifndef __PORT_H__ +#define __PORT_H__ + +#include "ploader.h" + +/* CheckPort result codes */ +enum { + CHECK_PORT_OK, + CHECK_PORT_OPEN_FAILED, + CHECK_PORT_NO_PROPELLER +}; + +/* prototypes */ +void InitPortState(PL_state *state); +void ShowPorts(PL_state *state, char *prefix); +int InitPort(PL_state *state, char *prefix, char *port, int baud, int verbose, char *actualport); + +#endif \ No newline at end of file