Factored out the port handling code that interfaces to osint_xxx.c.

There is still some work to do to handle use_reset_method().
Started work on a program to read/write eeprom. Not working yet.
This commit is contained in:
David Betz 2015-02-19 22:00:12 -05:00
parent a3ae2034ba
commit 8582bbc752
9 changed files with 1122 additions and 173 deletions

View File

@ -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 $@

285
eeprom.c Normal file
View File

@ -0,0 +1,285 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#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;
}

187
p1load.c
View File

@ -4,6 +4,7 @@
#include <string.h>
#include <ctype.h>
#include <limits.h>
#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;
}

173
packet.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#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.
*/

32
packet.h Normal file
View File

@ -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 <stdint.h>
#define PKTMAXLEN 1024
int SendPacket(int type, uint8_t *buf, int len);
int ReceivePacket(int *pType, uint8_t *buf, int len);
#endif

409
packet_driver.spin Normal file
View File

@ -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

View File

@ -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;

160
port.c Normal file
View File

@ -0,0 +1,160 @@
#include <stdio.h>
#include <string.h>
#include <limits.h>
#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;
}
}

18
port.h Normal file
View File

@ -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