Initial commit.

This commit is contained in:
David Betz 2015-01-24 23:34:20 -05:00
parent 1a1ccf4726
commit 7c4ed66e95
6 changed files with 1069 additions and 0 deletions

8
Makefile Normal file
View File

@ -0,0 +1,8 @@
p1load: p1load.c ploader.c osint_linux.c
cc -Wall -DMACOSX -o $@ p1load.c ploader.c osint_linux.c
run: p1load
./p1load blink.binary -r -t
clean:
rm -rf p1load

55
osint.h Normal file
View File

@ -0,0 +1,55 @@
/**
* @file osint.h
*
* Serial I/O functions used by PLoadLib.c
*
* Copyright (c) 2009 by John Steven Denson
* Modified in 2011 by David Michael Betz
*
* MIT License
*
* 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 __SERIAL_IO_H__
#define __SERIAL_IO_H__
#include <stdint.h>
/* serial i/o definitions */
#define SERIAL_TIMEOUT -1
/* serial i/o routines */
void serial_use_rts_for_reset(int use_rts);
int serial_find(const char* prefix, int (*check)(const char* port, void* data), void* data);
int serial_init(const char *port, unsigned long baud);
int serial_baud(unsigned long baud);
void serial_done(void);
int tx(uint8_t* buff, int n);
int rx(uint8_t* buff, int n);
int rx_timeout(uint8_t* buff, int n, int timeout);
void hwreset(void);
/* terminal mode */
void terminal_mode(int check_for_exit, int pst_mode);
/* miscellaneous functions */
void msleep(int ms);
#endif

467
osint_linux.c Normal file
View File

@ -0,0 +1,467 @@
/**
* @file osint_linux.c
*
* Serial I/O functions used by PLoadLib.c
*
* Copyright (c) 2009 by John Steven Denson
* Modified in 2011 by David Michael Betz
*
* MIT License
*
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/timeb.h>
#include <sys/select.h>
#include <sys/types.h>
#include <dirent.h>
#include <limits.h>
#include <signal.h>
#include "osint.h"
typedef int HANDLE;
static HANDLE hSerial = -1;
static struct termios old_sparm;
/* normally we use DTR for reset but setting this variable to non-zero will use RTS instead */
static int use_rts_for_reset = 0;
void serial_use_rts_for_reset(int use_rts)
{
use_rts_for_reset = use_rts;
}
static void chk(char *fun, int sts)
{
if (sts != 0)
printf("%s failed\n", fun);
}
int serial_find(const char* prefix, int (*check)(const char* port, void* data), void* data)
{
char path[PATH_MAX];
int prefixlen = strlen(prefix);
struct dirent *entry;
DIR *dirp;
if (!(dirp = opendir("/dev")))
return -1;
while ((entry = readdir(dirp)) != NULL) {
if (strncmp(entry->d_name, prefix, prefixlen) == 0) {
sprintf(path, "/dev/%s", entry->d_name);
if ((*check)(path, data) == 0) {
closedir(dirp);
return 0;
}
}
}
closedir(dirp);
return -1;
}
static void sigint_handler(int signum)
{
serial_done();
exit(1);
}
/**
* open serial port
* @param port - COMn port name
* @param baud - baud rate
* @returns 1 for success and 0 for failure
*/
int serial_init(const char* port, unsigned long baud)
{
struct termios sparm;
/* open the port */
#ifdef MACOSX
hSerial = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
#else
hSerial = open(port, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
#endif
if(hSerial == -1) {
//printf("error: opening '%s' -- %s\n", port, strerror(errno));
return 0;
}
signal(SIGINT, sigint_handler);
/* set the terminal to exclusive mode */
if (ioctl(hSerial, TIOCEXCL) != 0) {
//printf("error: can't open terminal for exclusive access\n");
close(hSerial);
return 0;
}
fcntl(hSerial, F_SETFL, 0);
/* set the baud rate */
if (!serial_baud(baud)) {
close(hSerial);
return 0;
}
/* get the current options */
chk("tcgetattr", tcgetattr(hSerial, &old_sparm));
sparm = old_sparm;
/* set raw input */
#ifdef MACOSX
cfmakeraw(&sparm);
sparm.c_cc[VTIME] = 0;
sparm.c_cc[VMIN] = 1;
#else
memset(&sparm, 0, sizeof(sparm));
sparm.c_cflag = CS8 | CLOCAL | CREAD;
sparm.c_lflag = 0; // &= ~(ICANON | ECHO | ECHOE | ISIG);
sparm.c_oflag = 0; // &= ~OPOST;
sparm.c_iflag = IGNPAR | IGNBRK;
sparm.c_cc[VTIME] = 0;
sparm.c_cc[VMIN] = 1;
#endif
/* set the options */
chk("tcflush", tcflush(hSerial, TCIFLUSH));
chk("tcsetattr", tcsetattr(hSerial, TCSANOW, &sparm));
return 1;
}
/**
* change the baud rate of the serial port
* @param baud - baud rate
* @returns 1 for success and 0 for failure
*/
int serial_baud(unsigned long baud)
{
struct termios sparm;
int tbaud = 0;
switch(baud) {
case 0: // default
tbaud = B115200;
break;
#ifdef B921600
case 921600:
tbaud = B921600;
break;
#endif
#ifdef B576000
case 576000:
tbaud = B576000;
break;
#endif
#ifdef B500000
case 500000:
tbaud = B500000;
break;
#endif
#ifdef B460800
case 460800:
tbaud = B460800;
break;
#endif
#ifdef B230400
case 230400:
tbaud = B230400;
break;
#endif
case 115200:
tbaud = B115200;
break;
case 57600:
tbaud = B57600;
break;
case 38400:
tbaud = B38400;
break;
case 19200:
tbaud = B19200;
break;
case 9600:
tbaud = B9600;
break;
default:
printf("Unsupported baudrate. Use ");
tbaud = baud; break;
#ifdef B921600
printf("921600, ");
#endif
#ifdef B576000
printf("576000, ");
#endif
#ifdef B500000
printf("500000, ");
#endif
#ifdef B460800
printf("460800, ");
#endif
#ifdef B230400
printf("230400, ");
#endif
printf("115200, 57600, 38400, 19200, or 9600\n");
serial_done();
exit(2);
break;
}
/* get the current options */
chk("tcgetattr", tcgetattr(hSerial, &sparm));
/* set raw input */
#ifdef MACOSX
chk("cfsetspeed", cfsetspeed(&sparm, tbaud));
#else
chk("cfsetispeed", cfsetispeed(&sparm, tbaud));
chk("cfsetospeed", cfsetospeed(&sparm, tbaud));
#endif
/* set the options */
chk("tcflush", tcflush(hSerial, TCIFLUSH));
chk("tcsetattr", tcsetattr(hSerial, TCSANOW, &sparm));
return 1;
}
/**
* close serial port
*/
void serial_done(void)
{
if (hSerial != -1) {
tcflush(hSerial, TCIOFLUSH);
tcsetattr(hSerial, TCSANOW, &old_sparm);
ioctl(hSerial, TIOCNXCL);
close(hSerial);
hSerial = -1;
}
}
/**
* receive a buffer
* @param buff - char pointer to buffer
* @param n - number of bytes in buffer to read
* @returns number of bytes read
*/
int rx(uint8_t* buff, int n)
{
ssize_t bytes = read(hSerial, buff, n);
if(bytes < 1) {
printf("Error reading port: %d\n", (int)bytes);
return 0;
}
return (int)bytes;
}
/**
* transmit a buffer
* @param buff - char pointer to buffer
* @param n - number of bytes in buffer to send
* @returns zero on failure
*/
int tx(uint8_t* buff, int n)
{
ssize_t bytes;
#if 0
int j = 0;
while(j < n) {
printf("%02x ",buff[j++]);
}
printf("tx %d byte(s)\n",n);
#endif
bytes = write(hSerial, buff, n);
if(bytes != n) {
printf("Error writing port\n");
return 0;
}
return (int)bytes;
}
/**
* receive a buffer with a timeout
* @param buff - char pointer to buffer
* @param n - number of bytes in buffer to read
* @param timeout - timeout in milliseconds
* @returns number of bytes read or SERIAL_TIMEOUT
*/
int rx_timeout(uint8_t* buff, int n, int timeout)
{
ssize_t bytes = 0;
struct timeval toval;
fd_set set;
FD_ZERO(&set);
FD_SET(hSerial, &set);
toval.tv_sec = timeout / 1000;
toval.tv_usec = (timeout % 1000) * 1000;
if (select(hSerial + 1, &set, NULL, NULL, &toval) > 0) {
if (FD_ISSET(hSerial, &set))
bytes = read(hSerial, buff, n);
}
return (int)(bytes > 0 ? bytes : SERIAL_TIMEOUT);
}
/**
* hwreset ... resets Propeller hardware using DTR or RTS
* @param sparm - pointer to DCB serial control struct
* @returns void
*/
void hwreset(void)
{
int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
msleep(10);
ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
msleep(90);
tcflush(hSerial, TCIFLUSH);
}
/**
* sleep for ms milliseconds
* @param ms - time to wait in milliseconds
*/
void msleep(int ms)
{
#if 0
volatile struct timeb t0, t1;
do {
ftime((struct timeb*)&t0);
do {
ftime((struct timeb*)&t1);
} while (t1.millitm == t0.millitm);
} while(ms-- > 0);
#else
usleep(ms * 1000);
#endif
}
#define ESC 0x1b /* escape from terminal mode */
/**
* simple terminal emulator
*/
void terminal_mode(int check_for_exit, int pst_mode)
{
struct termios oldt, newt;
char buf[128], realbuf[256]; // double in case buf is filled with \r in PST mode
ssize_t cnt;
fd_set set;
int exit_char = 0xdead; /* not a valid character */
int sawexit_char = 0;
int sawexit_valid = 0;
int exitcode = 0;
int continue_terminal = 1;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO | ISIG);
newt.c_iflag &= ~(ICRNL | INLCR);
newt.c_oflag &= ~OPOST;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
if (check_for_exit)
{
exit_char = 0xff;
}
#if 0
/* make it possible to detect breaks */
tcgetattr(hSerial, &newt);
newt.c_iflag &= ~IGNBRK;
newt.c_iflag |= PARMRK;
tcsetattr(hSerial, TCSANOW, &newt);
#endif
do {
FD_ZERO(&set);
FD_SET(hSerial, &set);
FD_SET(STDIN_FILENO, &set);
if (select(hSerial + 1, &set, NULL, NULL, NULL) > 0) {
if (FD_ISSET(hSerial, &set)) {
if ((cnt = read(hSerial, buf, sizeof(buf))) > 0) {
int i;
// check for breaks
ssize_t realbytes = 0;
for (i = 0; i < cnt; i++) {
if (sawexit_valid)
{
exitcode = buf[i];
continue_terminal = 0;
}
else if (sawexit_char) {
if (buf[i] == 0) {
sawexit_valid = 1;
} else {
realbuf[realbytes++] = exit_char;
realbuf[realbytes++] = buf[i];
sawexit_char = 0;
}
} else if (((int)buf[i] & 0xff) == exit_char) {
sawexit_char = 1;
} else {
realbuf[realbytes++] = buf[i];
if (pst_mode && buf[i] == '\r')
realbuf[realbytes++] = '\n';
}
}
write(fileno(stdout), realbuf, realbytes);
}
}
if (FD_ISSET(STDIN_FILENO, &set)) {
if ((cnt = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
int i;
for (i = 0; i < cnt; ++i) {
//printf("%02x\n", buf[i]);
if (buf[i] == ESC)
goto done;
}
write(hSerial, buf, cnt);
}
}
}
} while (continue_terminal);
done:
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
if (sawexit_valid)
{
exit(exitcode);
}
}

313
p1load.c Normal file
View File

@ -0,0 +1,313 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include "ploader.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)
#define PORT_PREFIX "ttyUSB"
#elif defined(MACOSX)
#define PORT_PREFIX "cu.usbserial"
#else
#define PORT_PREFIX ""
#endif
/* defaults */
#define BAUD_RATE 115200
/* 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 PL_serial serial = { cb_reset, cb_tx, cb_rx_timeout };
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[])
{
char actualPort[PATH_MAX], *port, *p;
int baudRate, baudRate2, verbose, terminalMode, pstMode, i;
char *file = NULL;
int loadType = 0;
long imageSize;
uint8_t *image;
/* initialize */
baudRate = baudRate2 = BAUD_RATE;
verbose = terminalMode = pstMode = FALSE;
port = NULL;
/* initialize the loader */
PL_Init(&state, &serial, NULL);
/* 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 'e':
loadType |= LOAD_TYPE_EEPROM;
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/ttyUSB%d", atoi(port));
port = buf;
#endif
}
#endif
#if defined(MACOSX)
if (port[0] != '/') {
static char buf[64];
sprintf(buf, "/dev/cu.usbserial-%s", port);
port = buf;
}
#endif
break;
case 'P':
ShowPorts(PORT_PREFIX);
break;
case 'r':
loadType |= LOAD_TYPE_RUN;
break;
case 'T':
pstMode = TRUE;
// fall through
case 't':
terminalMode = TRUE;
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(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) {
if ((image = ReadEntireFile(file, &imageSize)) != NULL) {
printf("Loading '%s' (%ld bytes)\n", file, imageSize);
if (PL_LoadSpinBinary(&state, loadType, image, imageSize) != 0)
printf("Load failed!\n");
}
}
/* enter terminal mode if requested */
if (terminalMode) {
printf("[ Entering terminal mode. Type ESC or Control-C to exit. ]\n");
fflush(stdout);
if (baudRate2 != baudRate)
serial_baud(baudRate2);
terminal_mode(FALSE, pstMode);
}
return 0;
}
/* Usage - display a usage message and exit */
static void Usage(void)
{
printf("\
p1load - a simple loader for the propeller - version 0.009, 2014-08-10\n\
usage: p1load\n\
[ -b baud ] baud rate (default is %d)\n\
[ -p port ] serial port (default is to auto-detect the port)\n\
[ -e ] write a bootable image to EEPROM\n\
[ -P ] list available serial ports\n\
[ -r ] run the program after loading\n\
[ -t ] enter terminal mode after running the program\n\
[ -T ] enter PST-compatible terminal mode\n\
[ -v ] verbose output\n\
[ -? ] display a usage message and exit\n\
file[,addr]... files to load\n", BAUD_RATE);
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;
}
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)) {
serial_done();
return CHECK_PORT_NO_PROPELLER;
}
return CHECK_PORT_OK;
}

175
ploader.c Normal file
View File

@ -0,0 +1,175 @@
#include <stdint.h>
#include "ploader.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define ACK_TIMEOUT 20
static void SerialInit(PL_state *state);
static void TByte(PL_state *state, uint8_t x);
static void TLong(PL_state *state, uint32_t x);
static void TComm(PL_state *state);
static int RBit(PL_state *state, int timeout);
static int IterateLFSR(PL_state *state);
void PL_Init(PL_state *state, PL_serial *serial, void *data)
{
state->serial = serial;
state->serialData = data;
}
/* PL_LoadSpinBinary - load a spin binary using the rom loader */
int PL_LoadSpinBinary(PL_state *state, int loadType, uint8_t *image, int size)
{
int retries = 100;
uint8_t buf[1];
int i;
TLong(state, loadType);
TLong(state, size / sizeof(uint32_t));
/* download the spin binary */
for (i = 0; i < size; i += 4) {
uint32_t data = image[i] | (image[i + 1] << 8) | (image[i + 2] << 16) | (image[i + 3] << 24);
TLong(state, data);
}
TComm(state);
usleep(1000);
/* wait for an ACK */
while (--retries >= 0) {
TByte(state, 0xf9);
TComm(state);
if ((*state->serial->rx_timeout)(state->serialData, buf, 1, ACK_TIMEOUT) <= 0)
continue;
if (buf[0] == 0xfe)
break;
}
return retries >= 0 ? 0 : -1;
}
/* this code is adapted from Chip Gracey's PNut IDE */
int PL_HardwareFound(PL_state *state, int *pVersion)
{
int version, i;
/* initialize the serial buffers */
SerialInit(state);
/* reset the propeller */
(*state->serial->reset)(state->serialData);
/* send the connect string + blanks for echoes */
TByte(state, 0xf9);
state->lfsr = 'P';
for (i = 0; i < 250; ++i)
TByte(state, IterateLFSR(state) | 0xfe);
for (i = 0; i < 250 + 8; ++i)
TByte(state, 0xf9);
TComm(state);
/* receive the connect string */
for (i = 0; i < 250; ++i)
if (RBit(state, 100) != IterateLFSR(state))
return FALSE;
/* receive the chip version */
for (version = i = 0; i < 8; ++i) {
int bit = RBit(state, 50);
if (bit < 0) {
return FALSE;
version = ((version >> 1) & 0x7f) | (bit << 7);
}
*pVersion = version;
/* return successfully */
return TRUE;
}
/* SerialInit - initialize the serial buffers */
static void SerialInit(PL_state *state)
{
state->txcnt = 0;
state->rxnext = 0;
state->rxcnt = 0;
}
/* TByte - add a byte to the transmit buffer */
static void TByte(PL_state *state, uint8_t x)
{
state->txbuf[state->txcnt++] = x;
if (state->txcnt >= sizeof(state->txbuf))
TComm(state);
}
/* TLong - add a long to the transmit buffer */
static void TLong(PL_state *state, uint32_t x)
{
int i;
for (i = 0; i < 11; ++i) {
#if 0
// p2 code
uint8_t byte = 0x92
| ((i == 10 ? -1 : 0) & 0x60)
| ((x >> 31) & 1)
| (((x >> 30) & 1) << 3)
| (((x >> 29) & 1) << 6);
TByte(state, byte);
x <<= 3;
#else
// p1 code
uint8_t byte = 0x92
| ((i == 10 ? -1 : 0) & 0x60)
| (x & 1)
| ((x & 2) << 2)
| ((x & 4) << 4);
TByte(state, byte);
x >>= 3;
#endif
}
}
/* TComm - write the transmit buffer to the port */
static void TComm(PL_state *state)
{
(*state->serial->tx)(state->serialData, state->txbuf, state->txcnt);
state->txcnt = 0;
}
/* RBit - receive a bit with a timeout */
static int RBit(PL_state *state, int timeout)
{
int result;
for (;;) {
if (state->rxnext >= state->rxcnt) {
state->rxcnt = (*state->serial->rx_timeout)(state->serialData, state->rxbuf, sizeof(state->rxbuf), timeout);
if (state->rxcnt <= 0) {
/* hardware lost */
return -1;
}
state->rxnext = 0;
}
result = state->rxbuf[state->rxnext++] - 0xfe;
if ((result & 0xfe) == 0)
return result;
/* checksum error */
}
}
/* IterateLFSR - get the next bit in the lfsr sequence */
static int IterateLFSR(PL_state *state)
{
uint8_t lfsr = state->lfsr;
int result = lfsr & 1;
state->lfsr = ((lfsr << 1) & 0xfe) | (((lfsr >> 7) ^ (lfsr >> 5) ^ (lfsr >> 4) ^ (lfsr >> 1)) & 1);
return result;
}
/* end of code adapted from Chip Gracey's PNut IDE */

51
ploader.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef __PLOADER_H__
#define __PLOADER_H__
#ifdef __cplusplus
extern "C"
{
#endif
#define LOAD_TYPE_SHUTDOWN 0
#define LOAD_TYPE_RUN 1
#define LOAD_TYPE_EEPROM 2
#define LOAD_TYPE_EEPROM_RUN 3
/* serial port interface - filled in by the user prior to calling PL_Init */
typedef struct {
void (*reset)(void *data);
int (*tx)(void *data, uint8_t* buf, int n);
int (*rx_timeout)(void *data, uint8_t* buf, int n, int timeout);
} PL_serial;
/* loader state structure - filled in by the loader functions */
typedef struct {
PL_serial *serial;
void *serialData;
uint8_t txbuf[1024];
int txcnt;
uint8_t rxbuf[1024];
int rxnext;
int rxcnt;
uint8_t lfsr;
} PL_state;
/* PL_Init - Initializes the loader state structure. */
void PL_Init(PL_state *state, PL_serial *serial, void *data);
/* PL_HardwareFound - Sends the handshake sequence and returns non-zero if a Propeller
chip is found on the serial interface and also sets the version parameter to the
chip version.
*/
int PL_HardwareFound(PL_state *state, int *pVersion);
/* PL_LoadSpinBinary - Loads a Spin binary image. Must be called immediatel following a
successful call to PL_HardwareFound.
*/
int PL_LoadSpinBinary(PL_state *state, int loadType, uint8_t *image, int size);
#ifdef __cplusplus
}
#endif
#endif