diff options
| -rw-r--r-- | fw/usb.c | 159 |
1 files changed, 82 insertions, 77 deletions
@@ -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 <args> 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 <opcode> <space> + 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 <opcode> <space> + 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 <args> 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 <opcode> <space> - return IDLE; - } - - opcode = readBuf[0u]; - - // skip <opcode> <space> - 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 |