136 lines
4.5 KiB
C

#include "cdc.h"
#include <memory.h>
#include "../usb_device_types.h"
#include "../usb.h"
#include <blocking_io/blocking_fifo.h>
#include <cmsis_gcc.h>
// state
static USB_CdcState cdcs = { 0 };
static uint8_t tx_buffer[USB_CDC_PCKT_BUFSIZE];
#define USB_CDC_FIFO_MEM_SIZE (3072) // FIXME: ez vagy a blocking FIFO bugos
static uint8_t fifo_mem[USB_CDC_FIFO_MEM_SIZE];
static BFifo fifo;
void usb_cdc_read_callback(const uint8_t * data, uint32_t size);
void usb_cdc_init(const USB_CdcAssignments *as) {
// clear the structure
memset(&cdcs, 0, sizeof(USB_CdcState));
// fill-in default values
USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding;
lc->dwDTERate = USB_CDC_DEFAULT_BITRATE;
lc->bCharFormat = USB_CDC_DEFAULT_CHAR_FORMAT;
lc->bParityType = USB_CDC_DEFAULT_PARITY_TYPE;
lc->bDataBits = USB_CDC_DEFAULT_DATA_BITS;
// fill-in assigments
cdcs.ep_assignments = *as;
// initialize buffer
bfifo_create(&fifo, fifo_mem, USB_CDC_FIFO_MEM_SIZE);
// from now on CDC is considered initialized
cdcs.initialized = true;
}
//static uint8_t replyBuf[sizeof(USB_Cdc_LineCodingStruct)];
int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) {
int ret = -1;
switch (cbevt->type) {
case USB_CBEVT_UNKNOWN_REQ: {
switch (cbevt->setup_request->bRequest) {
case USB_CDC_SET_LINE_CODING: // set line coding
memcpy(&cdcs.line_coding, cbevt->data, sizeof(USB_Cdc_LineCodingStruct));
//MSG("%u\n", cdcs.line_coding.dwDTERate);
ret = 0;
break;
case USB_CDC_GET_LINE_CODING: // get line coding
cbevt->reply_data = (const uint8_t *) &cdcs.line_coding; // expert move: pass the pointer, no copying
cbevt->reply_size = sizeof(USB_Cdc_LineCodingStruct);
cbevt->reply_valid = true; // the reply has been set to something valid
ret = 0;
break;
case USB_CDC_SEND_BREAK: // send break
// do nothing
ret = 0;
break;
case USB_CDC_SET_CONTROL_LINE_STATE: // set control line state
memcpy(&cdcs.control_line_state, cbevt->data, sizeof(USB_Cdc_ControlLineStateStruct));
//MSG("%u\n", cdcs.control_line_state.D);
ret = 0;
break;
default:
break;
}
// send a ZLP reply
if (ret != -1) {
cbevt->reply_data = NULL;
cbevt->reply_size = 0;
cbevt->reply_valid = true;
}
break;
}
case USB_CBEVT_OUT: {
if (cbevt->ep == cdcs.ep_assignments.data_ep) {
//MSG("%c\n", cbevt->data[0]);
ret = 0;
usb_cdc_read_callback(cbevt->data, cbevt->size);
//usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, cbevt->data, cbevt->size); // echo
}
break;
}
case USB_CBEVT_IN: {
if (cbevt->ep == cdcs.ep_assignments.control_ep) { // if notification feeding is requested
usbcore_schedule_transmission(cdcs.ep_assignments.control_ep, NULL, 0); // send ZLP
ret = 0;
} else if (cbevt->ep == cdcs.ep_assignments.data_ep) { // if data are requested
//usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, NULL, 0); // send ZLP
ret = 0;
// read from the fifo
uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE);
if (readSize > 0) {
uint32_t writeSize = usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
bfifo_pop(&fifo, writeSize, 0); // pop with no blocking
}
}
}
default:
break;
}
return ret;
}
// void usb_event_callback(USB_CallbackEvent *cbevt) {
// usb_cdc_process_and_return(cbevt);
// }
void usb_cdc_write(const uint8_t * data, uint32_t size) {
if (cdcs.initialized) {
bfifo_push_all(&fifo, data, size);
usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN);
}
}
__attribute__((weak)) void usb_cdc_read_callback(const uint8_t * data, uint32_t size) {
(void) data;
(void) size;
return;
}