diff --git a/class/acm.c b/class/acm.c index 46a8b4e..9242278 100644 --- a/class/acm.c +++ b/class/acm.c @@ -9,12 +9,15 @@ #include "acm.h" #include +#include #include #include "../usb.h" #include "../usb_device_types.h" +#include "cmsis_os2.h" #include +#include // ------------------------- @@ -22,6 +25,42 @@ static Usb_AcmState acms = {0}; ///< ACM module state static uint8_t tx_buffer[USB_ACM_PCKT_BUFSIZE]; ///< Transmit buffer static uint8_t fifo_mem[USB_ACM_FIFO_MEM_SIZE]; ///< Memory assigned to the TX BFifo static BFifo fifo; ///< TX Blocking FIFO +static osThreadId_t th; ///< ACM thread +static osEventFlagsId_t flags; ///< Event flags + +#define USB_ACM_DATA_IN_DONE (0x01) ///< IN transfer done flag +#define USB_ACM_COMM_INIT (0x02) ///< Communication has been initialized +#define USB_ACM_HOSTBOUND_DATA_AVAIL (0x04) ///< Hostbound data is available + +#define USB_ACM_LOOP_TIMEOUT_TICKS (100) ///< Main loop timeout for interrupt status transmission + +// ------------------------- + +static void thread_usb_acm(void *arg) { + osEventFlagsWait(flags, USB_ACM_COMM_INIT, 0, osWaitForever); // wait for communication to become initialized + + osEventFlagsSet(flags, USB_ACM_DATA_IN_DONE); // assume we can write to the data endpoint + + while (true) { + uint32_t signals = osEventFlagsWait(flags, USB_ACM_HOSTBOUND_DATA_AVAIL, osFlagsWaitAny, USB_ACM_LOOP_TIMEOUT_TICKS); + + if (signals != osErrorTimeout) { // check timeout + if (signals & USB_ACM_HOSTBOUND_DATA_AVAIL) { // data hostbound available + do { + osEventFlagsWait(flags, USB_ACM_DATA_IN_DONE, osFlagsWaitAny, 1000); // wait for the IN DONE flag + uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_ACM_PCKT_BUFSIZE); // read from the fifo + if (readSize > 0) { + uint32_t writeSize = usbcore_schedule_transmission(acms.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer + bfifo_pop(&fifo, writeSize, 0); // pop with no blocking + } + } while (bfifo_get_used(&fifo) > 0); + } + } else { // timeout + // send an all-zero interrupt + usbcore_schedule_transmission(acms.ep_assignments.control_ep, (const uint8_t *)&(acms.interrupt_data), sizeof(uint16_t)); + } + } +} // ------------------------- @@ -42,11 +81,20 @@ void usb_acm_init(const Usb_Acm_EpAssignments *as) { // initialize an all-0 interrupt acms.interrupt_data = 0; - acms.interrupt_pending = true; // communication parameters have not been set acms.commInit = false; + // create flags + flags = osEventFlagsNew(NULL); + + // create thread + osThreadAttr_t attr; + memset(&attr, 0, sizeof(osThreadAttr_t)); + attr.stack_size = 1024; + attr.name = "acm"; + th = osThreadNew(thread_usb_acm, NULL, &attr); + // from now on CDC module is considered initialized acms.moduleInit = true; } @@ -61,6 +109,9 @@ static void usb_cdc_review_comm_init() { // combine the above criteria acms.commInit = lcOk && clsOk; + + // signal the processing thread + osEventFlagsSet(flags, USB_ACM_COMM_INIT); } int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) { @@ -108,24 +159,11 @@ int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) { } case USB_CBEVT_IN: { - if (cbevt->ep == acms.ep_assignments.control_ep) { // if notification feeding is requested - if (acms.interrupt_pending) { - usbcore_schedule_transmission(acms.ep_assignments.control_ep, (const uint8_t *)&(acms.interrupt_data), sizeof(uint16_t)); // send ZLP - acms.interrupt_pending = false; - } - ret = 0; - } else if (cbevt->ep == acms.ep_assignments.data_ep) { // if data are requested - ret = 0; - - // read from the fifo - if (acms.commInit) { - uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_ACM_PCKT_BUFSIZE); - if (readSize > 0) { - uint32_t writeSize = usbcore_schedule_transmission(acms.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer - bfifo_pop(&fifo, writeSize, 0); // pop with no blocking - } - } + if (cbevt->ep == acms.ep_assignments.data_ep) { + osEventFlagsSet(flags, USB_ACM_DATA_IN_DONE); } + ret = 0; + break; } default: @@ -138,16 +176,15 @@ int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) { void usb_acm_write(const uint8_t *data, uint32_t size) { if (acms.moduleInit) { bfifo_push_all(&fifo, data, size); - usbcore_wake_up_endpoint(acms.ep_assignments.data_ep, USB_IN); + osEventFlagsSet(flags, USB_ACM_HOSTBOUND_DATA_AVAIL); } } - /** * @fn void usb_acm_read_callback(const uint8_t *data, uint32_t size) * Callback function prototype for data reception. This function is * expected to be overridden by the application. - * + * * @param data ingress data * @param size length of the data */ diff --git a/class/acm.h b/class/acm.h index cbbdb6c..36f9b49 100644 --- a/class/acm.h +++ b/class/acm.h @@ -82,7 +82,6 @@ typedef struct { Usb_Acm_LineCodingStruct line_coding; ///< Line Coding Usb_Acm_ControlLineStateStruct control_line_state; ///< Control Line State uint16_t interrupt_data; ///< Data sent though the next transfer on the notification element - bool interrupt_pending; ///< Interrupt data is valid and should be send in the next cycle bool moduleInit; ///< CDC module is initialized bool commInit; ///< Communication protocol is initialized } Usb_AcmState;