Initial commit.
This commit is contained in:
parent
1a1ccf4726
commit
7c4ed66e95
8
Makefile
Normal file
8
Makefile
Normal 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
55
osint.h
Normal 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
467
osint_linux.c
Normal 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
313
p1load.c
Normal 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
175
ploader.c
Normal 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
51
ploader.h
Normal 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
|
Loading…
Reference in New Issue
Block a user