2015-01-24 23:34:20 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
2015-01-25 21:31:09 -05:00
|
|
|
#include <ctype.h>
|
2015-01-24 23:34:20 -05:00
|
|
|
#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)
|
2015-01-27 19:55:31 -05:00
|
|
|
#ifdef RASPBERRY_PI
|
|
|
|
#define PORT_PREFIX "ttyAMA"
|
|
|
|
#else
|
|
|
|
#define PORT_PREFIX "ttyUSB"
|
|
|
|
#endif
|
2015-01-24 23:34:20 -05:00
|
|
|
#elif defined(MACOSX)
|
2015-01-27 20:03:46 -05:00
|
|
|
#define PORT_PREFIX "cu.usbserial-"
|
2015-01-24 23:34:20 -05:00
|
|
|
#else
|
|
|
|
#define PORT_PREFIX ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* defaults */
|
2015-02-12 06:47:05 -05:00
|
|
|
#define BAUD_RATE 115200
|
|
|
|
|
|
|
|
/* constants */
|
|
|
|
#define HUB_MEMORY_SIZE 32768
|
2015-01-24 23:34:20 -05:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
};
|
|
|
|
|
2015-02-01 12:37:55 -05:00
|
|
|
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);
|
|
|
|
}
|
2015-01-24 23:34:20 -05:00
|
|
|
|
2015-02-10 16:55:23 -05:00
|
|
|
static void cb_msleep(void *data, int msecs)
|
|
|
|
{
|
|
|
|
msleep(msecs);
|
|
|
|
}
|
|
|
|
|
2015-02-09 20:34:05 -05:00
|
|
|
static void cb_progress(void *data, int phase)
|
2015-02-08 08:21:46 -05:00
|
|
|
{
|
|
|
|
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:
|
2015-02-09 20:34:05 -05:00
|
|
|
printf("Loading hub memory ... ");
|
2015-02-08 08:21:46 -05:00
|
|
|
fflush(stdout);
|
|
|
|
break;
|
|
|
|
case LOAD_PHASE_EEPROM_WRITE:
|
2015-02-09 20:34:05 -05:00
|
|
|
printf("OK\nWriting EEPROM ... ");
|
2015-02-08 08:21:46 -05:00
|
|
|
fflush(stdout);
|
|
|
|
break;
|
|
|
|
case LOAD_PHASE_EEPROM_VERIFY:
|
|
|
|
printf("OK\nVerifying EEPROM ... ");
|
|
|
|
fflush(stdout);
|
|
|
|
break;
|
|
|
|
case LOAD_PHASE_DONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 23:34:20 -05:00
|
|
|
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[])
|
|
|
|
{
|
2015-01-27 17:41:41 -05:00
|
|
|
char actualPort[PATH_MAX], *var, *val, *port, *p;
|
2015-01-24 23:34:20 -05:00
|
|
|
int baudRate, baudRate2, verbose, terminalMode, pstMode, i;
|
2015-02-12 06:47:05 -05:00
|
|
|
int loadType = LOAD_TYPE_SHUTDOWN;
|
2015-01-24 23:34:20 -05:00
|
|
|
char *file = NULL;
|
|
|
|
long imageSize;
|
|
|
|
uint8_t *image;
|
|
|
|
|
|
|
|
/* initialize */
|
|
|
|
baudRate = baudRate2 = BAUD_RATE;
|
|
|
|
verbose = terminalMode = pstMode = FALSE;
|
|
|
|
port = NULL;
|
|
|
|
|
|
|
|
/* initialize the loader */
|
2015-02-08 08:21:46 -05:00
|
|
|
PL_Init(&state);
|
|
|
|
state.reset = cb_reset;
|
|
|
|
state.tx = cb_tx;
|
|
|
|
state.rx_timeout = cb_rx_timeout;
|
|
|
|
state.progress = cb_progress;
|
2015-02-10 16:55:23 -05:00
|
|
|
state.msleep = cb_msleep;
|
2015-02-08 20:35:58 -05:00
|
|
|
#ifdef RASPBERRY_PI
|
2015-02-08 20:39:53 -05:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2015-02-08 20:35:58 -05:00
|
|
|
#endif
|
2015-01-24 23:34:20 -05:00
|
|
|
|
|
|
|
/* 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;
|
2015-01-27 17:41:41 -05:00
|
|
|
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;
|
2015-01-24 23:34:20 -05:00
|
|
|
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];
|
2015-01-27 20:06:05 -05:00
|
|
|
sprintf(buf, "/dev/%s%d", PORT_PREFIX, atoi(port));
|
2015-01-24 23:34:20 -05:00
|
|
|
port = buf;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(MACOSX)
|
|
|
|
if (port[0] != '/') {
|
|
|
|
static char buf[64];
|
2015-01-27 20:06:05 -05:00
|
|
|
sprintf(buf, "/dev/%s-%s", PORT_PREFIX, port);
|
2015-01-24 23:34:20 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-02-12 06:47:05 -05:00
|
|
|
/* check for a file to load */
|
2015-01-24 23:34:20 -05:00
|
|
|
if (file) {
|
2015-02-12 06:47:05 -05:00
|
|
|
|
|
|
|
/* either -r, -e, or both must be given if a file is to be loaded */
|
|
|
|
if (loadType == LOAD_TYPE_SHUTDOWN) {
|
|
|
|
printf("error: must specify -r, -e, or both\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read the entire file into a buffer */
|
|
|
|
if (!(image = ReadEntireFile(file, &imageSize))) {
|
|
|
|
printf("error: reading '%s'\n", file);
|
|
|
|
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", file, imageSize);
|
|
|
|
switch (PL_LoadSpinBinary(&state, loadType, 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;
|
2015-01-24 23:34:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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("\
|
2015-02-08 15:30:47 -05:00
|
|
|
p1load - a simple loader for the propeller - %s, %s\n\
|
2015-01-24 23:34:20 -05:00
|
|
|
usage: p1load\n\
|
|
|
|
[ -b baud ] baud rate (default is %d)\n\
|
2015-01-27 17:41:41 -05:00
|
|
|
[ -D var=val ] set variable value\n\
|
2015-01-24 23:34:20 -05:00
|
|
|
[ -e ] write a bootable image to EEPROM\n\
|
2015-01-27 17:41:41 -05:00
|
|
|
[ -p port ] serial port (default is to auto-detect the port)\n\
|
2015-01-24 23:34:20 -05:00
|
|
|
[ -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\
|
2015-02-08 14:30:29 -05:00
|
|
|
file file to load\n", VERSION, __DATE__, BAUD_RATE);
|
2015-01-27 18:22:38 -05:00
|
|
|
#ifdef RASPBERRY_PI
|
|
|
|
printf("\
|
|
|
|
\n\
|
|
|
|
This version supports resetting the Propeller with a GPIO pin with option: -Dreset=gpio,pin,level\n\
|
2015-02-10 17:10:44 -05:00
|
|
|
where \"pin\" is the GPIO number to use and \"level\" is the logic level, 0 or 1. This defaults to\n\
|
|
|
|
GPIO 17 and level 0.\n\
|
2015-01-27 18:22:38 -05:00
|
|
|
");
|
|
|
|
#endif
|
2015-01-24 23:34:20 -05:00
|
|
|
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 */
|
2015-02-08 08:21:46 -05:00
|
|
|
if (PL_HardwareFound(&state, &version) != LOAD_STS_OK) {
|
2015-01-24 23:34:20 -05:00
|
|
|
serial_done();
|
|
|
|
return CHECK_PORT_NO_PROPELLER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CHECK_PORT_OK;
|
|
|
|
}
|