From 366330d3943ec4e066197a8d034d90caf8422a1d Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Sat, 6 Sep 2025 13:24:11 -0400 Subject: fw: handle "w" write eeprom command --- fw/eeprom.c | 2 +- fw/eeprom.h | 2 - fw/types.c | 8 +-- fw/types.h | 9 +++- fw/usb.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 159 insertions(+), 30 deletions(-) (limited to 'fw') diff --git a/fw/eeprom.c b/fw/eeprom.c index ce8aed7..686be40 100644 --- a/fw/eeprom.c +++ b/fw/eeprom.c @@ -90,7 +90,7 @@ eepromWrite(U16 addr, U8 *data, U8 size) { while (size--) { (void)spiTx(*data); data++; - incU16(&addr); + addU16(&addr, 1u); // Check if write crosses page boundary if (isPageStart(addr) && size) { diff --git a/fw/eeprom.h b/fw/eeprom.h index 07438a0..16d9d72 100644 --- a/fw/eeprom.h +++ b/fw/eeprom.h @@ -5,10 +5,8 @@ * * Usage: * - * #include * #include * #include "types.h" - * #include "spi.h" * #include "eeprom.h" */ diff --git a/fw/types.c b/fw/types.c index c18392e..a6c2411 100644 --- a/fw/types.c +++ b/fw/types.c @@ -5,9 +5,9 @@ #include "types.h" void -incU16(U16 *x) { - x->lo++; - if (x->lo == 0u) { - x->hi++; +addU16(U16 *a, U8 b) { + a->lo += b; + if (STATUSbits.C) { + a->hi++; } } diff --git a/fw/types.h b/fw/types.h index 22a651e..835491d 100644 --- a/fw/types.h +++ b/fw/types.h @@ -7,10 +7,15 @@ * #include "types.h" */ +typedef enum { + OK, + FAIL, +} Status; + typedef uint8_t U8; typedef struct { - U8 lo, hi; + U8 hi, lo; } U16; -void incU16(U16 *x); +void addU16(U16 *a, U8 b); diff --git a/fw/usb.c b/fw/usb.c index 0b03250..ae95de7 100644 --- a/fw/usb.c +++ b/fw/usb.c @@ -1,17 +1,23 @@ #include +#include #include #include -#include #include #include #include +#include "types.h" +#include "eeprom.h" + #include "usb.h" /***** Constants *****/ +// Safety counter +#define BAILOUT 100u + // Line coding // See struct USB_CDC_LINE_CODING enum { @@ -30,8 +36,8 @@ typedef struct State { // Input buffer typedef struct { - uint8_t data[CDC_DATA_OUT_EP_SIZE]; - uint8_t len, head; + U8 data[CDC_DATA_OUT_EP_SIZE]; + U8 len, head; } RxQueue; /***** Function Declarations *****/ @@ -44,27 +50,47 @@ static State *readEepromState(void); /***** Global Variables *****/ -static uint8_t txBuf[CDC_DATA_IN_EP_SIZE]; +static U8 txBuf[CDC_DATA_IN_EP_SIZE]; static RxQueue rxBuf = {.len = 0u, .head = 0u}; /***** Function Definitions *****/ -// Return the next Rx'd char, or '\0' if no data. -static char -getchar(void) { +// Rx a char from USB. +// Returns FAIL if no data. +static Status +getchar(char *c) { if (rxBuf.len <= 0u) { rxBuf.len = getsUSBUSART(rxBuf.data, sizeof(rxBuf.data)); rxBuf.head = 0u; } if (rxBuf.len > 0u) { + *c = rxBuf.data[rxBuf.head]; + rxBuf.head++; rxBuf.len--; - return rxBuf.data[rxBuf.head++]; + return OK; } else { - return '\0'; + return FAIL; } } +// Attempt to Rx the next char up to retries+1 times. +static Status +getcharBlock(char *c, U8 retries) { + Status status; + + do { + status = getchar(c); + if (status == OK) { + return OK; + } + + USBDeviceTasks(); + } while (--retries + 1u); + + return FAIL; +} + void usbTask(void) { static State state = {idleState}; @@ -86,25 +112,31 @@ usbTask(void) { CDCTxService(); } +static void +nack(void) { + putsUSBUSART("nack\n"); +} + // Read (the start of) a command from USB. static State * idleState(void) { static State state; - char opcode; + char opcode, junk; + Status status; state.next = idleState; // Read opcode - opcode = getchar(); - if (!opcode) { + status = getchar(&opcode); + if (status != OK) { // No data return &state; } // Skip space - if (!getchar()) { + if (getchar(&junk) != OK) { // Incomplete command - putsUSBUSART("nack\n"); + nack(); return &state; } @@ -115,7 +147,7 @@ idleState(void) { case 'r': state.next = readEepromState; break; default: // invalid command rxBuf.len = 0u; // discard input - putsUSBUSART("nack\n"); + nack(); break; } @@ -126,35 +158,129 @@ idleState(void) { static State * echoState(void) { static State state; - uint8_t i; + static U8 i = 0u; + Status status; state.next = echoState; - i = 0u; while (i < sizeof(txBuf)) { - txBuf[i] = getchar(); - if (txBuf[i++] == '\n') { + status = getchar((char *) &txBuf[i]); + if (status == OK && txBuf[i++] == '\n') { // End of command state.next = idleState; break; + } else if (status != OK) { + // Wait to receive more data and continue on next call + return &state; } } if (i > 0u) { putUSBUSART(txBuf, i); + i = 0u; } return &state; } +// Parse a 2-digit hex number and consume the space after it. +static Status +parseU8(U8 *n) { + U8 i; + char c; + Status status; + + *n = 0u; + for (i = 0u; i < 2u; i++) { + *n <<= 4u; + status = getcharBlock(&c, BAILOUT); + if (status != OK) { + return FAIL; + } + if (isdigit(c)) { + *n += c - '0'; + } else if (c >= 'A' && c <= 'F') { + *n += 10u + (c - 'A'); + } else if (c >= 'a' && c <= 'f') { + *n += 10u + (c - 'a'); + } else { + return FAIL; + } + } + + // Skip space + status = getcharBlock(&c, BAILOUT); + if (status != OK || !isspace(c)) { + return FAIL; + } + + return OK; +} + // Handle "w" write eeprom command. static State * writeEepromState(void) { static State state; - - // TODO + U16 addr; + U8 size; + U8 i; + char c; + Status status; state.next = idleState; + + // Read and + if (parseU8(&addr.hi) != OK) { + nack(); + return &state; + } + if (parseU8(&addr.lo) != OK) { + nack(); + return &state; + } + if (parseU8(&size) != OK) { + nack(); + return &state; + } + + eepromWriteEnable(); + + // Read into buffer + for (i = 0u; i < size; i++) { + // Reuse txBuf to save memory + + // Receive byte + status = getcharBlock(&c, BAILOUT); + if (status != OK) { + nack(); + eepromWriteDisable(); + return &state; + } + + // Check for overflow + if (i > 0u && (i%sizeof(txBuf)) == 0u) { + eepromWrite(addr, txBuf, sizeof(txBuf)); + addU16(&addr, sizeof(txBuf)); + } + + txBuf[i%sizeof(txBuf)] = c; + } + + // Flush buffer to eeprom + if (i > 0u) { + eepromWrite(addr, txBuf, i%sizeof(txBuf)); + } + + eepromWriteDisable(); + + // Consume '\n' + status = getcharBlock(&c, BAILOUT); + if (status != OK || c != '\n') { + nack(); + } + + putsUSBUSART("ok\n"); + return &state; } -- cgit v1.2.3