- USB FIFO filling while transmission is in progress is implemented (huh)
This commit is contained in:
parent
c05d59ddf5
commit
6406222be3
@ -89,23 +89,23 @@ int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) {
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
usb_cdc_read_callback(cbevt->data, cbevt->size);
|
usb_cdc_read_callback(cbevt->data, cbevt->size);
|
||||||
//usbcore_write(cdcs.ep_assignments.data_ep, cbevt->data, cbevt->size); // echo
|
//usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, cbevt->data, cbevt->size); // echo
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case USB_CBEVT_IN: {
|
case USB_CBEVT_IN: {
|
||||||
if (cbevt->ep == cdcs.ep_assignments.control_ep) { // if notification feeding is requested
|
if (cbevt->ep == cdcs.ep_assignments.control_ep) { // if notification feeding is requested
|
||||||
usbcore_write(cdcs.ep_assignments.control_ep, NULL, 0); // send ZLP
|
usbcore_schedule_transmission(cdcs.ep_assignments.control_ep, NULL, 0); // send ZLP
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (cbevt->ep == cdcs.ep_assignments.data_ep) { // if data are requested
|
} else if (cbevt->ep == cdcs.ep_assignments.data_ep) { // if data are requested
|
||||||
//usbcore_write(cdcs.ep_assignments.data_ep, NULL, 0); // send ZLP
|
//usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, NULL, 0); // send ZLP
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
// read from the fifo
|
// read from the fifo
|
||||||
uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE);
|
uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE);
|
||||||
if (readSize > 0) {
|
if (readSize > 0) {
|
||||||
uint32_t writeSize = usbcore_write(cdcs.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
|
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
|
bfifo_pop(&fifo, writeSize, 0); // pop with no blocking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ typedef struct {
|
|||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
#define USB_CDC_PCKT_BUFSIZE (72)
|
#define USB_CDC_PCKT_BUFSIZE (300)
|
||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
|
277
class/eem.c
277
class/eem.c
@ -4,8 +4,28 @@
|
|||||||
|
|
||||||
#include "../usb.h"
|
#include "../usb.h"
|
||||||
|
|
||||||
|
#include <etherlib/dynmem.h>
|
||||||
|
#include <etherlib/eth_interface.h>
|
||||||
|
|
||||||
|
#include <standard_output/standard_output.h>
|
||||||
|
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
static USB_EemState eems = {0};
|
static USB_EemState eems = {0};
|
||||||
|
|
||||||
|
static uint8_t netbBuf[USB_EEM_FIFO_SIZE]; // Network bound FIFO memory
|
||||||
|
static uint8_t hostbBuf[USB_EEM_FIFO_SIZE]; // Host bound FIFO memory
|
||||||
|
|
||||||
|
#define EEM_EVENT_QUEUE_LENGTH (16)
|
||||||
|
#define EEM_FRAME_QUEUE_LENGTH (24)
|
||||||
|
#define EEM_PCKT_SIZE (64)
|
||||||
|
#define EEM_TRANSFER_UNIT (128)
|
||||||
|
|
||||||
|
static uint8_t transferBuffer[EEM_TRANSFER_UNIT]; // transfer buffer
|
||||||
|
|
||||||
|
void usb_eem_thread(void *);
|
||||||
|
|
||||||
void usb_eem_init(uint8_t data_ep) {
|
void usb_eem_init(uint8_t data_ep) {
|
||||||
// clear the state
|
// clear the state
|
||||||
memset(&eems, 0, sizeof(USB_EemState));
|
memset(&eems, 0, sizeof(USB_EemState));
|
||||||
@ -13,21 +33,81 @@ void usb_eem_init(uint8_t data_ep) {
|
|||||||
// store data endpoint number
|
// store data endpoint number
|
||||||
eems.data_ep = data_ep;
|
eems.data_ep = data_ep;
|
||||||
|
|
||||||
|
// create event queue
|
||||||
|
eems.eventQueue = osMessageQueueNew(EEM_EVENT_QUEUE_LENGTH, sizeof(uint8_t), NULL);
|
||||||
|
|
||||||
|
// create network bound and host bound FIFOs
|
||||||
|
bfifo_create(&(eems.hostbFifo), netbBuf, USB_EEM_FIFO_SIZE);
|
||||||
|
bfifo_create(&(eems.netbFifo), hostbBuf, USB_EEM_FIFO_SIZE);
|
||||||
|
|
||||||
|
// create queue for hostbound frames
|
||||||
|
eems.hostbFrameQ = osMessageQueueNew(EEM_FRAME_QUEUE_LENGTH, sizeof(USB_EemFrame *), NULL);
|
||||||
|
|
||||||
|
// no transmission or reception is in progress
|
||||||
|
eems.hostbState = EEM_IDLE;
|
||||||
|
eems.netbState = EEM_IDLE;
|
||||||
|
|
||||||
|
// no EchoResponse is queued
|
||||||
|
eems.echoRespQueued = false;
|
||||||
|
|
||||||
|
// create thread
|
||||||
|
osThreadAttr_t attr;
|
||||||
|
bzero(&attr, sizeof(osThreadAttr_t));
|
||||||
|
attr.priority = osPriorityNormal;
|
||||||
|
attr.stack_size = 2048;
|
||||||
|
attr.name = "eem";
|
||||||
|
eems.th = osThreadNew(usb_eem_thread, NULL, &attr);
|
||||||
|
|
||||||
// EEM is operational
|
// EEM is operational
|
||||||
eems.initialized = true;
|
eems.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usb_eem_push_event(USB_EemEvent evt) {
|
||||||
|
osMessageQueuePut(eems.eventQueue, &evt, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_EemEvent usb_eem_pop_event() {
|
||||||
|
USB_EemEvent evt;
|
||||||
|
osMessageQueueGet(eems.eventQueue, &evt, 0, osWaitForever);
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
|
|
||||||
int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
|
int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
|
||||||
switch (cbevt->type) {
|
switch (cbevt->type) {
|
||||||
case USB_CBEVT_UNKNOWN_REQ:
|
case USB_CBEVT_UNKNOWN_REQ:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_CBEVT_OUT:
|
case USB_CBEVT_OUT:
|
||||||
|
if ((cbevt->ep == eems.data_ep)) { // verify endpoint
|
||||||
|
bfifo_push(&(eems.netbFifo), cbevt->data, cbevt->size); // store portion of netbound packet
|
||||||
|
usb_eem_push_event(EEM_EVT_NETBOUND_PCKT_RECEIVED); // push notification
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_CBEVT_IN:
|
case USB_CBEVT_IN:
|
||||||
if (cbevt->ep == eems.data_ep) { // verify endpoint number
|
if (cbevt->ep == eems.data_ep) { // verify endpoint number
|
||||||
usbcore_write(eems.data_ep, NULL, 0); // send ZLP
|
if ((eems.hostbFrame != NULL) && (eems.hostbFrameIndex < eems.hostbFrameLength)) { // if there's something in the FIFO
|
||||||
|
uint8_t *readPtr = ((uint8_t *)eems.hostbFrame) + eems.hostbFrameIndex; // calculate read pointer
|
||||||
|
uint16_t bytesLeft = eems.hostbFrameLength - eems.hostbFrameIndex; // calculate bytes left
|
||||||
|
uint32_t writeSize = usbcore_schedule_transmission(eems.data_ep, readPtr, bytesLeft); // attempt to schedule transmission
|
||||||
|
|
||||||
|
//bool enableZLP = (bytesLeft < EEM_TRANSFER_UNIT) && ((bytesLeft % EEM_PCKT_SIZE) == 0); // ZLP transmission should be enabled if this was the last write and transfer size is integer multiple of the USB packet size
|
||||||
|
//cbevt->enable_autozlp = enableZLP;
|
||||||
|
|
||||||
|
eems.hostbFrameIndex += writeSize; // advance frame index
|
||||||
|
//MSG("U: %u T: %u\n", writeSize, bytesLeft);
|
||||||
|
|
||||||
|
// if (eems.hostbFrameIndex >= eems.hostbFrameLength) {
|
||||||
|
// MSG("---\n");
|
||||||
|
// }
|
||||||
|
} else { // no data is waiting for transmission
|
||||||
|
usbcore_schedule_transmission(eems.data_ep, NULL, 0); // send ZLP
|
||||||
|
}
|
||||||
|
|
||||||
|
// if FIFO is empty or flushed, then send notification
|
||||||
|
if ((eems.hostbFrame == NULL) || (eems.hostbFrameIndex >= eems.hostbFrameLength)) {
|
||||||
|
usb_eem_push_event(EEM_EVT_HOSTBOUND_TRANSFER_DONE); // push notification
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -37,3 +117,196 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------
|
||||||
|
|
||||||
|
#define EEM_HEADER_SIZE (2) // EEM header size in bytes
|
||||||
|
#define EEM_HEADER_TYPE_DEFAULT (0) // default header type code
|
||||||
|
#define EEM_HEADER_TYPE_CMD (1) // CMD header type code
|
||||||
|
|
||||||
|
// TODO rename: swap GET and the next word
|
||||||
|
#define EEM_IS_CMD_PCKT(h) ((((h)[1] & 0x80) >> 7) == EEM_HEADER_TYPE_CMD) // checks if header signals a following command packet or not
|
||||||
|
#define EEM_GET_CMD(h) ((h[1] >> 3) & 0b111) // get the actual command code from the header
|
||||||
|
#define EEM_GET_CMD_PARAM(h) (((uint16_t)(h)[0]) + ((((uint16_t)(h)[1]) & 0b111) << 8)) // get command arguments from the header
|
||||||
|
|
||||||
|
#define EEM_GET_DEFAULT_CRC_PRESENT(h) (((h)[1] >> 6) & 0b1) // checks if CRC is present
|
||||||
|
#define EEM_GET_DEFAULT_FRAME_LENGTH(h) (((uint16_t)(h)[0]) + ((((uint16_t)(h)[1]) & 0x3F) << 8)) // get Ethernet frame length (14-bits)
|
||||||
|
|
||||||
|
#define EEM_BUILD_HEADER(type, crc_present, len) (((uint16_t)(((type) & 0b1) << 15)) | ((uint16_t)(((crc_present) & 0b1) << 14)) | ((len) & 0x3FFF))
|
||||||
|
#define EEM_HEADER_GET_LENGTH(h) (((h) & 0x3FFF))
|
||||||
|
|
||||||
|
void usb_eem_process_networkbound() {
|
||||||
|
// extract netbound FIFO pointer for easier handling
|
||||||
|
BFifo *bf = &(eems.netbFifo);
|
||||||
|
|
||||||
|
switch (eems.netbState) {
|
||||||
|
case EEM_IDLE: { /* IDLE state, can start a new operation */
|
||||||
|
// verify, that the packet is big enough to contain the header
|
||||||
|
if (bfifo_get_used(bf) < EEM_HEADER_SIZE) {
|
||||||
|
break; // if not, then break (either a single byte, or a ZLP was received)
|
||||||
|
}
|
||||||
|
|
||||||
|
// certainly, we can acquire the header at this point
|
||||||
|
|
||||||
|
// get header
|
||||||
|
uint8_t header[EEM_HEADER_SIZE];
|
||||||
|
bfifo_read(bf, header, EEM_HEADER_SIZE); // read
|
||||||
|
bfifo_pop(bf, 2, 0); // pop (with no timeout)
|
||||||
|
|
||||||
|
// check if this packet was a command packet
|
||||||
|
if (EEM_IS_CMD_PCKT(header)) {
|
||||||
|
// if it is was a command, then fetch its fields
|
||||||
|
uint8_t bmEEMCmd = EEM_GET_CMD(header);
|
||||||
|
uint16_t bmEEMCmdParam = EEM_GET_CMD_PARAM(header);
|
||||||
|
|
||||||
|
// process only Echo commands (only if no previous EchoResponse was queued)
|
||||||
|
if ((bmEEMCmd == EEM_ECHO) && (!eems.echoRespQueued)) {
|
||||||
|
// store payload length
|
||||||
|
eems.netbSizeLeft = bmEEMCmdParam; // payload comes in the 11-bit parameter
|
||||||
|
|
||||||
|
// signal, that we will respond at the end the Echo packet
|
||||||
|
eems.echoRespQueued = true;
|
||||||
|
|
||||||
|
// step into the 'transfer in progress' state
|
||||||
|
eems.netbState = EEM_TRANSFER_IN_PROGRESS;
|
||||||
|
|
||||||
|
MSG("ECHO!\n");
|
||||||
|
}
|
||||||
|
} else { // this is a regular packet
|
||||||
|
// store Ethernet frame length
|
||||||
|
eems.netbFrameSize = EEM_GET_DEFAULT_FRAME_LENGTH(header); // set the frame size
|
||||||
|
|
||||||
|
// process packet with non-zero length
|
||||||
|
if (eems.netbFrameSize != 0) {
|
||||||
|
eems.netbSizeLeft = eems.netbFrameSize; // the full frame is ahead
|
||||||
|
|
||||||
|
// step into the 'transfer in progress' state
|
||||||
|
eems.netbState = EEM_TRANSFER_IN_PROGRESS;
|
||||||
|
|
||||||
|
// MSG("DEFAULT! %u\n", eems.netbFrameSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case EEM_TRANSFER_IN_PROGRESS: { /* transfer is in progress, collect bytes */
|
||||||
|
if (bfifo_get_used(bf) >= eems.netbFrameSize) { // if the full packet is in the buffer, then read it!
|
||||||
|
// create raw packet if Ethernet interface is defined
|
||||||
|
if (eems.intf != NULL) {
|
||||||
|
RawPckt raw;
|
||||||
|
bzero(&raw, sizeof(RawPckt));
|
||||||
|
raw.size = eems.netbFrameSize; // set size
|
||||||
|
raw.payload = dynmem_alloc(raw.size); // allocate buffer
|
||||||
|
if (raw.payload != NULL) {
|
||||||
|
bfifo_read(bf, raw.payload, raw.size); // copy payload to raw packet
|
||||||
|
ethinf_transmit(eems.intf, &raw); // transmit packet
|
||||||
|
} else {
|
||||||
|
MSG("EEM -> ETH packet allocation failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop data from the packet
|
||||||
|
bfifo_pop(bf, eems.netbFrameSize, 0);
|
||||||
|
|
||||||
|
// MSG("PKT OK! %u\n", eems.netbFrameSize);
|
||||||
|
|
||||||
|
eems.netbState = EEM_IDLE;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_eem_process_hostbound() {
|
||||||
|
// see if there are some packets waiting for transmission
|
||||||
|
if (osMessageQueueGetCount(eems.hostbFrameQ) == 0) {
|
||||||
|
return; // no packets
|
||||||
|
}
|
||||||
|
|
||||||
|
/*// check that forward buffer is indeed empty
|
||||||
|
BFifo * bf = &eems.hostbFifo;
|
||||||
|
if (bfifo_get_used(bf) > 0) {
|
||||||
|
return; // we don't want to overwrite concatenate transfers
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// check if transmission is done indeed
|
||||||
|
if ((eems.hostbFrame != NULL) && (eems.hostbFrameIndex < eems.hostbFrameLength)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidate frame
|
||||||
|
USB_EemFrame * oldEemFrame = eems.hostbFrame;
|
||||||
|
eems.hostbFrame = NULL;
|
||||||
|
|
||||||
|
// release frame
|
||||||
|
dynmem_free(oldEemFrame);
|
||||||
|
|
||||||
|
// at this point, we can safely pop from the frame queue, popping will not block,
|
||||||
|
// and the forward queue is certainly empty
|
||||||
|
|
||||||
|
// get EEM frame pointer
|
||||||
|
USB_EemFrame *eemFrame;
|
||||||
|
osMessageQueueGet(eems.hostbFrameQ, &eemFrame, 0, osWaitForever);
|
||||||
|
|
||||||
|
// push frame into the transfer queue
|
||||||
|
/* uint32_t frameLength = EEM_HEADER_GET_LENGTH(eemFrame->header);
|
||||||
|
bfifo_push(bf, (const uint8_t *) eemFrame, frameLength + EEM_HEADER_SIZE); // push header and payload */
|
||||||
|
|
||||||
|
// setup frame length and reset read index
|
||||||
|
eems.hostbFrameLength = EEM_HEADER_GET_LENGTH(eemFrame->header) + EEM_HEADER_SIZE;
|
||||||
|
eems.hostbFrameIndex = 0;
|
||||||
|
|
||||||
|
// set the frame pointer
|
||||||
|
eems.hostbFrame = eemFrame;
|
||||||
|
|
||||||
|
// MSG("%u\n", frameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_eem_ethernet_intercept_cb(EthInterface *intf, const RawPckt *rawPckt) {
|
||||||
|
// check for free space in the hostbound frame queue
|
||||||
|
if (osMessageQueueGetSpace(eems.hostbFrameQ) == 0) {
|
||||||
|
MSG("Hostbound frame queue is full, frame dropped!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy packet
|
||||||
|
USB_EemFrame *eemFrame = dynmem_alloc(sizeof(USB_EemFrame) + rawPckt->size);
|
||||||
|
if (eemFrame == NULL) {
|
||||||
|
MSG("Allocation while intercepting traffic failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point, allocation was certainly succesful
|
||||||
|
|
||||||
|
// build header: CRC is calculated and present, size comes from the raw packet size
|
||||||
|
eemFrame->header = EEM_BUILD_HEADER(EEM_HEADER_TYPE_DEFAULT, 1, rawPckt->size);
|
||||||
|
|
||||||
|
// copy payload
|
||||||
|
memcpy(eemFrame->payload, rawPckt->payload, rawPckt->size);
|
||||||
|
|
||||||
|
// push onto hostbound queue
|
||||||
|
osMessageQueuePut(eems.hostbFrameQ, &eemFrame, 0, osWaitForever); // will not block, since we checked, that there is space in the queue
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_eem_set_intf(EthInterface *intf) {
|
||||||
|
eems.intf = intf; // store interface
|
||||||
|
ethinf_set_intercept_callback(intf, usb_eem_ethernet_intercept_cb); // set intercept callback
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_eem_thread(void *) {
|
||||||
|
for (;;) {
|
||||||
|
// pop event
|
||||||
|
USB_EemEvent evt = usb_eem_pop_event();
|
||||||
|
|
||||||
|
switch (evt) {
|
||||||
|
// process netbound packet
|
||||||
|
case EEM_EVT_NETBOUND_PCKT_RECEIVED:
|
||||||
|
usb_eem_process_networkbound();
|
||||||
|
break;
|
||||||
|
case EEM_EVT_HOSTBOUND_TRANSFER_DONE:
|
||||||
|
usb_eem_process_hostbound();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
class/eem.h
55
class/eem.h
@ -5,9 +5,58 @@
|
|||||||
|
|
||||||
#include "../usb_callback_event.h"
|
#include "../usb_callback_event.h"
|
||||||
|
|
||||||
|
#include <blocking_io/blocking_fifo.h>
|
||||||
|
|
||||||
|
#include <etherlib/etherlib.h>
|
||||||
|
|
||||||
|
#define USB_EEM_FIFO_SIZE (2048)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EEM_ECHO = 0, // Echo
|
||||||
|
EEM_ECHO_RESPONSE, // Echo response
|
||||||
|
EEM_SUSPEND_HINT, // Suspend hint
|
||||||
|
EEM_RESPONSE_HINT, // Response hint
|
||||||
|
EEM_RESPONSE_COMPLETE_HINT, // Response complete hint
|
||||||
|
EEM_TICKLE, // Tickle
|
||||||
|
} USB_EemCmd;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EEM_IDLE = 0, // IDLE state, a new transfer may be initiated
|
||||||
|
EEM_TRANSFER_IN_PROGRESS // transfer is in progress, new transfers have to wait
|
||||||
|
} USB_EemFsmState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EEM_EVT_NONE = 0, // no event
|
||||||
|
EEM_EVT_NETBOUND_PCKT_RECEIVED, // a USB packet has been received for a netbound Ethernet frame
|
||||||
|
// EEM_EVT_HOSTBOUND_FRAME_IN_QUEUE, // a new hostbound frame is in the queue
|
||||||
|
EEM_EVT_HOSTBOUND_TRANSFER_DONE, // the previous hostbound transfer has completed
|
||||||
|
} USB_EemEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ethernet frame prepended with EEM header
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uint16_t header; ///< EEM header (CRC present?, Frame Length)
|
||||||
|
uint8_t payload[]; ///< Actual payload
|
||||||
|
} USB_EemFrame;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EthInterface * intf; // interface for packet interception and injection
|
||||||
uint8_t data_ep; // bulk data in and out endpoint pair
|
uint8_t data_ep; // bulk data in and out endpoint pair
|
||||||
|
osMessageQueueId_t eventQueue; // event queue
|
||||||
|
BFifo hostbFifo; // Hostbound FIFO
|
||||||
|
BFifo netbFifo; // Network bound FIFO
|
||||||
|
USB_EemFsmState netbState; // state of host bound operations
|
||||||
|
uint16_t netbFrameSize; // size of network bound packet
|
||||||
|
uint16_t netbSizeLeft; // number of bytes expected from the host sending into current network bound packet
|
||||||
|
USB_EemFsmState hostbState; // state of network bound operations
|
||||||
|
osMessageQueueId_t hostbFrameQ; // queue for hostbound message pointers
|
||||||
|
USB_EemFrame * hostbFrame; // hostbound frame
|
||||||
|
uint16_t hostbFrameLength; // hostbound frame length
|
||||||
|
uint16_t hostbFrameIndex; // read index in hostbound frame
|
||||||
|
bool echoRespQueued; // indicates if an EchoResponse was queued
|
||||||
bool initialized; // EEM is initialized
|
bool initialized; // EEM is initialized
|
||||||
|
osThreadId_t th; // EEM thread
|
||||||
} USB_EemState;
|
} USB_EemState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,4 +72,10 @@ void usb_eem_init(uint8_t data_ep);
|
|||||||
*/
|
*/
|
||||||
int usb_eem_process_and_return(USB_CallbackEvent * cbevt);
|
int usb_eem_process_and_return(USB_CallbackEvent * cbevt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Ethernet interface.
|
||||||
|
* @param pointer to Ethernet interface
|
||||||
|
*/
|
||||||
|
void usb_eem_set_intf(EthInterface * intf);
|
||||||
|
|
||||||
#endif /* CLASS_EEM */
|
#endif /* CLASS_EEM */
|
||||||
|
@ -60,18 +60,41 @@
|
|||||||
"direction": "in",
|
"direction": "in",
|
||||||
"transfer_type": "bulk",
|
"transfer_type": "bulk",
|
||||||
"max_packet_size": 64,
|
"max_packet_size": 64,
|
||||||
"service_interval": 0
|
"service_interval": 20
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": 1,
|
"n": 1,
|
||||||
"direction": "out",
|
"direction": "out",
|
||||||
"transfer_type": "bulk",
|
"transfer_type": "bulk",
|
||||||
"max_packet_size": 64,
|
"max_packet_size": 64,
|
||||||
"service_interval": 0
|
"service_interval": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"class": "0x02",
|
||||||
|
"subclass": "0x0C",
|
||||||
|
"protocol_code": "0x07",
|
||||||
|
"additional_interfaces": [],
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"n": 3,
|
||||||
|
"direction": "in",
|
||||||
|
"transfer_type": "bulk",
|
||||||
|
"max_packet_size": 64,
|
||||||
|
"service_interval": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n": 3,
|
||||||
|
"direction": "out",
|
||||||
|
"transfer_type": "bulk",
|
||||||
|
"max_packet_size": 64,
|
||||||
|
"service_interval": 10
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
343
desc/usb_desc.c
343
desc/usb_desc.c
@ -1,189 +1,176 @@
|
|||||||
#include "usb_desc.h"
|
#include "usb_desc.h"
|
||||||
|
|
||||||
const USB_StrDesc_lang_id lang_id = {
|
const USB_DeviceDesc devDesc = { /* Device Descriptor */
|
||||||
/* String descriptor */
|
0x12, //bLength
|
||||||
0x4, // bLength
|
UD_Device, //bDescriptorType
|
||||||
UD_String, // bDescriptorType
|
0x200, //bcdUSB
|
||||||
0x409, // bString
|
0x2, //bDeviceClass
|
||||||
|
0x0, //bDeviceSubclass
|
||||||
|
0x0, //bDeviceProtocol
|
||||||
|
0x40, //bMaxPacketSize0
|
||||||
|
0x925, //idVendor
|
||||||
|
0x9050, //idProduct
|
||||||
|
0x100, //bcdDevice
|
||||||
|
0x1, //iManufacturer
|
||||||
|
0x2, //iProduct
|
||||||
|
0x3, //iSerialNumber
|
||||||
|
0x1, //bNumConfigurations
|
||||||
};
|
};
|
||||||
|
|
||||||
const USB_StrDesc_vendor_string vendor_string = {
|
const USB_DeviceQualifierDesc devQualDesc = { /* Device Qualifier descriptor */
|
||||||
/* String descriptor */
|
0x9, //bLength
|
||||||
0x10, // bLength
|
UD_DeviceQualifier, //bDescriptorType
|
||||||
UD_String, // bDescriptorType
|
0x200, //bcdUSB
|
||||||
{
|
0x2, //bDeviceClass
|
||||||
'E',
|
0x0, //bDeviceSubclass
|
||||||
'p',
|
0x0, //bDeviceProtocol
|
||||||
'a',
|
0x40, //bMaxPacketSize
|
||||||
'g',
|
0x1, //bNumConfigurations
|
||||||
'r',
|
|
||||||
'i',
|
|
||||||
's',
|
|
||||||
}, // bString
|
|
||||||
};
|
|
||||||
|
|
||||||
const USB_StrDesc_product_string product_string = {
|
|
||||||
/* String descriptor */
|
|
||||||
0x16, // bLength
|
|
||||||
UD_String, // bDescriptorType
|
|
||||||
{
|
|
||||||
'T',
|
|
||||||
'e',
|
|
||||||
's',
|
|
||||||
't',
|
|
||||||
'd',
|
|
||||||
'e',
|
|
||||||
'v',
|
|
||||||
'i',
|
|
||||||
'c',
|
|
||||||
'e',
|
|
||||||
}, // bString
|
|
||||||
};
|
|
||||||
|
|
||||||
const USB_StrDesc_serial_number serial_number = {
|
|
||||||
/* String descriptor */
|
|
||||||
0xa, // bLength
|
|
||||||
UD_String, // bDescriptorType
|
|
||||||
{
|
|
||||||
'1',
|
|
||||||
'5',
|
|
||||||
'5',
|
|
||||||
'2',
|
|
||||||
}, // bString
|
|
||||||
};
|
|
||||||
|
|
||||||
const StringDescs strDescs = {
|
|
||||||
(USB_StringDesc *)&lang_id, // lang_id
|
|
||||||
(USB_StringDesc *)&vendor_string, // vendor_string
|
|
||||||
(USB_StringDesc *)&product_string, // product_string
|
|
||||||
(USB_StringDesc *)&serial_number, // serial_number
|
|
||||||
};
|
|
||||||
|
|
||||||
const USB_DeviceDesc devDesc = {
|
|
||||||
/* Device Descriptor */
|
|
||||||
0x12, // bLength
|
|
||||||
UD_Device, // bDescriptorType
|
|
||||||
0x200, // bcdUSB
|
|
||||||
0x2, // bDeviceClass
|
|
||||||
0x0, // bDeviceSubclass
|
|
||||||
0x0, // bDeviceProtocol
|
|
||||||
0x40, // bMaxPacketSize0
|
|
||||||
0x925, // idVendor
|
|
||||||
0x9050, // idProduct
|
|
||||||
0x100, // bcdDevice
|
|
||||||
0x1, // iManufacturer
|
|
||||||
0x2, // iProduct
|
|
||||||
0x3, // iSerialNumber
|
|
||||||
0x1, // bNumConfigurations
|
|
||||||
};
|
|
||||||
|
|
||||||
const USB_DeviceQualifierDesc devQualDesc = {
|
|
||||||
/* Device Qualifier descriptor */
|
|
||||||
0x9, // bLength
|
|
||||||
UD_DeviceQualifier, // bDescriptorType
|
|
||||||
0x200, // bcdUSB
|
|
||||||
0x2, // bDeviceClass
|
|
||||||
0x0, // bDeviceSubclass
|
|
||||||
0x0, // bDeviceProtocol
|
|
||||||
0x40, // bMaxPacketSize
|
|
||||||
0x1, // bNumConfigurations
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const FullConfigurations0 fullConfDescs0 = {
|
const FullConfigurations0 fullConfDescs0 = {
|
||||||
{
|
{ /* Configuration descriptor */
|
||||||
/* Configuration descriptor */
|
0x9, //bLength
|
||||||
0x9, // bLength
|
UD_Configuration, //bDescriptorType
|
||||||
UD_Configuration, // bDescriptorType
|
sizeof(struct _FullConfigurations0), //wTotalLength
|
||||||
sizeof(struct _FullConfigurations0), // wTotalLength
|
0x3, //bNumInterfaces
|
||||||
0x2, // bNumInterfaces
|
0x1, //bConfigurationValue
|
||||||
0x1, // bConfigurationValue
|
0x0, //iConfiguration
|
||||||
0x0, // iConfiguration
|
USB_CONFIG_ATTR_USB1_1_FLAG, //bmAttributes
|
||||||
USB_CONFIG_ATTR_USB1_1_FLAG, // bmAttributes
|
0x32, //bMaxPower
|
||||||
0x32, // bMaxPower
|
}, //config
|
||||||
}, // config
|
{ /* Interface descriptor : 0 */
|
||||||
{
|
0x9, //bLength
|
||||||
/* Interface descriptor : 0 */
|
UD_Interface, //bDescriptorType
|
||||||
0x9, // bLength
|
0x0, //bInterfaceNumber
|
||||||
UD_Interface, // bDescriptorType
|
0x0, //bAlternateSetting
|
||||||
0x0, // bInterfaceNumber
|
0x1, //bNumEndpoints
|
||||||
0x0, // bAlternateSetting
|
0x2, //bInterfaceClass
|
||||||
0x1, // bNumEndpoints
|
0x2, //bInterfaceSubclass
|
||||||
0x2, // bInterfaceClass
|
0x1, //bInterfaceProtocol
|
||||||
0x2, // bInterfaceSubclass
|
0x0, //iInterface
|
||||||
0x1, // bInterfaceProtocol
|
}, //intf0
|
||||||
0x0, // iInterface
|
{ /* Header Functional descriptor */
|
||||||
}, // intf0
|
0x5, //bLength
|
||||||
{
|
0x24, //bDescriptorType
|
||||||
/* Header Functional descriptor */
|
0x0, //bDescriptorSubType
|
||||||
0x5, // bLength
|
0x110, //bcdCDC
|
||||||
0x24, // bDescriptorType
|
}, //intf0hfd
|
||||||
0x0, // bDescriptorSubType
|
{ /* Abstract Control Management Functional descriptor */
|
||||||
0x110, // bcdCDC
|
0x4, //bLength
|
||||||
}, // intf0hfd
|
0x24, //bDescriptorType
|
||||||
{
|
0x2, //bDescriptorSubType
|
||||||
/* Abstract Control Management Functional descriptor */
|
0x2, //bmCapabilities
|
||||||
0x4, // bLength
|
}, //intf0acmfd
|
||||||
0x24, // bDescriptorType
|
{ /* Union Functional descriptor */
|
||||||
0x2, // bDescriptorSubType
|
0x5, //bLength
|
||||||
0x2, // bmCapabilities
|
0x24, //bDescriptorType
|
||||||
}, // intf0acmfd
|
0x6, //bDescriptorSubType
|
||||||
{
|
0x0, //bMasterInterface
|
||||||
/* Abstract Control Management Functional descriptor */
|
0x1, //bSlaveInterface0
|
||||||
0x5, // bLength
|
}, //intf0ufd
|
||||||
0x24, // bDescriptorType
|
{ /* Call Management Functional descriptor */
|
||||||
0x6, // bDescriptorSubType
|
0x5, //bLength
|
||||||
0x0, // bMasterInterface
|
0x24, //bDescriptorType
|
||||||
0x1, // bSlaveInterface0
|
0x1, //bDescriptorSubType
|
||||||
}, // intf0ufd
|
0x0, //bmCapabilities
|
||||||
{
|
0x1, //dDataInterface
|
||||||
/* Call Management Functional descriptor */
|
}, //intf0cmfd
|
||||||
0x5, // bLength
|
{ /* Endpoint descriptor : 2 in */
|
||||||
0x24, // bDescriptorType
|
0x7, //bLength
|
||||||
0x1, // bDescriptorSubType
|
UD_Endpoint, //bDescriptorType
|
||||||
0x0, // bmCapabilities
|
(USB_IN << 7) | (2), //bEndpointAddress
|
||||||
0x1, // dDataInterface
|
UT_Interrupt, //bmAttributes
|
||||||
}, // intf0cmfd
|
0x40, //wMaxPacketSize
|
||||||
{
|
0x2, //bInterval
|
||||||
/* Endpoint descriptor : 2 in */
|
}, //ep2in
|
||||||
0x7, // bLength
|
{ /* Interface descriptor : 1 */
|
||||||
UD_Endpoint, // bDescriptorType
|
0x9, //bLength
|
||||||
(USB_IN << 7) | (2), // bEndpointAddress
|
UD_Interface, //bDescriptorType
|
||||||
UT_Interrupt, // bmAttributes
|
0x1, //bInterfaceNumber
|
||||||
0x40, // wMaxPacketSize
|
0x0, //bAlternateSetting
|
||||||
0x2, // bInterval
|
0x2, //bNumEndpoints
|
||||||
}, // ep2in
|
0xa, //bInterfaceClass
|
||||||
{
|
0x0, //bInterfaceSubclass
|
||||||
/* Interface descriptor : 1 */
|
0x0, //bInterfaceProtocol
|
||||||
0x9, // bLength
|
0x0, //iInterface
|
||||||
UD_Interface, // bDescriptorType
|
}, //intf1
|
||||||
0x1, // bInterfaceNumber
|
{ /* Endpoint descriptor : 1 in */
|
||||||
0x0, // bAlternateSetting
|
0x7, //bLength
|
||||||
0x2, // bNumEndpoints
|
UD_Endpoint, //bDescriptorType
|
||||||
0xa, // bInterfaceClass
|
(USB_IN << 7) | (1), //bEndpointAddress
|
||||||
0x0, // bInterfaceSubclass
|
UT_Bulk, //bmAttributes
|
||||||
0x0, // bInterfaceProtocol
|
0x40, //wMaxPacketSize
|
||||||
0x0, // iInterface
|
0x14, //bInterval
|
||||||
}, // intf1
|
}, //ep1in
|
||||||
{
|
{ /* Endpoint descriptor : 1 out */
|
||||||
/* Endpoint descriptor : 1 in */
|
0x7, //bLength
|
||||||
0x7, // bLength
|
UD_Endpoint, //bDescriptorType
|
||||||
UD_Endpoint, // bDescriptorType
|
(USB_OUT << 7) | (1), //bEndpointAddress
|
||||||
(USB_IN << 7) | (1), // bEndpointAddress
|
UT_Bulk, //bmAttributes
|
||||||
UT_Bulk, // bmAttributes
|
0x40, //wMaxPacketSize
|
||||||
0x40, // wMaxPacketSize
|
0x14, //bInterval
|
||||||
0x0, // bInterval
|
}, //ep1out
|
||||||
}, // ep1in
|
{ /* Interface descriptor : 2 */
|
||||||
{
|
0x9, //bLength
|
||||||
/* Endpoint descriptor : 1 out */
|
UD_Interface, //bDescriptorType
|
||||||
0x7, // bLength
|
0x2, //bInterfaceNumber
|
||||||
UD_Endpoint, // bDescriptorType
|
0x0, //bAlternateSetting
|
||||||
(USB_OUT << 7) | (1), // bEndpointAddress
|
0x2, //bNumEndpoints
|
||||||
UT_Bulk, // bmAttributes
|
0x2, //bInterfaceClass
|
||||||
0x40, // wMaxPacketSize
|
0xc, //bInterfaceSubclass
|
||||||
0x0, // bInterval
|
0x7, //bInterfaceProtocol
|
||||||
}, // ep1out
|
0x0, //iInterface
|
||||||
|
}, //intf2
|
||||||
|
{ /* Endpoint descriptor : 3 in */
|
||||||
|
0x7, //bLength
|
||||||
|
UD_Endpoint, //bDescriptorType
|
||||||
|
(USB_IN << 7) | (3), //bEndpointAddress
|
||||||
|
UT_Bulk, //bmAttributes
|
||||||
|
0x40, //wMaxPacketSize
|
||||||
|
0xa, //bInterval
|
||||||
|
}, //ep3in
|
||||||
|
{ /* Endpoint descriptor : 3 out */
|
||||||
|
0x7, //bLength
|
||||||
|
UD_Endpoint, //bDescriptorType
|
||||||
|
(USB_OUT << 7) | (3), //bEndpointAddress
|
||||||
|
UT_Bulk, //bmAttributes
|
||||||
|
0x40, //wMaxPacketSize
|
||||||
|
0xa, //bInterval
|
||||||
|
}, //ep3out
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConfDescs confDescs = {
|
const ConfDescs confDescs = {
|
||||||
(USB_ConfigurationDesc *)&fullConfDescs0, // fullConfDescs0
|
(USB_ConfigurationDesc *) & fullConfDescs0, //fullConfDescs0
|
||||||
|
};
|
||||||
|
|
||||||
|
const USB_StrDesc_lang_id lang_id = { /* String descriptor */
|
||||||
|
0x4, //bLength
|
||||||
|
UD_String, //bDescriptorType
|
||||||
|
0x409, //bString
|
||||||
|
};
|
||||||
|
|
||||||
|
const USB_StrDesc_vendor_string vendor_string = { /* String descriptor */
|
||||||
|
0x10, //bLength
|
||||||
|
UD_String, //bDescriptorType
|
||||||
|
{'E', 'p', 'a', 'g', 'r', 'i', 's',}, //bString
|
||||||
|
};
|
||||||
|
|
||||||
|
const USB_StrDesc_product_string product_string = { /* String descriptor */
|
||||||
|
0x16, //bLength
|
||||||
|
UD_String, //bDescriptorType
|
||||||
|
{'T', 'e', 's', 't', 'd', 'e', 'v', 'i', 'c', 'e',}, //bString
|
||||||
|
};
|
||||||
|
|
||||||
|
const USB_StrDesc_serial_number serial_number = { /* String descriptor */
|
||||||
|
0xa, //bLength
|
||||||
|
UD_String, //bDescriptorType
|
||||||
|
{'1', '5', '5', '2',}, //bString
|
||||||
|
};
|
||||||
|
|
||||||
|
const StringDescs strDescs = {
|
||||||
|
(USB_StringDesc *) & lang_id, //lang_id
|
||||||
|
(USB_StringDesc *) & vendor_string, //vendor_string
|
||||||
|
(USB_StringDesc *) & product_string, //product_string
|
||||||
|
(USB_StringDesc *) & serial_number, //serial_number
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef CORE_USB_DESC_USB_DESC
|
#ifndef _USB_DESC_H
|
||||||
#define CORE_USB_DESC_USB_DESC
|
#define _USB_DESC_H
|
||||||
|
|
||||||
#include "../usb_device_types.h"
|
#include "../usb_device_types.h"
|
||||||
|
|
||||||
@ -7,39 +7,6 @@
|
|||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
|
||||||
typedef struct _USB_StrDesc_lang_id {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint16_t bString;
|
|
||||||
} __attribute__((packed)) USB_StrDesc_lang_id;
|
|
||||||
|
|
||||||
extern const USB_StrDesc_lang_id lang_id; /* String descriptor */
|
|
||||||
typedef struct _USB_StrDesc_vendor_string {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint16_t bString[7];
|
|
||||||
} __attribute__((packed)) USB_StrDesc_vendor_string;
|
|
||||||
|
|
||||||
extern const USB_StrDesc_vendor_string vendor_string; /* String descriptor */
|
|
||||||
typedef struct _USB_StrDesc_product_string {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint16_t bString[10];
|
|
||||||
} __attribute__((packed)) USB_StrDesc_product_string;
|
|
||||||
|
|
||||||
extern const USB_StrDesc_product_string product_string; /* String descriptor */
|
|
||||||
typedef struct _USB_StrDesc_serial_number {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint16_t bString[4];
|
|
||||||
} __attribute__((packed)) USB_StrDesc_serial_number;
|
|
||||||
|
|
||||||
extern const USB_StrDesc_serial_number serial_number; /* String descriptor */
|
|
||||||
|
|
||||||
// ---------------------------
|
|
||||||
|
|
||||||
typedef USB_StringDesc *StringDescs[4];
|
|
||||||
extern const StringDescs strDescs;
|
|
||||||
extern const USB_DeviceDesc devDesc; /* Device Descriptor */
|
extern const USB_DeviceDesc devDesc; /* Device Descriptor */
|
||||||
extern const USB_DeviceQualifierDesc devQualDesc; /* Device Qualifier descriptor */
|
extern const USB_DeviceQualifierDesc devQualDesc; /* Device Qualifier descriptor */
|
||||||
typedef struct _USB_HeaderFunctionalDescriptor {
|
typedef struct _USB_HeaderFunctionalDescriptor {
|
||||||
@ -73,12 +40,15 @@ typedef struct _FullConfigurations0 {
|
|||||||
USB_InterfaceDesc intf0; /* Interface descriptor : 0 */
|
USB_InterfaceDesc intf0; /* Interface descriptor : 0 */
|
||||||
USB_HeaderFunctionalDescriptor intf0hfd; /* Header Functional descriptor */
|
USB_HeaderFunctionalDescriptor intf0hfd; /* Header Functional descriptor */
|
||||||
USB_AbstractControlManagementFunctionalDescriptor intf0acmfd; /* Abstract Control Management Functional descriptor */
|
USB_AbstractControlManagementFunctionalDescriptor intf0acmfd; /* Abstract Control Management Functional descriptor */
|
||||||
USB_UnionFunctionalDescriptor intf0ufd; /* Abstract Control Management Functional descriptor */
|
USB_UnionFunctionalDescriptor intf0ufd; /* Union Functional descriptor */
|
||||||
USB_CallManagementFunctionalDescriptor intf0cmfd; /* Call Management Functional descriptor */
|
USB_CallManagementFunctionalDescriptor intf0cmfd; /* Call Management Functional descriptor */
|
||||||
USB_EndpointDesc ep2in; /* Endpoint descriptor : 2 in */
|
USB_EndpointDesc ep2in; /* Endpoint descriptor : 2 in */
|
||||||
USB_InterfaceDesc intf1; /* Interface descriptor : 1 */
|
USB_InterfaceDesc intf1; /* Interface descriptor : 1 */
|
||||||
USB_EndpointDesc ep1in; /* Endpoint descriptor : 1 in */
|
USB_EndpointDesc ep1in; /* Endpoint descriptor : 1 in */
|
||||||
USB_EndpointDesc ep1out; /* Endpoint descriptor : 1 out */
|
USB_EndpointDesc ep1out; /* Endpoint descriptor : 1 out */
|
||||||
|
USB_InterfaceDesc intf2; /* Interface descriptor : 2 */
|
||||||
|
USB_EndpointDesc ep3in; /* Endpoint descriptor : 3 in */
|
||||||
|
USB_EndpointDesc ep3out; /* Endpoint descriptor : 3 out */
|
||||||
} __attribute__((packed)) FullConfigurations0;
|
} __attribute__((packed)) FullConfigurations0;
|
||||||
|
|
||||||
extern const FullConfigurations0 fullConfDescs0;
|
extern const FullConfigurations0 fullConfDescs0;
|
||||||
@ -87,5 +57,38 @@ extern const FullConfigurations0 fullConfDescs0;
|
|||||||
|
|
||||||
typedef USB_ConfigurationDesc *ConfDescs[1];
|
typedef USB_ConfigurationDesc *ConfDescs[1];
|
||||||
extern const ConfDescs confDescs;
|
extern const ConfDescs confDescs;
|
||||||
|
typedef struct _USB_StrDesc_lang_id {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t bString;
|
||||||
|
} __attribute__((packed)) USB_StrDesc_lang_id;
|
||||||
|
|
||||||
#endif /* CORE_USB_DESC_USB_DESC */
|
extern const USB_StrDesc_lang_id lang_id; /* String descriptor */
|
||||||
|
typedef struct _USB_StrDesc_vendor_string {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t bString[7];
|
||||||
|
} __attribute__((packed)) USB_StrDesc_vendor_string;
|
||||||
|
|
||||||
|
extern const USB_StrDesc_vendor_string vendor_string; /* String descriptor */
|
||||||
|
typedef struct _USB_StrDesc_product_string {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t bString[10];
|
||||||
|
} __attribute__((packed)) USB_StrDesc_product_string;
|
||||||
|
|
||||||
|
extern const USB_StrDesc_product_string product_string; /* String descriptor */
|
||||||
|
typedef struct _USB_StrDesc_serial_number {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t bString[4];
|
||||||
|
} __attribute__((packed)) USB_StrDesc_serial_number;
|
||||||
|
|
||||||
|
extern const USB_StrDesc_serial_number serial_number; /* String descriptor */
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
typedef USB_StringDesc *StringDescs[4];
|
||||||
|
extern const StringDescs strDescs;
|
||||||
|
|
||||||
|
#endif // _USB_DESC_H
|
||||||
|
239
usb.c
239
usb.c
@ -69,40 +69,40 @@ void usbcore_init() {
|
|||||||
|
|
||||||
void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) {
|
void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) {
|
||||||
|
|
||||||
//MSG("STUP: %u, %s\n", size, stage == UST_SETUP ? "SETUP" : "DATA");
|
// MSG("STUP: %u, %s\n", size, stage == UST_SETUP ? "SETUP" : "DATA");
|
||||||
|
|
||||||
// #define USB_PREPARE_DESC_VAR(var, size) sz = usb_prepare_descriptor((const uint8_t *)&(var), sizeof((var)), (size))
|
// #define USB_PREPARE_DESC_VAR(var, size) sz = usb_prepare_descriptor((const uint8_t *)&(var), sizeof((var)), (size))
|
||||||
|
|
||||||
switch (stups.next_stage) {
|
switch (stups.next_stage) {
|
||||||
case UST_SETUP: { // expecting SETUP stage
|
case UST_SETUP: { // expecting SETUP stage
|
||||||
if (stage == UST_SETUP) { // SETUP received
|
if (stage == UST_SETUP) { // SETUP received
|
||||||
// save setup request
|
// save setup request
|
||||||
stups.setup_req = *((USB_SetupRequest *)data);
|
stups.setup_req = *((USB_SetupRequest *)data);
|
||||||
|
|
||||||
// if data direction is IN, then don't expect an OUT transaction
|
// if data direction is IN, then don't expect an OUT transaction
|
||||||
if ((stups.setup_req.bmRequestType.fields.dir == USB_IN) ||
|
if ((stups.setup_req.bmRequestType.fields.dir == USB_IN) ||
|
||||||
((stups.setup_req.bmRequestType.fields.dir == USB_OUT) && (stups.setup_req.wLength == 0))) {
|
((stups.setup_req.bmRequestType.fields.dir == USB_OUT) && (stups.setup_req.wLength == 0))) {
|
||||||
stups.out_complete = true; // DATA stage is IN
|
stups.out_complete = true; // DATA stage is IN
|
||||||
} else {
|
} else {
|
||||||
stups.out_complete = false; // OUT transaction are not exhausted yet (i.e. DATA stage is OUT)
|
stups.out_complete = false; // OUT transaction are not exhausted yet (i.e. DATA stage is OUT)
|
||||||
stups.next_stage = UST_DATA; // next stage is DATA OUT stage
|
stups.next_stage = UST_DATA; // next stage is DATA OUT stage
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UST_DATA: { // expecting DATA stage
|
||||||
|
if (stage == UST_DATA) { // DATA received
|
||||||
|
stups.out_complete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UST_DATA: { // expecting DATA stage
|
// step into SETUP state
|
||||||
if (stage == UST_DATA) { // DATA received
|
stups.next_stage = UST_SETUP;
|
||||||
stups.out_complete = true;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// step into SETUP state
|
default:
|
||||||
stups.next_stage = UST_SETUP;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// expect status transaction to follow the data phase
|
// expect status transaction to follow the data phase
|
||||||
@ -117,117 +117,132 @@ void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stag
|
|||||||
#define SET_TRANSMISSION_POINTER(ptr) data = (const uint8_t *)(ptr)
|
#define SET_TRANSMISSION_POINTER(ptr) data = (const uint8_t *)(ptr)
|
||||||
|
|
||||||
switch (stups.setup_req.bRequest) {
|
switch (stups.setup_req.bRequest) {
|
||||||
case UREQ_GetDescriptor: // GET DESCRIPTOR
|
case UREQ_GetDescriptor: // GET DESCRIPTOR
|
||||||
{
|
{
|
||||||
// which descriptor?
|
// which descriptor?
|
||||||
uint8_t desc_type = (stups.setup_req.wValue >> 8); // get descriptor type
|
uint8_t desc_type = (stups.setup_req.wValue >> 8); // get descriptor type
|
||||||
uint8_t desc_index = (stups.setup_req.wValue & 0xFF); // get descriptor index
|
uint8_t desc_index = (stups.setup_req.wValue & 0xFF); // get descriptor index
|
||||||
uint8_t sz = 0;
|
uint8_t sz = 0;
|
||||||
const uint8_t *data = NULL;
|
const uint8_t *data = NULL;
|
||||||
|
|
||||||
switch (desc_type) {
|
switch (desc_type) {
|
||||||
case UD_Device: // DEVICE DESCRIPTOR
|
case UD_Device: // DEVICE DESCRIPTOR
|
||||||
DETERMINE_TRANSFER_SIZE(devDesc.bLength);
|
DETERMINE_TRANSFER_SIZE(devDesc.bLength);
|
||||||
SET_TRANSMISSION_POINTER(&devDesc);
|
SET_TRANSMISSION_POINTER(&devDesc);
|
||||||
break;
|
break;
|
||||||
case UD_Configuration: // CONFIGURATION DESCRIPTOR
|
case UD_Configuration: // CONFIGURATION DESCRIPTOR
|
||||||
DETERMINE_TRANSFER_SIZE(confDescs[desc_index]->wTotalLength);
|
DETERMINE_TRANSFER_SIZE(confDescs[desc_index]->wTotalLength);
|
||||||
SET_TRANSMISSION_POINTER(confDescs[desc_index]);
|
SET_TRANSMISSION_POINTER(confDescs[desc_index]);
|
||||||
break;
|
break;
|
||||||
case UD_String: // STRING DESCRIPTOR
|
case UD_String: // STRING DESCRIPTOR
|
||||||
DETERMINE_TRANSFER_SIZE(strDescs[desc_index]->bLength);
|
DETERMINE_TRANSFER_SIZE(strDescs[desc_index]->bLength);
|
||||||
SET_TRANSMISSION_POINTER(strDescs[desc_index]);
|
SET_TRANSMISSION_POINTER(strDescs[desc_index]);
|
||||||
break;
|
break;
|
||||||
case UD_DeviceQualifier:
|
case UD_DeviceQualifier:
|
||||||
DETERMINE_TRANSFER_SIZE(devQualDesc.bLength);
|
DETERMINE_TRANSFER_SIZE(devQualDesc.bLength);
|
||||||
SET_TRANSMISSION_POINTER(&devQualDesc);
|
SET_TRANSMISSION_POINTER(&devQualDesc);
|
||||||
break;
|
break;
|
||||||
// Descriptors not implemented
|
// Descriptors not implemented
|
||||||
default:
|
default:
|
||||||
usbdrv_stall_endpoint(0, USB_IN, true); // stall IN, since request in unsupported
|
usbdrv_stall_endpoint(0, USB_IN, true); // stall IN, since request in unsupported
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// arm data transmission
|
|
||||||
usbdrv_arm_IN_endpoint(0, data, sz);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UREQ_SetAddress: { // SET ADDRESS
|
// arm data transmission
|
||||||
uint8_t addr = stups.setup_req.wValue & 0x7F;
|
usbdrv_arm_IN_endpoint(0, data, sz);
|
||||||
usbdrv_set_address(addr);
|
break;
|
||||||
usbdrv_arm_OUT_endpoint(0, 64); // prepare for data OUT stage
|
}
|
||||||
USBDRV_ARM_IN_ZLP(0); // ZLP IN
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case UREQ_SetConfiguration: // SET CONFIGURATION
|
|
||||||
{
|
|
||||||
uint8_t config_id = stups.setup_req.wValue & 0xFF;
|
|
||||||
usbdrv_fetch_endpoint_configuration(config_id - 1);
|
|
||||||
USBDRV_ARM_IN_ZLP(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case UREQ_SetInterface: // SET INTERFACE
|
|
||||||
{
|
|
||||||
// TODO: set configuration
|
|
||||||
USBDRV_ARM_IN_ZLP(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: { // UNKNOWN REQUEST, pass processing to user application
|
|
||||||
USB_CallbackEvent cbevt = { 0 };
|
|
||||||
cbevt.type = USB_CBEVT_UNKNOWN_REQ;
|
|
||||||
cbevt.setup_request = &stups.setup_req;
|
|
||||||
cbevt.data = (const uint8_t *)data;
|
|
||||||
cbevt.size = size;
|
|
||||||
cbevt.ep = 0;
|
|
||||||
cbevt.dir = USB_OUT;
|
|
||||||
cbevt.reply_valid = false;
|
|
||||||
usb_event_callback(&cbevt);
|
|
||||||
|
|
||||||
if (cbevt.reply_valid) {
|
case UREQ_SetAddress: { // SET ADDRESS
|
||||||
usbdrv_arm_IN_endpoint(0, cbevt.reply_data, cbevt.reply_size);
|
uint8_t addr = stups.setup_req.wValue & 0x7F;
|
||||||
}
|
usbdrv_set_address(addr);
|
||||||
break;
|
usbdrv_arm_OUT_endpoint(0, 64); // prepare for data OUT stage
|
||||||
|
USBDRV_ARM_IN_ZLP(0); // ZLP IN
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UREQ_SetConfiguration: // SET CONFIGURATION
|
||||||
|
{
|
||||||
|
uint8_t config_id = stups.setup_req.wValue & 0xFF;
|
||||||
|
usbdrv_fetch_endpoint_configuration(config_id - 1);
|
||||||
|
USBDRV_ARM_IN_ZLP(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UREQ_SetInterface: // SET INTERFACE
|
||||||
|
{
|
||||||
|
// TODO: set configuration
|
||||||
|
USBDRV_ARM_IN_ZLP(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: { // UNKNOWN REQUEST, pass processing to user application
|
||||||
|
USB_CallbackEvent cbevt = {0};
|
||||||
|
cbevt.type = USB_CBEVT_UNKNOWN_REQ;
|
||||||
|
cbevt.setup_request = &stups.setup_req;
|
||||||
|
cbevt.data = (const uint8_t *)data;
|
||||||
|
cbevt.size = size;
|
||||||
|
cbevt.ep = 0;
|
||||||
|
cbevt.dir = USB_OUT;
|
||||||
|
cbevt.reply_valid = false;
|
||||||
|
usb_event_callback(&cbevt);
|
||||||
|
|
||||||
|
if (cbevt.reply_valid) {
|
||||||
|
usbdrv_arm_IN_endpoint(0, cbevt.reply_data, cbevt.reply_size);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stups.out_complete = false;
|
stups.out_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
|
void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
|
||||||
USB_CallbackEvent cbevt = { 0 }; // allocate and clear structure...
|
USB_CallbackEvent cbevt = {0}; // allocate and clear structure...
|
||||||
cbevt.ep = cbcpd->ep; // later only fill nonzero fields
|
cbevt.ep = cbcpd->ep; // later only fill nonzero fields
|
||||||
|
|
||||||
bool discard_event = false; // only discard if event does not fit any category above
|
bool discard_event = false; // only discard if event does not fit any category above
|
||||||
switch (cbcpd->code) {
|
switch (cbcpd->code) {
|
||||||
case USB_CBC_OUT: {
|
case USB_CBC_OUT: {
|
||||||
cbevt.type = USB_CBEVT_OUT;
|
cbevt.type = USB_CBEVT_OUT;
|
||||||
cbevt.data = cbcpd->data;
|
cbevt.data = cbcpd->data;
|
||||||
cbevt.size = cbcpd->size;
|
cbevt.size = cbcpd->size;
|
||||||
cbevt.dir = USB_OUT;
|
cbevt.dir = USB_OUT;
|
||||||
break;
|
cbevt.arm_out_endpoint = true;
|
||||||
}
|
break;
|
||||||
case USB_CBC_IN_FIFOEMPTY:
|
}
|
||||||
case USB_CBC_IN_DONE: {
|
case USB_CBC_IN_FIFOEMPTY:
|
||||||
cbevt.type = USB_CBEVT_IN;
|
case USB_CBC_IN_DONE: {
|
||||||
if (cbcpd->code == USB_CBC_IN_FIFOEMPTY) { // signals a failed in transfer
|
cbevt.type = USB_CBEVT_IN;
|
||||||
cbevt.subtype = USB_CBEVST_IN_REQ;
|
if (cbcpd->code == USB_CBC_IN_FIFOEMPTY) { // signals a failed in transfer
|
||||||
}
|
cbevt.subtype = USB_CBEVST_IN_REQ;
|
||||||
cbevt.dir = USB_IN;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
cbevt.dir = USB_IN;
|
||||||
|
cbevt.enable_autozlp = true; // by default, enable auto ZLP
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
discard_event = true;
|
discard_event = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if event is not ment to be discarded, then invoke event callback
|
// if event is not ment to be discarded, then invoke event callback
|
||||||
if (!discard_event) {
|
if (!discard_event) {
|
||||||
usb_event_callback(&cbevt);
|
usb_event_callback(&cbevt);
|
||||||
|
|
||||||
|
// for OUT events, check the autoarm flag
|
||||||
|
if (cbevt.dir == USB_OUT) {
|
||||||
|
if (cbevt.arm_out_endpoint) {
|
||||||
|
usbdrv_autoarm_OUT_endpoint(cbcpd->ep);
|
||||||
|
}
|
||||||
|
} else if (cbevt.dir == USB_IN) {
|
||||||
|
usbdrv_enable_autozlp(cbcpd->ep, cbevt.enable_autozlp); // handle auto ZLP setting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t usbcore_write(uint8_t ep, const uint8_t *data, uint16_t size) {
|
uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size) {
|
||||||
return usbdrv_arm_IN_endpoint(ep, data, size);
|
return usbdrv_arm_IN_endpoint(ep, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size) {
|
||||||
|
return usbdrv_arm_OUT_endpoint(ep, size);
|
||||||
}
|
}
|
3
usb.h
3
usb.h
@ -4,6 +4,7 @@
|
|||||||
#include "usb_callback_event.h"
|
#include "usb_callback_event.h"
|
||||||
|
|
||||||
void usbcore_init(); // initialize USB core
|
void usbcore_init(); // initialize USB core
|
||||||
uint32_t usbcore_write(uint8_t ep, const uint8_t *data, uint16_t size); // write data to endpoint, return with number of bytes actually written
|
uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t size); // write data to endpoint, return with number of bytes actually written
|
||||||
|
uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size); // expect data coming from the endpoint
|
||||||
|
|
||||||
#endif /* CORE_USB_USB */
|
#endif /* CORE_USB_USB */
|
||||||
|
@ -28,6 +28,8 @@ typedef struct {
|
|||||||
bool reply_valid; // reply message is valid
|
bool reply_valid; // reply message is valid
|
||||||
const uint8_t * reply_data; // reply data
|
const uint8_t * reply_data; // reply data
|
||||||
uint8_t reply_size; // reply size
|
uint8_t reply_size; // reply size
|
||||||
|
bool arm_out_endpoint; // automatically arm OUT endpoint at the end of the current transmission
|
||||||
|
bool enable_autozlp; // enable automatic ZLP transmission based on transfer size
|
||||||
} USB_CallbackEvent;
|
} USB_CallbackEvent;
|
||||||
|
|
||||||
#endif /* CORE_USB_USB_CALLBACK_EVENT */
|
#endif /* CORE_USB_USB_CALLBACK_EVENT */
|
||||||
|
381
usb_driver.c
381
usb_driver.c
@ -94,6 +94,10 @@ void usbdrv_reset() {
|
|||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
|
static void usbdrv_thread(void *param);
|
||||||
|
#endif
|
||||||
|
|
||||||
// initialize global state
|
// initialize global state
|
||||||
void usbdrv_init_global_state() {
|
void usbdrv_init_global_state() {
|
||||||
// clear state
|
// clear state
|
||||||
@ -103,8 +107,18 @@ void usbdrv_init_global_state() {
|
|||||||
gs.rx_buf = rx_buf;
|
gs.rx_buf = rx_buf;
|
||||||
gs.rx_buf_level = 0;
|
gs.rx_buf_level = 0;
|
||||||
|
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
// initialize event queue
|
// initialize event queue
|
||||||
// gs.event_queue = Q_CREATE_T(USB_EVENT_QUEUE_LENGTH, USBDRV_EventCompound, event_queue_mem);
|
gs.event_queue = osMessageQueueNew(16, sizeof(USBDRV_EventCompound), NULL);
|
||||||
|
|
||||||
|
// initialize event processing thread
|
||||||
|
osThreadAttr_t attr;
|
||||||
|
bzero(&attr, sizeof(osThreadAttr_t));
|
||||||
|
attr.stack_size = 2048;
|
||||||
|
attr.name = "usb";
|
||||||
|
attr.priority = osPriorityNormal;
|
||||||
|
gs.th = osThreadNew(usbdrv_thread, NULL, &attr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
@ -149,6 +163,9 @@ void usbdrv_periph_init() {
|
|||||||
usbdrv_flush_rx_fifo();
|
usbdrv_flush_rx_fifo();
|
||||||
usbdrv_flush_tx_fifo(USB_FLUSH_TX_FIFO_ALL);
|
usbdrv_flush_tx_fifo(USB_FLUSH_TX_FIFO_ALL);
|
||||||
|
|
||||||
|
// make Tx FIFO empty interrupt fire when Tx FIFO is emtpy
|
||||||
|
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_TXFELVL);
|
||||||
|
|
||||||
// set masks for endpoint interrupts
|
// set masks for endpoint interrupts
|
||||||
SET_BIT(USBD->DIEPMSK, USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_ITTXFEMSK); // transfer complete, timeout and Tx FIFO empty while receiving IN for IN EPs
|
SET_BIT(USBD->DIEPMSK, USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_ITTXFEMSK); // transfer complete, timeout and Tx FIFO empty while receiving IN for IN EPs
|
||||||
SET_BIT(USBD->DOEPMSK, USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_STUPM); // transfer complete and SETUP complete for OUT EPs
|
SET_BIT(USBD->DOEPMSK, USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_STUPM); // transfer complete and SETUP complete for OUT EPs
|
||||||
@ -244,7 +261,7 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) {
|
|||||||
#define USB_MIN_FIFO_SIZE (64)
|
#define USB_MIN_FIFO_SIZE (64)
|
||||||
#define USB_FIFO_MARGIN (8)
|
#define USB_FIFO_MARGIN (8)
|
||||||
#define USB_RX_FIFO_SETUP_RESERVATION_DWORDS (10)
|
#define USB_RX_FIFO_SETUP_RESERVATION_DWORDS (10)
|
||||||
#define USB_MIN_GROSS_TX_FIFO_SIZE (USB_MIN_EP_FIFO_SIZE + USB_FIFO_MARGIN)
|
#define USB_MIN_GROSS_TX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE)
|
||||||
#define USB_MIN_GROSS_RX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE + USB_RX_FIFO_SETUP_RESERVATION_DWORDS * 4)
|
#define USB_MIN_GROSS_RX_FIFO_SIZE (2 * USB_MIN_EP_FIFO_SIZE + USB_RX_FIFO_SETUP_RESERVATION_DWORDS * 4)
|
||||||
|
|
||||||
// build FIFO (compute addresses)
|
// build FIFO (compute addresses)
|
||||||
@ -265,10 +282,12 @@ void usbdrv_build_fifo() {
|
|||||||
for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) {
|
for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) {
|
||||||
USBDRV_EpConfig *cfg = &gs.ep_IN[i];
|
USBDRV_EpConfig *cfg = &gs.ep_IN[i];
|
||||||
if (cfg->is_configured) {
|
if (cfg->is_configured) {
|
||||||
cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size + USB_FIFO_MARGIN)); // correct FIFO size if necessary
|
cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size)); // correct FIFO size if necessary
|
||||||
cfg->fifo_address = next_fifo_addr; // store FIFO address
|
cfg->fifo_address = next_fifo_addr; // store FIFO address
|
||||||
cfg->zlp_next = false; // clear ZLP next
|
cfg->auto_zlp = true; // turn on automatic ZLP appending
|
||||||
next_fifo_addr += cfg->fifo_size; // advance next address
|
cfg->zlp_next = false;
|
||||||
|
// cfg->txp = false; // no transfer is in progress
|
||||||
|
next_fifo_addr += cfg->fifo_size; // advance next address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,6 +374,8 @@ void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *c
|
|||||||
// NAK processing
|
// NAK processing
|
||||||
if (cfg->responding_NAK) {
|
if (cfg->responding_NAK) {
|
||||||
SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_SNAK); // send NAK
|
SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_SNAK); // send NAK
|
||||||
|
} else {
|
||||||
|
SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_CNAK); // clear sending NAK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,44 +491,73 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
|
|||||||
/*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
|
/*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
|
||||||
WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
||||||
|
|
||||||
// transmission may only be commenced if last transmission has concluded
|
// determine if a transmission is in progress or not
|
||||||
if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
|
bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA);
|
||||||
|
/*if (txp) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
|
||||||
|
|
||||||
// determine final write size
|
// determine final write size
|
||||||
uint32_t freeSize = 0;
|
uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
|
||||||
// if (len > 0) { // only poll DTXFSTS if (len > 0) (see datasheet)
|
uint16_t writeSize = 0;
|
||||||
freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
|
|
||||||
//}
|
|
||||||
uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
|
|
||||||
|
|
||||||
// calculate packet count based on max packet size
|
if (txp) { // transaction is in progress
|
||||||
uint16_t mps = gs.ep_IN[ep].max_packet_size;
|
uint32_t remainingBytes = USBINEP[ep].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ; // acquire remaining bytes
|
||||||
uint16_t packet_count = 1; // for ZLPs
|
if (len >= mps) { // write only full-sized packets, or a short packet
|
||||||
if (writeSize > 0) { // if length is nonzero
|
uint16_t mws = MIN(freeSize, len); // maximum possible write size
|
||||||
packet_count = writeSize / mps + (((writeSize % mps) > 0) ? 1 : 0);
|
uint16_t fpc = mws / mps; // full packet count
|
||||||
|
writeSize = fpc * mps; // form write size
|
||||||
|
} else { // length is less then a full packet size
|
||||||
|
if (len <= freeSize) { // packet can be written
|
||||||
|
writeSize = len;
|
||||||
|
} else {
|
||||||
|
writeSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// adjust write size to remaining size
|
||||||
|
writeSize = MIN(remainingBytes, writeSize);
|
||||||
|
} else { // no transaction is in progress
|
||||||
|
writeSize = MIN(freeSize, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set zlp_next if transmission size is integer multiple of max packet size6
|
// if no transmission is in progress
|
||||||
gs.ep_IN[ep].zlp_next = (writeSize > 0) && ((writeSize % mps) == 0);
|
if (!txp) {
|
||||||
|
// calculate packet count based on max packet size
|
||||||
|
uint16_t packet_count = 1; // for ZLPs
|
||||||
|
if (len > 0) { // if length is nonzero
|
||||||
|
packet_count = len / mps + (((len % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
|
||||||
|
}
|
||||||
|
|
||||||
// program DIEPTSIZ with transfer length
|
// set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
|
||||||
USBINEP[ep].DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) | (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
|
gs.ep_IN[ep].zlp_next = (len > 0) && ((len % mps) == 0);
|
||||||
|
|
||||||
// enable endpoint and cancel responding NAK
|
// program DIEPTSIZ with transfer length
|
||||||
SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
|
USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | len;
|
||||||
|
|
||||||
|
// enable endpoint and cancel responding NAK
|
||||||
|
SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn interrupt generation on only, if this is NOT the last FIFO write considering the current transfer
|
||||||
|
if (len > writeSize) {
|
||||||
|
USBD->DIEPEMPMSK |= ((uint32_t)(1 << ep));
|
||||||
|
}
|
||||||
|
|
||||||
// disable ALL USB interrupts to prevent access to specific registers (see errata)
|
// disable ALL USB interrupts to prevent access to specific registers (see errata)
|
||||||
CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
||||||
|
|
||||||
|
// https://github.com/iliasam/STM32F4_USB_MICROPHONE/blob/master/Libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c#L655
|
||||||
|
// https://github.com/iliasam/STM32F4_USB_MICROPHONE/blob/master/Libraries/STM32_USB_OTG_Driver/src/usb_core.c#L168
|
||||||
|
|
||||||
// push full dwords
|
// push full dwords
|
||||||
volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
|
volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
|
||||||
uint32_t floorlen_dwords = writeSize >> 2;
|
uint32_t floorlen_dwords = writeSize >> 2;
|
||||||
for (uint16_t i = 0; i < floorlen_dwords; i++) {
|
for (uint16_t i = 0; i < floorlen_dwords; i++) {
|
||||||
uint16_t i0 = 4 * i;
|
uint16_t i0 = 4 * i;
|
||||||
uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
|
uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
|
||||||
p[i] = dword;
|
*p = dword;
|
||||||
}
|
}
|
||||||
|
|
||||||
// push the remaining partial dword
|
// push the remaining partial dword
|
||||||
@ -529,9 +579,29 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// arm OUT endpoint
|
// arm OUT endpoint
|
||||||
void usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size) {
|
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size) {
|
||||||
|
// arm endpoint only if it was not armed before
|
||||||
|
if (READ_BIT(USBOUTEP[ep].DOEPCTL, USB_OTG_DOEPCTL_EPENA)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cap size at max packet size defined for this endpoint
|
||||||
|
size = MIN(gs.ep_OUT[ep].max_packet_size, size);
|
||||||
|
|
||||||
|
// write registers
|
||||||
USBOUTEP[ep].DOEPTSIZ |= USB_OTG_DOEPTSIZ_PKTCNT | size; // program DIEPTSIZ with maximum (expected) transfer length and set PCKTCNT to make ready for reception
|
USBOUTEP[ep].DOEPTSIZ |= USB_OTG_DOEPTSIZ_PKTCNT | size; // program DIEPTSIZ with maximum (expected) transfer length and set PCKTCNT to make ready for reception
|
||||||
SET_BIT(USBOUTEP[ep].DOEPCTL, USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK); // enable endpoint and clear NAK
|
SET_BIT(USBOUTEP[ep].DOEPCTL, USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK); // enable endpoint and clear NAK
|
||||||
|
|
||||||
|
// return with armed size
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbdrv_autoarm_OUT_endpoint(uint8_t ep) {
|
||||||
|
gs.ep_OUT[ep].autoarm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbdrv_enable_autozlp(uint8_t ep, bool en) {
|
||||||
|
gs.ep_IN[ep].auto_zlp = en;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
@ -543,25 +613,25 @@ void usbdrv_set_address(uint8_t addr) {
|
|||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
// push event onto the event queue
|
// push event onto the event queue
|
||||||
// void usbdrv_push_event(uint32_t evt_code, USBDRV_EventData *evt_data) {
|
void usbdrv_push_event(uint32_t evt_code, USBDRV_EventData *evt_data) {
|
||||||
// USBDRV_EventCompound evt_cpd;
|
USBDRV_EventCompound evt_cpd;
|
||||||
// if (evt_data != NULL) {
|
if (evt_data != NULL) {
|
||||||
// evt_cpd.data = *evt_data;
|
evt_cpd.data = *evt_data;
|
||||||
// }
|
}
|
||||||
// evt_cpd.code = evt_code;
|
evt_cpd.code = evt_code;
|
||||||
// q_push(gs.event_queue, &evt_cpd);
|
osMessageQueuePut(gs.event_queue, &evt_cpd, 0, 0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // call this to process incoming events
|
static void usbdrv_thread(void *param) {
|
||||||
// void usbdrv_periodic_processing() {
|
for (;;) {
|
||||||
// if ((gs.event_queue != NULL) && (q_avail(gs.event_queue))) {
|
USBDRV_EventCompound evt_cpd;
|
||||||
// USBDRV_EventCompound evt_cpd;
|
osMessageQueueGet(gs.event_queue, &evt_cpd, 0, osWaitForever);
|
||||||
// q_top(gs.event_queue, &evt_cpd);
|
usbdrv_process_event(evt_cpd.code, NULL);
|
||||||
// q_pop(gs.event_queue);
|
}
|
||||||
// usbdrv_process_event(evt_cpd.code, NULL);
|
}
|
||||||
// }
|
#endif
|
||||||
// }
|
|
||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
@ -664,7 +734,10 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
|
|||||||
SET_BIT(USBOUTEP[ep].DOEPINT, USB_OTG_DOEPINT_XFRC);
|
SET_BIT(USBOUTEP[ep].DOEPINT, USB_OTG_DOEPINT_XFRC);
|
||||||
USBMSG("OUT\n");
|
USBMSG("OUT\n");
|
||||||
|
|
||||||
usbdrv_arm_OUT_endpoint(ep, gs.ep_OUT[ep].max_packet_size);
|
if ((ep == 0) || (gs.ep_OUT[ep].autoarm)) { // EP0 must always be armed
|
||||||
|
usbdrv_arm_OUT_endpoint(ep, gs.ep_OUT[ep].max_packet_size); // arm endpoint
|
||||||
|
gs.ep_OUT[ep].autoarm = false; // clear autoarm flag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -685,13 +758,23 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
|
|||||||
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC)) { // timeout done
|
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC)) { // timeout done
|
||||||
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
|
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
|
||||||
USBMSG("TO\n");
|
USBMSG("TO\n");
|
||||||
}
|
} else if ((USBD->DIEPEMPMSK & (1 << ep)) && READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TXFE)) {
|
||||||
|
// disable FIFO empty interrupt
|
||||||
|
USBD->DIEPEMPMSK &= ~((uint32_t)(1 << ep));
|
||||||
|
|
||||||
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC)) { // IN transaction done
|
cbcpd.code = USB_CBC_IN_FIFOEMPTY;
|
||||||
|
usbcore_process_nonsetup_event(&cbcpd);
|
||||||
|
} else if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC)) { // IN transaction done
|
||||||
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC);
|
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_XFRC);
|
||||||
|
|
||||||
|
// disable FIFO empty interrupt
|
||||||
|
USBD->DIEPEMPMSK &= ~((uint32_t)(1 << ep));
|
||||||
|
|
||||||
|
// transfer finished
|
||||||
|
// gs.ep_IN[ep].txp = false;
|
||||||
|
|
||||||
// see if a ZLP transmission was queued
|
// see if a ZLP transmission was queued
|
||||||
if (gs.ep_IN[ep].zlp_next) {
|
if (/*gs.ep_IN[ep].auto_zlp && */ gs.ep_IN[ep].zlp_next) {
|
||||||
usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
|
usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
|
||||||
} else { // no ZLP
|
} else { // no ZLP
|
||||||
USBMSG("IN [%d]\n", ep);
|
USBMSG("IN [%d]\n", ep);
|
||||||
@ -699,13 +782,14 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
|
|||||||
cbcpd.code = USB_CBC_IN_DONE;
|
cbcpd.code = USB_CBC_IN_DONE;
|
||||||
usbcore_process_nonsetup_event(&cbcpd);
|
usbcore_process_nonsetup_event(&cbcpd);
|
||||||
}
|
}
|
||||||
}
|
} else if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE)) { // IN endpoint IN token received with Tx FIFO empty interrupt
|
||||||
|
|
||||||
if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE)) { // IN endpoint IN token received with Tx FIFO empty interrupt
|
|
||||||
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE);
|
SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE);
|
||||||
|
|
||||||
// USBMSG("IN FIFOEMPTY [%d]\n", ep);
|
// USBMSG("IN FIFOEMPTY [%d]\n", ep);
|
||||||
|
|
||||||
|
// transfer finished
|
||||||
|
// gs.ep_IN[ep].txp = false;
|
||||||
|
|
||||||
cbcpd.code = USB_CBC_IN_FIFOEMPTY;
|
cbcpd.code = USB_CBC_IN_FIFOEMPTY;
|
||||||
usbcore_process_nonsetup_event(&cbcpd);
|
usbcore_process_nonsetup_event(&cbcpd);
|
||||||
}
|
}
|
||||||
@ -737,7 +821,14 @@ bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir) {
|
|||||||
return (USBD->DAINT & (1 << (ep + ((dir == USB_OUT) ? USB_OTG_DAINT_OEPINT_Pos : 0)))) != 0;
|
return (USBD->DAINT & (1 << (ep + ((dir == USB_OUT) ? USB_OTG_DAINT_OEPINT_Pos : 0)))) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
|
#define PROCESS_EVENT(evt, data) usbdrv_push_event((evt), (data))
|
||||||
|
#else
|
||||||
|
#define PROCESS_EVENT(evt, data) usbdrv_process_event((evt), (data))
|
||||||
|
#endif
|
||||||
|
|
||||||
void OTG_FS_IRQHandler() {
|
void OTG_FS_IRQHandler() {
|
||||||
|
|
||||||
uint32_t ints = USBG->GINTSTS;
|
uint32_t ints = USBG->GINTSTS;
|
||||||
|
|
||||||
// USB reset
|
// USB reset
|
||||||
@ -753,15 +844,16 @@ void OTG_FS_IRQHandler() {
|
|||||||
// ST calls speed negotiation the enumeration, normally this
|
// ST calls speed negotiation the enumeration, normally this
|
||||||
// interrupt fires only before even communication is commenced)
|
// interrupt fires only before even communication is commenced)
|
||||||
if (ints & USB_OTG_GINTSTS_ENUMDNE) {
|
if (ints & USB_OTG_GINTSTS_ENUMDNE) {
|
||||||
SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_ENUMDNE); // clear interrupt
|
SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_ENUMDNE); // clear interrupt
|
||||||
usbdrv_process_event(USB_EVT_SPEEDNEG_DONE, NULL); // process event
|
PROCESS_EVENT(USB_EVT_SPEEDNEG_DONE, NULL); // process event
|
||||||
// usbdrv_push_event(USB_EVT_SPEEDNEG_DONE, NULL); // push event
|
// usbdrv_process_event(USB_EVT_SPEEDNEG_DONE, NULL); // process event
|
||||||
|
// usbdrv_push_event(USB_EVT_SPEEDNEG_DONE, NULL); // push event
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start of Frame received (like Keep-Alive in LS mode)
|
// Start of Frame received (like Keep-Alive in LS mode)
|
||||||
// if (ints & USB_OTG_GINTSTS_SOF) {
|
if (ints & USB_OTG_GINTSTS_SOF) {
|
||||||
// SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_SOF); // clear interrupt
|
SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_SOF); // clear interrupt
|
||||||
// }
|
}
|
||||||
|
|
||||||
// USB Suspend
|
// USB Suspend
|
||||||
if (ints & USB_OTG_GINTSTS_USBSUSP) {
|
if (ints & USB_OTG_GINTSTS_USBSUSP) {
|
||||||
@ -771,7 +863,7 @@ void OTG_FS_IRQHandler() {
|
|||||||
|
|
||||||
// OUT endpoint interrupt
|
// OUT endpoint interrupt
|
||||||
if (ints & USB_OTG_GINTSTS_OEPINT) {
|
if (ints & USB_OTG_GINTSTS_OEPINT) {
|
||||||
usbdrv_process_event(USB_EVT_OUT_DONE, NULL);
|
PROCESS_EVENT(USB_EVT_OUT_DONE, NULL);
|
||||||
// usbdrv_push_event(USB_EVT_OUT_DONE, NULL);
|
// usbdrv_push_event(USB_EVT_OUT_DONE, NULL);
|
||||||
// if (USBD->DAINT & (1 << 16)) {
|
// if (USBD->DAINT & (1 << 16)) {
|
||||||
// if (USBOUTEP[0].DOEPINT & USB_OTG_DOEPINT_STUP) {
|
// if (USBOUTEP[0].DOEPINT & USB_OTG_DOEPINT_STUP) {
|
||||||
@ -785,15 +877,182 @@ void OTG_FS_IRQHandler() {
|
|||||||
// SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_RXFLVL); // clear interrupt
|
// SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_RXFLVL); // clear interrupt
|
||||||
USBMSG("RX DONE\n");
|
USBMSG("RX DONE\n");
|
||||||
// CLEAR_BIT(USBG->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); // mask interrupt until processing is done
|
// CLEAR_BIT(USBG->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); // mask interrupt until processing is done
|
||||||
usbdrv_process_event(USB_EVT_RECEPTION_DONE, NULL); // process event
|
PROCESS_EVENT(USB_EVT_RECEPTION_DONE, NULL); // process event
|
||||||
// usbdrv_push_event(USB_EVT_RECEPTION_DONE, NULL); // push event
|
// usbdrv_push_event(USB_EVT_RECEPTION_DONE, NULL); // push event
|
||||||
}
|
}
|
||||||
|
|
||||||
// IN endpoint interrupt
|
// IN endpoint interrupt
|
||||||
if (ints & USB_OTG_GINTSTS_IEPINT) {
|
if (ints & USB_OTG_GINTSTS_IEPINT) {
|
||||||
usbdrv_process_event(USB_EVT_IN_DONE, NULL);
|
PROCESS_EVENT(USB_EVT_IN_DONE, NULL);
|
||||||
// usbdrv_push_event(USB_EVT_IN_DONE, NULL);
|
// usbdrv_push_event(USB_EVT_IN_DONE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
|
||||||
|
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
|
||||||
|
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
|
||||||
|
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
||||||
|
|
||||||
|
// // determine if a transmission is in progress or not
|
||||||
|
// if (gs.ep_IN[ep].txp) {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // determine if a transmission is in progress or not
|
||||||
|
// // bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA); // transmission in progress
|
||||||
|
|
||||||
|
// // transmission may only be commenced if last transmission has concluded
|
||||||
|
// /*if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
|
||||||
|
// return 0;
|
||||||
|
// }*/
|
||||||
|
|
||||||
|
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
|
||||||
|
|
||||||
|
// // determine final write size
|
||||||
|
// uint32_t freeSize = 0;
|
||||||
|
|
||||||
|
// // if (len > 0) { // only poll DTXFSTS if (len > 0) (see datasheet)
|
||||||
|
// freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
|
||||||
|
// //}
|
||||||
|
|
||||||
|
// // if (gs.ep_IN[ep].txp && (freeSize == 0)) {
|
||||||
|
// // return 0;
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
|
||||||
|
|
||||||
|
// // if transmission is in progress, then remaining transmission bytes also limits transmission size
|
||||||
|
// if (gs.ep_IN[ep].txp) {
|
||||||
|
// uint16_t bytesLeft = USBINEP[ep].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ;
|
||||||
|
// writeSize = MIN(writeSize, bytesLeft);
|
||||||
|
|
||||||
|
// // if this was the last write, then disable Tx empty interrupt
|
||||||
|
// if (bytesLeft <= mps) {
|
||||||
|
// USBD->DIEPEMPMSK &= ~((uint32_t)(1 << ep));
|
||||||
|
// } else { // if not, turn it back on
|
||||||
|
// USBD->DIEPEMPMSK |= ((uint32_t)(1 << ep));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// } else { // if no transmission was in progress, then setup endpoint for transmission
|
||||||
|
// // calculate packet count based on max packet size
|
||||||
|
// uint16_t packet_count = 1; // for ZLPs
|
||||||
|
// if (writeSize > 0) { // if length is nonzero
|
||||||
|
// packet_count = len / mps + (((len % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
|
||||||
|
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (len > 0) && ((len % mps) == 0);
|
||||||
|
|
||||||
|
// // program DIEPTSIZ with transfer length
|
||||||
|
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | len;
|
||||||
|
|
||||||
|
// // enable endpoint and cancel responding NAK
|
||||||
|
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
|
||||||
|
|
||||||
|
// // enable FIFO empty interrupt, only if further write operations will follow
|
||||||
|
// // DO NOT enable this interrupt source when dealing with EP0!
|
||||||
|
// if ((ep != 0) && (writeSize < len)) {
|
||||||
|
// USBD->DIEPEMPMSK |= (1 << ep);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // set transfer in progress
|
||||||
|
// gs.ep_IN[ep].txp = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
|
||||||
|
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
||||||
|
|
||||||
|
// // push full dwords
|
||||||
|
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
|
||||||
|
// uint32_t floorlen_dwords = writeSize >> 2;
|
||||||
|
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
|
||||||
|
// uint16_t i0 = 4 * i;
|
||||||
|
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
|
||||||
|
// p[i] = dword;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // push the remaining partial dword
|
||||||
|
// uint8_t rem_bytes = writeSize & 0b11;
|
||||||
|
// if (rem_bytes > 0) {
|
||||||
|
// uint32_t rem_dword = 0;
|
||||||
|
// uint16_t rem_start = writeSize - rem_bytes;
|
||||||
|
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
|
||||||
|
// rem_dword = (rem_dword << 8) | data[i];
|
||||||
|
// }
|
||||||
|
// *p = rem_dword;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // unmask USB interrupts
|
||||||
|
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
||||||
|
|
||||||
|
// // return with written size
|
||||||
|
// return writeSize;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// EZ MŰKÖDIK, DE CSAK RÖVID TRANSFEREKRE
|
||||||
|
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
|
||||||
|
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
|
||||||
|
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
|
||||||
|
|
||||||
|
// // determine if a transmission is in progress or not
|
||||||
|
// bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA);
|
||||||
|
// if (txp) {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
|
||||||
|
|
||||||
|
// // determine final write size
|
||||||
|
// uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
|
||||||
|
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
|
||||||
|
|
||||||
|
// // calculate packet count based on max packet size
|
||||||
|
// uint16_t packet_count = 1; // for ZLPs
|
||||||
|
// if (writeSize > 0) { // if length is nonzero
|
||||||
|
// packet_count = writeSize / mps + (((writeSize % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
|
||||||
|
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (writeSize > 0) && ((writeSize % mps) == 0);
|
||||||
|
|
||||||
|
// // program DIEPTSIZ with transfer length
|
||||||
|
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
|
||||||
|
|
||||||
|
// // enable endpoint and cancel responding NAK
|
||||||
|
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
|
||||||
|
|
||||||
|
// // set transfer in progress
|
||||||
|
// //gs.ep_IN[ep].txp = true;
|
||||||
|
|
||||||
|
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
|
||||||
|
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
||||||
|
|
||||||
|
// // push full dwords
|
||||||
|
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
|
||||||
|
// uint32_t floorlen_dwords = writeSize >> 2;
|
||||||
|
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
|
||||||
|
// uint16_t i0 = 4 * i;
|
||||||
|
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
|
||||||
|
// p[i] = dword;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // push the remaining partial dword
|
||||||
|
// uint8_t rem_bytes = writeSize & 0b11;
|
||||||
|
// if (rem_bytes > 0) {
|
||||||
|
// uint32_t rem_dword = 0;
|
||||||
|
// uint16_t rem_start = writeSize - rem_bytes;
|
||||||
|
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
|
||||||
|
// rem_dword = (rem_dword << 8) | data[i];
|
||||||
|
// }
|
||||||
|
// *p = rem_dword;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // unmask USB interrupts
|
||||||
|
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
|
||||||
|
|
||||||
|
// // return with written size
|
||||||
|
// return writeSize;
|
||||||
|
// }
|
32
usb_driver.h
32
usb_driver.h
@ -1,11 +1,11 @@
|
|||||||
#ifndef CORE_USB_USB_DRIVER
|
#ifndef CORE_USB_USB_DRIVER
|
||||||
#define CORE_USB_USB_DRIVER
|
#define CORE_USB_USB_DRIVER
|
||||||
|
|
||||||
//#include "utils/gen_queue.h"
|
// #include "utils/gen_queue.h"
|
||||||
|
|
||||||
#include "usb_common_types.h"
|
#include "usb_common_types.h"
|
||||||
|
|
||||||
//#define USBDBGMSG
|
// #define USBDBGMSG
|
||||||
|
|
||||||
#define USB_NUM_OF_ENDPOINTS (4)
|
#define USB_NUM_OF_ENDPOINTS (4)
|
||||||
|
|
||||||
@ -14,6 +14,15 @@
|
|||||||
|
|
||||||
#define USB_MIN_EP_FIFO_SIZE (64)
|
#define USB_MIN_EP_FIFO_SIZE (64)
|
||||||
|
|
||||||
|
// Unfortunately this cannot be enabled, since the USB controller
|
||||||
|
// generates such enormous amounts of interrupts, so that no other
|
||||||
|
// task can run along the USB processing.
|
||||||
|
#define USB_EVENT_PROCESSING_IN_OS_THREAD (0)
|
||||||
|
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// endpoint configuration structure
|
// endpoint configuration structure
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t max_packet_size; // maximum packet size
|
uint16_t max_packet_size; // maximum packet size
|
||||||
@ -26,7 +35,10 @@ typedef struct {
|
|||||||
uint8_t is_configured; // the endpoint is in use
|
uint8_t is_configured; // the endpoint is in use
|
||||||
uint16_t fifo_address; // address in the FIFO
|
uint16_t fifo_address; // address in the FIFO
|
||||||
uint16_t fifo_size; // FIFO size
|
uint16_t fifo_size; // FIFO size
|
||||||
bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer
|
bool8_t auto_zlp; // automatically insert ZLP packets
|
||||||
|
bool8_t zlp_next; // indicates, that ZLP should be transmitted at the end of the current transfer (for IN endpoints)
|
||||||
|
bool8_t autoarm; // automatically arm endpoint (for OUT endpoints)
|
||||||
|
//bool8_t txp; // transfer in progress
|
||||||
} USBDRV_EpConfig;
|
} USBDRV_EpConfig;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -58,8 +70,11 @@ typedef struct {
|
|||||||
uint16_t state; // FSM state
|
uint16_t state; // FSM state
|
||||||
uint8_t *rx_buf; // pointer to the receive buffer (this way declaration can be separated)
|
uint8_t *rx_buf; // pointer to the receive buffer (this way declaration can be separated)
|
||||||
uint16_t rx_buf_level; // fill level of the rx buffer
|
uint16_t rx_buf_level; // fill level of the rx buffer
|
||||||
// Queue *event_queue; // event queue
|
|
||||||
uint8_t address; // device address
|
uint8_t address; // device address
|
||||||
|
#if USB_EVENT_PROCESSING_IN_OS_THREAD
|
||||||
|
osMessageQueueId_t event_queue; // event queue
|
||||||
|
osThreadId_t th; // event processing thread
|
||||||
|
#endif
|
||||||
} USBDRV_GlobalState;
|
} USBDRV_GlobalState;
|
||||||
|
|
||||||
// USB received packet status
|
// USB received packet status
|
||||||
@ -90,8 +105,8 @@ typedef struct {
|
|||||||
|
|
||||||
// callback codes
|
// callback codes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
USB_CBC_OUT, // OUT done!
|
USB_CBC_OUT, // OUT done!
|
||||||
USB_CBC_IN_DONE, // IN done!
|
USB_CBC_IN_DONE, // IN done!
|
||||||
USB_CBC_IN_FIFOEMPTY, // could not serve IN request, since Tx FIFO was empty
|
USB_CBC_IN_FIFOEMPTY, // could not serve IN request, since Tx FIFO was empty
|
||||||
} USBDRV_CallbackCode;
|
} USBDRV_CallbackCode;
|
||||||
|
|
||||||
@ -138,7 +153,10 @@ void usbdrv_process_rx_fifo_top(USBDRV_EventData *evt_data); // see what's on to
|
|||||||
|
|
||||||
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len); // write data to specific endpoint FIFO
|
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len); // write data to specific endpoint FIFO
|
||||||
#define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0)
|
#define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0)
|
||||||
void usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint
|
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint8_t size); // arm OUT endpoint, returned with the actual armed size (capped by the max packet size on that endpoint)
|
||||||
|
void usbdrv_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer
|
||||||
|
void usbdrv_enable_autozlp(uint8_t ep, bool en); // enable or disable automatic ZLP appending to the transaction
|
||||||
|
|
||||||
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag
|
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag
|
||||||
|
|
||||||
void usbdrv_set_address(uint8_t addr); // set device address
|
void usbdrv_set_address(uint8_t addr); // set device address
|
||||||
|
Loading…
x
Reference in New Issue
Block a user