From ce7f1a7f7aa0dbdc8d4ae1536db8f9605b4e4702 Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Fri, 5 Sep 2025 17:55:43 -0400 Subject: rework usb state machine --- fw/usb.c | 159 ++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 82 insertions(+), 77 deletions(-) diff --git a/fw/usb.c b/fw/usb.c index a843945..bdf3b64 100644 --- a/fw/usb.c +++ b/fw/usb.c @@ -10,6 +10,8 @@ #include "usb.h" +/***** Constants *****/ + // Line coding // See struct USB_CDC_LINE_CODING enum { @@ -19,24 +21,84 @@ enum { DATA_BITS = 8, }; -// State -typedef enum { - IDLE, - ECHO, - WRITE_EEPROM, - READ_EEPROM, +/***** Types *****/ + +// A state is a function that executes the state's action and returns the next state. +typedef struct State { + struct State* (*next)(void); } State; +/***** Function Declarations *****/ + +// States +static State *idleState(void); +static State *echoState(void); +static State *writeEepromState(void); +static State *readEepromState(void); + +/***** Global Variables *****/ + static uint8_t readBuf[CDC_DATA_OUT_EP_SIZE]; static uint8_t writeBuf[CDC_DATA_IN_EP_SIZE]; static uint8_t readLen = 0u; +/***** Function Definitions *****/ + +void +usbTask(void) { + static State state = {idleState}; + + USBDeviceTasks(); + + if (USBGetDeviceState() < CONFIGURED_STATE) { + return; + } + if (USBIsDeviceSuspended()) { + return; + } + + if (USBUSARTIsTxTrfReady()) { + // Execute action and transition to next state + state = *state.next(); + } + + CDCTxService(); +} + +// Read (the start of) a command from USB. +// Leaves at the beginning of the read buffer. +static State * +idleState(void) { + static State state; + uint8_t opcode; + + readLen = getsUSBUSART(readBuf, sizeof(readBuf)); + if (readLen >= 2u) { + opcode = readBuf[0u]; + + // skip + memmove(readBuf, readBuf+2u, readLen-2u); + readLen -= 2u; + + switch (opcode) { + case 'e': state.next = echoState; break; + case 'w': state.next = writeEepromState; break; + case 'r': state.next = readEepromState; break; + default: state.next = idleState; break; // invalid command + } + } else { + // Invalid command. Must start with + state.next = idleState; + } + + return &state; +} + // Handle "e" echo command. -// Returns the next state. -static State -echo(void) { +static State * +echoState(void) { + static State state = {echoState}; uint8_t i; - State state = ECHO; if (readLen == 0u) { readLen = getsUSBUSART(readBuf, sizeof(readBuf)); @@ -46,7 +108,7 @@ echo(void) { writeBuf[i] = readBuf[i]; if (readBuf[i] == '\n') { // End of command - state = IDLE; + state.next = idleState; i++; break; } @@ -57,80 +119,23 @@ echo(void) { } readLen = 0u; - return state; + return &state; } // Handle "w" write eeprom command. -// Returns the next state. -static State -writeEeprom(void) { +static State * +writeEepromState(void) { + static State state = {idleState}; // TODO - return IDLE; + return &state; } // Handle "r" read eeprom command. -// Returns the next state. -static State -readEeprom(void) { +static State * +readEepromState(void) { + static State state = {idleState}; // TODO - return IDLE; -} - -static State -cmdState(uint8_t opcode) { - switch (opcode) { - case 'e': return ECHO; - case 'w': return WRITE_EEPROM; - case 'r': return READ_EEPROM; - default: return IDLE; // invalid command - } -} - -// Read (the start of) a command from USB. -// Leaves at the beginning of the read buffer. -// Returns the next state based on the opcode of the command. -static State -readCmd(void) { - uint8_t opcode; - - readLen = getsUSBUSART(readBuf, sizeof(readBuf)); - if (readLen < 2u) { - // Invalid command. Must start with - return IDLE; - } - - opcode = readBuf[0u]; - - // skip - memmove(readBuf, readBuf+2u, readLen-2u); - readLen -= 2u; - - return cmdState(opcode); -} - -void -usbTask(void) { - static State state = IDLE; - - USBDeviceTasks(); - - if (USBGetDeviceState() < CONFIGURED_STATE) { - return; - } - if (USBIsDeviceSuspended()) { - return; - } - - if (USBUSARTIsTxTrfReady()) { - switch (state) { - case IDLE: state = readCmd(); break; - case ECHO: state = echo(); break; - case WRITE_EEPROM: state = writeEeprom(); break; - case READ_EEPROM: state = readEeprom(); break; - } - } - - CDCTxService(); + return &state; } static void -- cgit v1.2.3