p1load/p1load.c

402 lines
11 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.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)
#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
/* 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_progress(void *data, int phase, int current)
{
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("\rLoading hub memory ... %d", current);
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[])
{
char actualPort[PATH_MAX], *var, *val, *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);
state.reset = cb_reset;
state.tx = cb_tx;
state.rx_timeout = cb_rx_timeout;
state.progress = cb_progress;
/* 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 '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/%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(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);
switch (PL_LoadSpinBinary(&state, loadType, image, imageSize)) {
case LOAD_STS_OK:
printf(" -- OK\n");
break;
case LOAD_STS_ERROR:
printf(" -- Error\n");
break;
case LOAD_STS_TIMEOUT:
printf(" -- Timeout\n");
break;
default:
printf(" -- Internal error\n");
break;
}
}
}
/* 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 - v%s, %s\n\
usage: p1load\n\
[ -b baud ] baud rate (default is %d)\n\
[ -D var=val ] set variable value\n\
[ -e ] write a bootable image to EEPROM\n\
[ -p port ] serial port (default is to auto-detect the port)\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 file to load\n", VERSION, __DATE__, BAUD_RATE);
#ifdef RASPBERRY_PI
printf("\
\n\
This version 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. \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;
}
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;
}