#include #include #include #include #include #include #include #include "usb.h" /***** Constants *****/ // Line coding // See struct USB_CDC_LINE_CODING enum { DATA_RATE = 9600, // bps CHAR_FORMAT = NUM_STOP_BITS_1, PARITY_TYPE = PARITY_NONE, DATA_BITS = 8, }; /***** 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; // Input buffer typedef struct { uint8_t data[CDC_DATA_OUT_EP_SIZE]; uint8_t len, head; } RxQueue; /***** Function Declarations *****/ // States static State *idleState(void); static State *echoState(void); static State *writeEepromState(void); static State *readEepromState(void); /***** Global Variables *****/ static uint8_t 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) { if (rxBuf.len <= 0u) { rxBuf.len = getsUSBUSART(rxBuf.data, sizeof(rxBuf.data)); rxBuf.head = 0u; } if (rxBuf.len > 0u) { rxBuf.len--; return rxBuf.data[rxBuf.head++]; } else { return '\0'; } } 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. static State * idleState(void) { static State state; char opcode; state.next = idleState; // Read opcode opcode = getchar(); if (!opcode) { // No data return &state; } // Skip space if (!getchar()) { // Incomplete command putsUSBUSART("nack\n"); return &state; } // State transition switch (opcode) { case 'e': state.next = echoState; break; case 'w': state.next = writeEepromState; break; case 'r': state.next = readEepromState; break; default: // invalid command rxBuf.len = 0u; // discard input putsUSBUSART("nack\n"); break; } return &state; } // Handle "e" echo command. static State * echoState(void) { static State state; uint8_t i; state.next = echoState; i = 0u; while (i < sizeof(txBuf)) { txBuf[i] = getchar(); if (txBuf[i++] == '\n') { // End of command state.next = idleState; break; } } if (i > 0u) { putUSBUSART(txBuf, i); } return &state; } // Handle "w" write eeprom command. static State * writeEepromState(void) { static State state; // TODO state.next = idleState; return &state; } // Handle "r" read eeprom command. static State * readEepromState(void) { static State state; // TODO state.next = idleState; return &state; } static void configure(void) { line_coding.dwDTERate = DATA_RATE; line_coding.bCharFormat = CHAR_FORMAT; line_coding.bParityType = PARITY_TYPE; line_coding.bDataBits = DATA_BITS; } bool USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, uint16_t size) { switch ((int)event) { case EVENT_TRANSFER: break; case EVENT_SOF: break; case EVENT_SUSPEND: break; case EVENT_RESUME: break; case EVENT_CONFIGURED: CDCInitEP(); configure(); break; case EVENT_SET_DESCRIPTOR: break; case EVENT_EP0_REQUEST: USBCheckCDCRequest(); break; case EVENT_BUS_ERROR: break; case EVENT_TRANSFER_TERMINATED: break; default: break; } return true; }