diff --git a/p1load.c b/p1load.c index b569d70..8cf1ac7 100644 --- a/p1load.c +++ b/p1load.c @@ -59,7 +59,37 @@ 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 void cb_progress(void *data, int phase, int current, int total) +{ + 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("\rLoading hub memory ... OK \nWriting EEPROM ... "); + fflush(stdout); + break; + case LOAD_PHASE_EEPROM_VERIFY: + printf("OK\nVerifying EEPROM ... "); + fflush(stdout); + break; + case LOAD_PHASE_DONE: + printf("OK\n"); + break; + default: + break; + } +} + static PL_state state; static int version; @@ -86,7 +116,11 @@ int main(int argc, char *argv[]) port = NULL; /* initialize the loader */ - PL_Init(&state, &serial, NULL); + 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) { @@ -210,8 +244,19 @@ int main(int argc, char *argv[]) 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"); + switch (PL_LoadSpinBinary(&state, loadType, image, imageSize)) { + case LOAD_STS_OK: + break; + case LOAD_STS_ERROR: + printf("Error\n"); + break; + case LOAD_STS_TIMEOUT: + printf("Timeout\n"); + break; + default: + printf("Internal error\n"); + break; + } } } @@ -347,7 +392,7 @@ static int OpenPort(const char* port, int baud) return CHECK_PORT_OPEN_FAILED; /* check for a propeller on this port */ - if (!PL_HardwareFound(&state, &version)) { + if (PL_HardwareFound(&state, &version) != LOAD_STS_OK) { serial_done(); return CHECK_PORT_NO_PROPELLER; } diff --git a/ploader.c b/ploader.c index a32c68e..6d3f6fe 100644 --- a/ploader.c +++ b/ploader.c @@ -1,4 +1,4 @@ -#include +#include #include "ploader.h" #ifndef TRUE @@ -6,10 +6,15 @@ #define FALSE 0 #endif +/* timeouts in milliseconds */ #define ACK_TIMEOUT 25 -#define CHECKSUM_RETRIES (2000 / ACK_TIMEOUT) -#define EEPROM_PROGRAMMING_RETRIES (5000 / ACK_TIMEOUT) -#define EEPROM_VERIFICATION_RETRIES (2000 / ACK_TIMEOUT) +#define CHECKSUM_TIMEOUT 10000 // big because it includes program loading +#define EEPROM_PROGRAMMING_TIMEOUT 5000 +#define EEPROM_VERIFICATION_TIMEOUT 2000 + +#define CHECKSUM_RETRIES (CHECKSUM_TIMEOUT / ACK_TIMEOUT) +#define EEPROM_PROGRAMMING_RETRIES (EEPROM_PROGRAMMING_TIMEOUT / ACK_TIMEOUT) +#define EEPROM_VERIFICATION_RETRIES (EEPROM_VERIFICATION_TIMEOUT / ACK_TIMEOUT) static int WaitForAck(PL_state *state, int retries); static void SerialInit(PL_state *state); @@ -19,10 +24,9 @@ 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) +void PL_Init(PL_state *state) { - state->serial = serial; - state->serialData = data; + memset(state, 0, sizeof(PL_state)); } /* PL_Shutdown - shutdown the loader */ @@ -37,55 +41,57 @@ int PL_LoadSpinBinary(PL_state *state, int loadType, uint8_t *image, int size) { int i, sts; - printf("Loading hub memory ... "); fflush(stdout); - TLong(state, loadType); TLong(state, size / sizeof(uint32_t)); /* download the spin binary */ for (i = 0; i < size; i += 4) { + + /* report load progress */ + if (state->progress && (i % 1024) == 0) + (*state->progress)(state->progressData, LOAD_PHASE_PROGRAM, i, size); + + /* transmit the next long */ uint32_t data = image[i] | (image[i + 1] << 8) | (image[i + 2] << 16) | (image[i + 3] << 24); TLong(state, data); } TComm(state); /* wait for an ACK indicating a successful load */ - if ((sts = WaitForAck(state, CHECKSUM_RETRIES)) <= 0) { - if (sts < 0) - printf("Timeout waiting for checksum\n"); - else - printf("Checksum error\n"); - return sts; - } - printf("OK\n"); + if ((sts = WaitForAck(state, CHECKSUM_RETRIES)) < 0) + return LOAD_STS_TIMEOUT; + else if (sts == 0) + return LOAD_STS_ERROR; /* wait for eeprom programming and verification */ if (loadType == LOAD_TYPE_EEPROM || loadType == LOAD_TYPE_EEPROM_RUN) { + /* report the start of the eeprom writing phase */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_EEPROM_WRITE, 0, size); + /* wait for an ACK indicating a successful EEPROM programming */ - printf("Writing EEPROM ... "); fflush(stdout); - if ((sts = WaitForAck(state, EEPROM_PROGRAMMING_RETRIES)) <= 0) { - if (sts < 0) - printf("Timeout\n"); - else - printf("Failed\n"); - return sts; - } - printf("OK\n"); + if ((sts = WaitForAck(state, EEPROM_PROGRAMMING_RETRIES)) < 0) + return LOAD_STS_TIMEOUT; + else if (sts == 0) + return LOAD_STS_ERROR; + /* report the start of the eeprom verification phase */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_EEPROM_VERIFY, 0, size); + /* wait for an ACK indicating a successful EEPROM verification */ - printf("Verifying EEPROM ... "); fflush(stdout); - if ((sts = WaitForAck(state, EEPROM_VERIFICATION_RETRIES)) <= 0) { - if (sts < 0) - printf("Timeout\n"); - else - printf("Failed\n"); - return sts; - } - printf("OK\n"); + if ((sts = WaitForAck(state, EEPROM_VERIFICATION_RETRIES)) < 0) + return LOAD_STS_TIMEOUT; + else if (sts == 0) + return LOAD_STS_ERROR; } - return 1; + /* report load completion */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_DONE, 0, size); + + return LOAD_STS_OK; } static int WaitForAck(PL_state *state, int retries) @@ -94,7 +100,7 @@ static int WaitForAck(PL_state *state, int retries) while (--retries >= 0) { TByte(state, 0xf9); TComm(state); - if ((*state->serial->rx_timeout)(state->serialData, buf, 1, ACK_TIMEOUT) > 0) + if ((*state->rx_timeout)(state->serialData, buf, 1, ACK_TIMEOUT) > 0) return buf[0] == 0xfe; } return -1; // timeout @@ -109,8 +115,12 @@ int PL_HardwareFound(PL_state *state, int *pVersion) /* initialize the serial buffers */ SerialInit(state); + /* report the start of the handshake phase */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_HANDSHAKE, 0, 0); + /* reset the propeller (includes post-reset delay of 100ms) */ - (*state->serial->reset)(state->serialData); + (*state->reset)(state->serialData); /* transmit the calibration pulses */ TByte(state, 0xf9); @@ -127,22 +137,38 @@ int PL_HardwareFound(PL_state *state, int *pVersion) /* flush the transmit buffer */ TComm(state); + /* report the start of the handshake response phase */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_RESPONSE, 0, 0); + /* receive the connection response */ - for (i = 0; i < 250; ++i) - if (RBit(state, 100) != IterateLFSR(state)) - return FALSE; + for (i = 0; i < 250; ++i) { + int bit = RBit(state, 100); + if (bit < 0) + return LOAD_STS_TIMEOUT; + else if (bit != IterateLFSR(state)) + return LOAD_STS_ERROR; + } + /* report the start of the version phase */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_VERSION, 0, 0); + /* receive the chip version */ for (version = i = 0; i < 8; ++i) { int bit = RBit(state, 50); if (bit < 0) - return FALSE; + return LOAD_STS_TIMEOUT; version = ((version >> 1) & 0x7f) | (bit << 7); } *pVersion = version; + /* report handshake completion */ + if (state->progress) + (*state->progress)(state->progressData, LOAD_PHASE_HANDSHAKE_DONE, 0, 0); + /* return successfully */ - return TRUE; + return LOAD_STS_OK; } /* SerialInit - initialize the serial buffers */ @@ -193,7 +219,7 @@ static void TLong(PL_state *state, uint32_t x) /* TComm - write the transmit buffer to the port */ static void TComm(PL_state *state) { - (*state->serial->tx)(state->serialData, state->txbuf, state->txcnt); + (*state->tx)(state->serialData, state->txbuf, state->txcnt); state->txcnt = 0; } @@ -203,7 +229,7 @@ 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); + state->rxcnt = (*state->rx_timeout)(state->serialData, state->rxbuf, sizeof(state->rxbuf), timeout); if (state->rxcnt <= 0) { /* hardware lost */ return -1; diff --git a/ploader.h b/ploader.h index df0735d..0086b4f 100644 --- a/ploader.h +++ b/ploader.h @@ -8,22 +8,38 @@ extern "C" #include -#define LOAD_TYPE_SHUTDOWN 0 -#define LOAD_TYPE_RUN 1 -#define LOAD_TYPE_EEPROM 2 -#define LOAD_TYPE_EEPROM_RUN 3 +#define LOAD_PHASE_HANDSHAKE 0 +#define LOAD_PHASE_RESPONSE 1 +#define LOAD_PHASE_VERSION 2 +#define LOAD_PHASE_HANDSHAKE_DONE 3 +#define LOAD_PHASE_PROGRAM 4 +#define LOAD_PHASE_EEPROM_WRITE 5 +#define LOAD_PHASE_EEPROM_VERIFY 6 +#define LOAD_PHASE_DONE 7 -/* 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; +#define LOAD_STS_OK 0 +#define LOAD_STS_ERROR -1 +#define LOAD_STS_TIMEOUT -2 + +#define LOAD_TYPE_SHUTDOWN 0 +#define LOAD_TYPE_RUN 1 +#define LOAD_TYPE_EEPROM 2 +#define LOAD_TYPE_EEPROM_RUN 3 /* loader state structure - filled in by the loader functions */ typedef struct { - PL_serial *serial; + + /* serial driver interface */ + 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); void *serialData; + + /* load progress interface */ + void (*progress)(void *data, int phase, int current, int total); + void *progressData; + + /* internal variables */ uint8_t txbuf[1024]; int txcnt; uint8_t rxbuf[1024]; @@ -33,10 +49,7 @@ typedef struct { } PL_state; /* PL_Init - Initializes the loader state structure. */ -void PL_Init(PL_state *state, PL_serial *serial, void *data); - -/* PL_Shutdown - Shutdown the loader.*/ -void PL_Shutdown(PL_state *state); +void PL_Init(PL_state *state); /* 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 @@ -49,6 +62,9 @@ int PL_HardwareFound(PL_state *state, int *pVersion); */ int PL_LoadSpinBinary(PL_state *state, int loadType, uint8_t *image, int size); +/* PL_Shutdown - Shutdown the loader.*/ +void PL_Shutdown(PL_state *state); + #ifdef __cplusplus } #endif