- 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;
 | 
			
		||||
 | 
			
		||||
                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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case USB_CBEVT_IN: {
 | 
			
		||||
            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;
 | 
			
		||||
            } 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;
 | 
			
		||||
                
 | 
			
		||||
                // read from the fifo
 | 
			
		||||
                uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE);
 | 
			
		||||
                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
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -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 <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 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) {
 | 
			
		||||
    // clear the state
 | 
			
		||||
    memset(&eems, 0, sizeof(USB_EemState));
 | 
			
		||||
@ -13,21 +33,81 @@ void usb_eem_init(uint8_t data_ep) {
 | 
			
		||||
    // store data endpoint number
 | 
			
		||||
    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
 | 
			
		||||
    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) {
 | 
			
		||||
    switch (cbevt->type) {
 | 
			
		||||
    case USB_CBEVT_UNKNOWN_REQ:
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    case USB_CBEVT_IN:
 | 
			
		||||
        if (cbevt->ep == eems.data_ep) { // verify endpoint number
 | 
			
		||||
            usbcore_write(eems.data_ep, NULL, 0); // send ZLP
 | 
			
		||||
        if (cbevt->ep == eems.data_ep) {                                                                // verify endpoint number
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
@ -37,3 +117,196 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
 | 
			
		||||
 | 
			
		||||
    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 <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 {
 | 
			
		||||
    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
 | 
			
		||||
    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
 | 
			
		||||
    osThreadId_t th; // EEM thread
 | 
			
		||||
} USB_EemState;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -23,4 +72,10 @@ void usb_eem_init(uint8_t data_ep);
 | 
			
		||||
*/
 | 
			
		||||
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 */
 | 
			
		||||
 | 
			
		||||
@ -60,18 +60,41 @@
 | 
			
		||||
              "direction": "in",
 | 
			
		||||
              "transfer_type": "bulk",
 | 
			
		||||
              "max_packet_size": 64,
 | 
			
		||||
              "service_interval": 0
 | 
			
		||||
              "service_interval": 20
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              "n": 1,
 | 
			
		||||
              "direction": "out",
 | 
			
		||||
              "transfer_type": "bulk",
 | 
			
		||||
              "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"
 | 
			
		||||
 | 
			
		||||
const USB_StrDesc_lang_id lang_id = {
 | 
			
		||||
    /* String descriptor */
 | 
			
		||||
    0x4,       // bLength
 | 
			
		||||
    UD_String, // bDescriptorType
 | 
			
		||||
    0x409,     // bString
 | 
			
		||||
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_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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 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 = {
 | 
			
		||||
    {
 | 
			
		||||
        /* Configuration descriptor */
 | 
			
		||||
        0x9,                                 // bLength
 | 
			
		||||
        UD_Configuration,                    // bDescriptorType
 | 
			
		||||
        sizeof(struct _FullConfigurations0), // wTotalLength
 | 
			
		||||
        0x2,                                 // bNumInterfaces
 | 
			
		||||
        0x1,                                 // bConfigurationValue
 | 
			
		||||
        0x0,                                 // iConfiguration
 | 
			
		||||
        USB_CONFIG_ATTR_USB1_1_FLAG,         // bmAttributes
 | 
			
		||||
        0x32,                                // bMaxPower
 | 
			
		||||
    },                                       // config
 | 
			
		||||
    {
 | 
			
		||||
        /* Interface descriptor : 0 */
 | 
			
		||||
        0x9,          // bLength
 | 
			
		||||
        UD_Interface, // bDescriptorType
 | 
			
		||||
        0x0,          // bInterfaceNumber
 | 
			
		||||
        0x0,          // bAlternateSetting
 | 
			
		||||
        0x1,          // bNumEndpoints
 | 
			
		||||
        0x2,          // bInterfaceClass
 | 
			
		||||
        0x2,          // bInterfaceSubclass
 | 
			
		||||
        0x1,          // bInterfaceProtocol
 | 
			
		||||
        0x0,          // iInterface
 | 
			
		||||
    },                // intf0
 | 
			
		||||
    {
 | 
			
		||||
        /* Header Functional descriptor */
 | 
			
		||||
        0x5,   // bLength
 | 
			
		||||
        0x24,  // bDescriptorType
 | 
			
		||||
        0x0,   // bDescriptorSubType
 | 
			
		||||
        0x110, // bcdCDC
 | 
			
		||||
    },         // intf0hfd
 | 
			
		||||
    {
 | 
			
		||||
        /* Abstract Control Management Functional descriptor */
 | 
			
		||||
        0x4,  // bLength
 | 
			
		||||
        0x24, // bDescriptorType
 | 
			
		||||
        0x2,  // bDescriptorSubType
 | 
			
		||||
        0x2,  // bmCapabilities
 | 
			
		||||
    },        // intf0acmfd
 | 
			
		||||
    {
 | 
			
		||||
        /* Abstract Control Management Functional descriptor */
 | 
			
		||||
        0x5,  // bLength
 | 
			
		||||
        0x24, // bDescriptorType
 | 
			
		||||
        0x6,  // bDescriptorSubType
 | 
			
		||||
        0x0,  // bMasterInterface
 | 
			
		||||
        0x1,  // bSlaveInterface0
 | 
			
		||||
    },        // intf0ufd
 | 
			
		||||
    {
 | 
			
		||||
        /* Call Management Functional descriptor */
 | 
			
		||||
        0x5,  // bLength
 | 
			
		||||
        0x24, // bDescriptorType
 | 
			
		||||
        0x1,  // bDescriptorSubType
 | 
			
		||||
        0x0,  // bmCapabilities
 | 
			
		||||
        0x1,  // dDataInterface
 | 
			
		||||
    },        // intf0cmfd
 | 
			
		||||
    {
 | 
			
		||||
        /* Endpoint descriptor : 2 in */
 | 
			
		||||
        0x7,                 // bLength
 | 
			
		||||
        UD_Endpoint,         // bDescriptorType
 | 
			
		||||
        (USB_IN << 7) | (2), // bEndpointAddress
 | 
			
		||||
        UT_Interrupt,        // bmAttributes
 | 
			
		||||
        0x40,                // wMaxPacketSize
 | 
			
		||||
        0x2,                 // bInterval
 | 
			
		||||
    },                       // ep2in
 | 
			
		||||
    {
 | 
			
		||||
        /* Interface descriptor : 1 */
 | 
			
		||||
        0x9,          // bLength
 | 
			
		||||
        UD_Interface, // bDescriptorType
 | 
			
		||||
        0x1,          // bInterfaceNumber
 | 
			
		||||
        0x0,          // bAlternateSetting
 | 
			
		||||
        0x2,          // bNumEndpoints
 | 
			
		||||
        0xa,          // bInterfaceClass
 | 
			
		||||
        0x0,          // bInterfaceSubclass
 | 
			
		||||
        0x0,          // bInterfaceProtocol
 | 
			
		||||
        0x0,          // iInterface
 | 
			
		||||
    },                // intf1
 | 
			
		||||
    {
 | 
			
		||||
        /* Endpoint descriptor : 1 in */
 | 
			
		||||
        0x7,                 // bLength
 | 
			
		||||
        UD_Endpoint,         // bDescriptorType
 | 
			
		||||
        (USB_IN << 7) | (1), // bEndpointAddress
 | 
			
		||||
        UT_Bulk,             // bmAttributes
 | 
			
		||||
        0x40,                // wMaxPacketSize
 | 
			
		||||
        0x0,                 // bInterval
 | 
			
		||||
    },                       // ep1in
 | 
			
		||||
    {
 | 
			
		||||
        /* Endpoint descriptor : 1 out */
 | 
			
		||||
        0x7,                  // bLength
 | 
			
		||||
        UD_Endpoint,          // bDescriptorType
 | 
			
		||||
        (USB_OUT << 7) | (1), // bEndpointAddress
 | 
			
		||||
        UT_Bulk,              // bmAttributes
 | 
			
		||||
        0x40,                 // wMaxPacketSize
 | 
			
		||||
        0x0,                  // bInterval
 | 
			
		||||
    },                        // ep1out
 | 
			
		||||
    {                           /* Configuration descriptor */
 | 
			
		||||
     0x9,                       //bLength
 | 
			
		||||
     UD_Configuration,          //bDescriptorType
 | 
			
		||||
     sizeof(struct _FullConfigurations0),       //wTotalLength
 | 
			
		||||
     0x3,                       //bNumInterfaces
 | 
			
		||||
     0x1,                       //bConfigurationValue
 | 
			
		||||
     0x0,                       //iConfiguration
 | 
			
		||||
     USB_CONFIG_ATTR_USB1_1_FLAG,       //bmAttributes
 | 
			
		||||
     0x32,                      //bMaxPower
 | 
			
		||||
     },                         //config
 | 
			
		||||
    {                           /* Interface descriptor : 0 */
 | 
			
		||||
     0x9,                       //bLength
 | 
			
		||||
     UD_Interface,              //bDescriptorType
 | 
			
		||||
     0x0,                       //bInterfaceNumber
 | 
			
		||||
     0x0,                       //bAlternateSetting
 | 
			
		||||
     0x1,                       //bNumEndpoints
 | 
			
		||||
     0x2,                       //bInterfaceClass
 | 
			
		||||
     0x2,                       //bInterfaceSubclass
 | 
			
		||||
     0x1,                       //bInterfaceProtocol
 | 
			
		||||
     0x0,                       //iInterface
 | 
			
		||||
     },                         //intf0
 | 
			
		||||
    {                           /* Header Functional descriptor */
 | 
			
		||||
     0x5,                       //bLength
 | 
			
		||||
     0x24,                      //bDescriptorType
 | 
			
		||||
     0x0,                       //bDescriptorSubType
 | 
			
		||||
     0x110,                     //bcdCDC
 | 
			
		||||
     },                         //intf0hfd
 | 
			
		||||
    {                           /* Abstract Control Management Functional descriptor */
 | 
			
		||||
     0x4,                       //bLength
 | 
			
		||||
     0x24,                      //bDescriptorType
 | 
			
		||||
     0x2,                       //bDescriptorSubType
 | 
			
		||||
     0x2,                       //bmCapabilities
 | 
			
		||||
     },                         //intf0acmfd
 | 
			
		||||
    {                           /* Union Functional descriptor */
 | 
			
		||||
     0x5,                       //bLength
 | 
			
		||||
     0x24,                      //bDescriptorType
 | 
			
		||||
     0x6,                       //bDescriptorSubType
 | 
			
		||||
     0x0,                       //bMasterInterface
 | 
			
		||||
     0x1,                       //bSlaveInterface0
 | 
			
		||||
     },                         //intf0ufd
 | 
			
		||||
    {                           /* Call Management Functional descriptor */
 | 
			
		||||
     0x5,                       //bLength
 | 
			
		||||
     0x24,                      //bDescriptorType
 | 
			
		||||
     0x1,                       //bDescriptorSubType
 | 
			
		||||
     0x0,                       //bmCapabilities
 | 
			
		||||
     0x1,                       //dDataInterface
 | 
			
		||||
     },                         //intf0cmfd
 | 
			
		||||
    {                           /* Endpoint descriptor : 2 in */
 | 
			
		||||
     0x7,                       //bLength
 | 
			
		||||
     UD_Endpoint,               //bDescriptorType
 | 
			
		||||
     (USB_IN << 7) | (2),       //bEndpointAddress
 | 
			
		||||
     UT_Interrupt,              //bmAttributes
 | 
			
		||||
     0x40,                      //wMaxPacketSize
 | 
			
		||||
     0x2,                       //bInterval
 | 
			
		||||
     },                         //ep2in
 | 
			
		||||
    {                           /* Interface descriptor : 1 */
 | 
			
		||||
     0x9,                       //bLength
 | 
			
		||||
     UD_Interface,              //bDescriptorType
 | 
			
		||||
     0x1,                       //bInterfaceNumber
 | 
			
		||||
     0x0,                       //bAlternateSetting
 | 
			
		||||
     0x2,                       //bNumEndpoints
 | 
			
		||||
     0xa,                       //bInterfaceClass
 | 
			
		||||
     0x0,                       //bInterfaceSubclass
 | 
			
		||||
     0x0,                       //bInterfaceProtocol
 | 
			
		||||
     0x0,                       //iInterface
 | 
			
		||||
     },                         //intf1
 | 
			
		||||
    {                           /* Endpoint descriptor : 1 in */
 | 
			
		||||
     0x7,                       //bLength
 | 
			
		||||
     UD_Endpoint,               //bDescriptorType
 | 
			
		||||
     (USB_IN << 7) | (1),       //bEndpointAddress
 | 
			
		||||
     UT_Bulk,                   //bmAttributes
 | 
			
		||||
     0x40,                      //wMaxPacketSize
 | 
			
		||||
     0x14,                      //bInterval
 | 
			
		||||
     },                         //ep1in
 | 
			
		||||
    {                           /* Endpoint descriptor : 1 out */
 | 
			
		||||
     0x7,                       //bLength
 | 
			
		||||
     UD_Endpoint,               //bDescriptorType
 | 
			
		||||
     (USB_OUT << 7) | (1),      //bEndpointAddress
 | 
			
		||||
     UT_Bulk,                   //bmAttributes
 | 
			
		||||
     0x40,                      //wMaxPacketSize
 | 
			
		||||
     0x14,                      //bInterval
 | 
			
		||||
     },                         //ep1out
 | 
			
		||||
    {                           /* Interface descriptor : 2 */
 | 
			
		||||
     0x9,                       //bLength
 | 
			
		||||
     UD_Interface,              //bDescriptorType
 | 
			
		||||
     0x2,                       //bInterfaceNumber
 | 
			
		||||
     0x0,                       //bAlternateSetting
 | 
			
		||||
     0x2,                       //bNumEndpoints
 | 
			
		||||
     0x2,                       //bInterfaceClass
 | 
			
		||||
     0xc,                       //bInterfaceSubclass
 | 
			
		||||
     0x7,                       //bInterfaceProtocol
 | 
			
		||||
     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 = {
 | 
			
		||||
    (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
 | 
			
		||||
#define CORE_USB_DESC_USB_DESC
 | 
			
		||||
#ifndef _USB_DESC_H
 | 
			
		||||
#define _USB_DESC_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_DeviceQualifierDesc devQualDesc;       /* Device Qualifier descriptor */
 | 
			
		||||
typedef struct _USB_HeaderFunctionalDescriptor {
 | 
			
		||||
@ -73,12 +40,15 @@ typedef struct _FullConfigurations0 {
 | 
			
		||||
    USB_InterfaceDesc intf0;    /* Interface descriptor : 0 */
 | 
			
		||||
    USB_HeaderFunctionalDescriptor intf0hfd;    /* Header 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_EndpointDesc ep2in;     /* Endpoint descriptor : 2 in */
 | 
			
		||||
    USB_InterfaceDesc intf1;    /* Interface descriptor : 1 */
 | 
			
		||||
    USB_EndpointDesc ep1in;     /* Endpoint descriptor : 1 in */
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
extern const FullConfigurations0 fullConfDescs0;
 | 
			
		||||
@ -87,5 +57,38 @@ extern const FullConfigurations0 fullConfDescs0;
 | 
			
		||||
 | 
			
		||||
typedef USB_ConfigurationDesc *ConfDescs[1];
 | 
			
		||||
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) {
 | 
			
		||||
 | 
			
		||||
    //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))
 | 
			
		||||
 | 
			
		||||
    switch (stups.next_stage) {
 | 
			
		||||
        case UST_SETUP: {             // expecting SETUP stage
 | 
			
		||||
            if (stage == UST_SETUP) { // SETUP received
 | 
			
		||||
                // save setup request
 | 
			
		||||
                stups.setup_req = *((USB_SetupRequest *)data);
 | 
			
		||||
    case UST_SETUP: {             // expecting SETUP stage
 | 
			
		||||
        if (stage == UST_SETUP) { // SETUP received
 | 
			
		||||
            // save setup request
 | 
			
		||||
            stups.setup_req = *((USB_SetupRequest *)data);
 | 
			
		||||
 | 
			
		||||
                // if data direction is IN, then don't expect an OUT transaction
 | 
			
		||||
                if ((stups.setup_req.bmRequestType.fields.dir == USB_IN) ||
 | 
			
		||||
                    ((stups.setup_req.bmRequestType.fields.dir == USB_OUT) && (stups.setup_req.wLength == 0))) {
 | 
			
		||||
                    stups.out_complete = true; // DATA stage is IN
 | 
			
		||||
                } else {
 | 
			
		||||
                    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
 | 
			
		||||
                }
 | 
			
		||||
            // if data direction is IN, then don't expect an OUT transaction
 | 
			
		||||
            if ((stups.setup_req.bmRequestType.fields.dir == USB_IN) ||
 | 
			
		||||
                ((stups.setup_req.bmRequestType.fields.dir == USB_OUT) && (stups.setup_req.wLength == 0))) {
 | 
			
		||||
                stups.out_complete = true; // DATA stage is IN
 | 
			
		||||
            } else {
 | 
			
		||||
                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
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case UST_DATA: {             // expecting DATA stage
 | 
			
		||||
        if (stage == UST_DATA) { // DATA received
 | 
			
		||||
            stups.out_complete = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case UST_DATA: {             // expecting DATA stage
 | 
			
		||||
            if (stage == UST_DATA) { // DATA received
 | 
			
		||||
                stups.out_complete = true;
 | 
			
		||||
            }
 | 
			
		||||
        // step into SETUP state
 | 
			
		||||
        stups.next_stage = UST_SETUP;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
            // step into SETUP state
 | 
			
		||||
            stups.next_stage = UST_SETUP;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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)
 | 
			
		||||
 | 
			
		||||
    switch (stups.setup_req.bRequest) {
 | 
			
		||||
        case UREQ_GetDescriptor: // GET DESCRIPTOR
 | 
			
		||||
        {
 | 
			
		||||
            // which descriptor?
 | 
			
		||||
            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 sz = 0;
 | 
			
		||||
            const uint8_t *data = NULL;
 | 
			
		||||
    case UREQ_GetDescriptor: // GET DESCRIPTOR
 | 
			
		||||
    {
 | 
			
		||||
        // which descriptor?
 | 
			
		||||
        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 sz = 0;
 | 
			
		||||
        const uint8_t *data = NULL;
 | 
			
		||||
 | 
			
		||||
            switch (desc_type) {
 | 
			
		||||
                case UD_Device: // DEVICE DESCRIPTOR
 | 
			
		||||
                    DETERMINE_TRANSFER_SIZE(devDesc.bLength);
 | 
			
		||||
                    SET_TRANSMISSION_POINTER(&devDesc);
 | 
			
		||||
                    break;
 | 
			
		||||
                case UD_Configuration: // CONFIGURATION DESCRIPTOR
 | 
			
		||||
                    DETERMINE_TRANSFER_SIZE(confDescs[desc_index]->wTotalLength);
 | 
			
		||||
                    SET_TRANSMISSION_POINTER(confDescs[desc_index]);
 | 
			
		||||
                    break;
 | 
			
		||||
                case UD_String: // STRING DESCRIPTOR
 | 
			
		||||
                    DETERMINE_TRANSFER_SIZE(strDescs[desc_index]->bLength);
 | 
			
		||||
                    SET_TRANSMISSION_POINTER(strDescs[desc_index]);
 | 
			
		||||
                    break;
 | 
			
		||||
                case UD_DeviceQualifier:
 | 
			
		||||
                    DETERMINE_TRANSFER_SIZE(devQualDesc.bLength);
 | 
			
		||||
                    SET_TRANSMISSION_POINTER(&devQualDesc);
 | 
			
		||||
                    break;
 | 
			
		||||
                // Descriptors not implemented
 | 
			
		||||
                default:
 | 
			
		||||
                    usbdrv_stall_endpoint(0, USB_IN, true); // stall IN, since request in unsupported
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // arm data transmission
 | 
			
		||||
            usbdrv_arm_IN_endpoint(0, data, sz);
 | 
			
		||||
        switch (desc_type) {
 | 
			
		||||
        case UD_Device: // DEVICE DESCRIPTOR
 | 
			
		||||
            DETERMINE_TRANSFER_SIZE(devDesc.bLength);
 | 
			
		||||
            SET_TRANSMISSION_POINTER(&devDesc);
 | 
			
		||||
            break;
 | 
			
		||||
        case UD_Configuration: // CONFIGURATION DESCRIPTOR
 | 
			
		||||
            DETERMINE_TRANSFER_SIZE(confDescs[desc_index]->wTotalLength);
 | 
			
		||||
            SET_TRANSMISSION_POINTER(confDescs[desc_index]);
 | 
			
		||||
            break;
 | 
			
		||||
        case UD_String: // STRING DESCRIPTOR
 | 
			
		||||
            DETERMINE_TRANSFER_SIZE(strDescs[desc_index]->bLength);
 | 
			
		||||
            SET_TRANSMISSION_POINTER(strDescs[desc_index]);
 | 
			
		||||
            break;
 | 
			
		||||
        case UD_DeviceQualifier:
 | 
			
		||||
            DETERMINE_TRANSFER_SIZE(devQualDesc.bLength);
 | 
			
		||||
            SET_TRANSMISSION_POINTER(&devQualDesc);
 | 
			
		||||
            break;
 | 
			
		||||
        // Descriptors not implemented
 | 
			
		||||
        default:
 | 
			
		||||
            usbdrv_stall_endpoint(0, USB_IN, true); // stall IN, since request in unsupported
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case UREQ_SetAddress: { // SET ADDRESS
 | 
			
		||||
            uint8_t addr = stups.setup_req.wValue & 0x7F;
 | 
			
		||||
            usbdrv_set_address(addr);
 | 
			
		||||
            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);
 | 
			
		||||
        // arm data transmission
 | 
			
		||||
        usbdrv_arm_IN_endpoint(0, data, sz);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
            if (cbevt.reply_valid) {
 | 
			
		||||
                usbdrv_arm_IN_endpoint(0, cbevt.reply_data, cbevt.reply_size);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
    case UREQ_SetAddress: { // SET ADDRESS
 | 
			
		||||
        uint8_t addr = stups.setup_req.wValue & 0x7F;
 | 
			
		||||
        usbdrv_set_address(addr);
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
 | 
			
		||||
    USB_CallbackEvent cbevt = { 0 }; // allocate and clear structure...
 | 
			
		||||
    cbevt.ep = cbcpd->ep; // later only fill nonzero fields
 | 
			
		||||
    USB_CallbackEvent cbevt = {0}; // allocate and clear structure...
 | 
			
		||||
    cbevt.ep = cbcpd->ep;          // later only fill nonzero fields
 | 
			
		||||
 | 
			
		||||
    bool discard_event = false; // only discard if event does not fit any category above
 | 
			
		||||
    switch (cbcpd->code) {
 | 
			
		||||
        case USB_CBC_OUT: {
 | 
			
		||||
            cbevt.type = USB_CBEVT_OUT;
 | 
			
		||||
            cbevt.data = cbcpd->data;
 | 
			
		||||
            cbevt.size = cbcpd->size;
 | 
			
		||||
            cbevt.dir = USB_OUT;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case USB_CBC_IN_FIFOEMPTY:
 | 
			
		||||
        case USB_CBC_IN_DONE: {
 | 
			
		||||
            cbevt.type = USB_CBEVT_IN;
 | 
			
		||||
            if (cbcpd->code == USB_CBC_IN_FIFOEMPTY) { // signals a failed in transfer
 | 
			
		||||
                cbevt.subtype = USB_CBEVST_IN_REQ;
 | 
			
		||||
            }
 | 
			
		||||
            cbevt.dir = USB_IN;
 | 
			
		||||
            break;
 | 
			
		||||
    case USB_CBC_OUT: {
 | 
			
		||||
        cbevt.type = USB_CBEVT_OUT;
 | 
			
		||||
        cbevt.data = cbcpd->data;
 | 
			
		||||
        cbevt.size = cbcpd->size;
 | 
			
		||||
        cbevt.dir = USB_OUT;
 | 
			
		||||
        cbevt.arm_out_endpoint = true;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case USB_CBC_IN_FIFOEMPTY:
 | 
			
		||||
    case USB_CBC_IN_DONE: {
 | 
			
		||||
        cbevt.type = USB_CBEVT_IN;
 | 
			
		||||
        if (cbcpd->code == USB_CBC_IN_FIFOEMPTY) { // signals a failed in transfer
 | 
			
		||||
            cbevt.subtype = USB_CBEVST_IN_REQ;
 | 
			
		||||
        }
 | 
			
		||||
        cbevt.dir = USB_IN;
 | 
			
		||||
        cbevt.enable_autozlp = true; // by default, enable auto ZLP
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            discard_event = true;
 | 
			
		||||
            break;
 | 
			
		||||
    default:
 | 
			
		||||
        discard_event = true;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if event is not ment to be discarded, then invoke event callback
 | 
			
		||||
    if (!discard_event) {
 | 
			
		||||
        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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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"
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,8 @@ typedef struct {
 | 
			
		||||
    bool reply_valid; // reply message is valid
 | 
			
		||||
    const uint8_t * reply_data; // reply data
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
void usbdrv_init_global_state() {
 | 
			
		||||
    // clear state
 | 
			
		||||
@ -103,8 +107,18 @@ void usbdrv_init_global_state() {
 | 
			
		||||
    gs.rx_buf = rx_buf;
 | 
			
		||||
    gs.rx_buf_level = 0;
 | 
			
		||||
 | 
			
		||||
#if USB_EVENT_PROCESSING_IN_OS_THREAD
 | 
			
		||||
    // 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_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_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
 | 
			
		||||
@ -244,7 +261,7 @@ void usbdrv_fetch_endpoint_configuration(uint8_t config_index) {
 | 
			
		||||
#define USB_MIN_FIFO_SIZE (64)
 | 
			
		||||
#define USB_FIFO_MARGIN (8)
 | 
			
		||||
#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)
 | 
			
		||||
 | 
			
		||||
// build FIFO (compute addresses)
 | 
			
		||||
@ -265,10 +282,12 @@ void usbdrv_build_fifo() {
 | 
			
		||||
    for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) {
 | 
			
		||||
        USBDRV_EpConfig *cfg = &gs.ep_IN[i];
 | 
			
		||||
        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_address = next_fifo_addr;                                                                  // store FIFO address
 | 
			
		||||
            cfg->zlp_next = false;                                                                               // clear ZLP next
 | 
			
		||||
            next_fifo_addr += cfg->fifo_size;                                                                    // advance next address
 | 
			
		||||
            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->auto_zlp = true;                                                              // turn on automatic ZLP appending
 | 
			
		||||
            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
 | 
			
		||||
        if (cfg->responding_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_PKTCNT, 1);*/
 | 
			
		||||
 | 
			
		||||
    // transmission may only be commenced if last transmission has concluded
 | 
			
		||||
    if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
 | 
			
		||||
    // 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 = 0;
 | 
			
		||||
    // if (len > 0) { // only poll DTXFSTS if (len > 0) (see datasheet)
 | 
			
		||||
    freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
 | 
			
		||||
    //}
 | 
			
		||||
    uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
 | 
			
		||||
    uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
 | 
			
		||||
    uint16_t writeSize = 0;
 | 
			
		||||
 | 
			
		||||
    // calculate packet count based on max packet size
 | 
			
		||||
    uint16_t mps = gs.ep_IN[ep].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);
 | 
			
		||||
    if (txp) {                                                                    // transaction is in progress
 | 
			
		||||
        uint32_t remainingBytes = USBINEP[ep].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ; // acquire remaining bytes
 | 
			
		||||
        if (len >= mps) {                                                         // write only full-sized packets, or a short packet
 | 
			
		||||
            uint16_t mws = MIN(freeSize, len);                                    // maximum possible write size
 | 
			
		||||
            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
 | 
			
		||||
    gs.ep_IN[ep].zlp_next = (writeSize > 0) && ((writeSize % mps) == 0);
 | 
			
		||||
    // if no transmission is in progress
 | 
			
		||||
    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
 | 
			
		||||
    USBINEP[ep].DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) | (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
 | 
			
		||||
        // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
 | 
			
		||||
        gs.ep_IN[ep].zlp_next = (len > 0) && ((len % mps) == 0);
 | 
			
		||||
 | 
			
		||||
    // enable endpoint and cancel responding NAK
 | 
			
		||||
    SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
 | 
			
		||||
        // 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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)
 | 
			
		||||
    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
 | 
			
		||||
    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;
 | 
			
		||||
        *p = 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
 | 
			
		||||
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
 | 
			
		||||
    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
 | 
			
		||||
// void usbdrv_push_event(uint32_t evt_code, USBDRV_EventData *evt_data) {
 | 
			
		||||
//     USBDRV_EventCompound evt_cpd;
 | 
			
		||||
//     if (evt_data != NULL) {
 | 
			
		||||
//         evt_cpd.data = *evt_data;
 | 
			
		||||
//     }
 | 
			
		||||
//     evt_cpd.code = evt_code;
 | 
			
		||||
//     q_push(gs.event_queue, &evt_cpd);
 | 
			
		||||
// }
 | 
			
		||||
void usbdrv_push_event(uint32_t evt_code, USBDRV_EventData *evt_data) {
 | 
			
		||||
    USBDRV_EventCompound evt_cpd;
 | 
			
		||||
    if (evt_data != NULL) {
 | 
			
		||||
        evt_cpd.data = *evt_data;
 | 
			
		||||
    }
 | 
			
		||||
    evt_cpd.code = evt_code;
 | 
			
		||||
    osMessageQueuePut(gs.event_queue, &evt_cpd, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// // call this to process incoming events
 | 
			
		||||
// void usbdrv_periodic_processing() {
 | 
			
		||||
//     if ((gs.event_queue != NULL) && (q_avail(gs.event_queue))) {
 | 
			
		||||
//         USBDRV_EventCompound evt_cpd;
 | 
			
		||||
//         q_top(gs.event_queue, &evt_cpd);
 | 
			
		||||
//         q_pop(gs.event_queue);
 | 
			
		||||
//         usbdrv_process_event(evt_cpd.code, NULL);
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
static void usbdrv_thread(void *param) {
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        USBDRV_EventCompound evt_cpd;
 | 
			
		||||
        osMessageQueueGet(gs.event_queue, &evt_cpd, 0, osWaitForever);
 | 
			
		||||
        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);
 | 
			
		||||
                        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
 | 
			
		||||
                        SET_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_TOC);
 | 
			
		||||
                        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);
 | 
			
		||||
 | 
			
		||||
                        // 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
 | 
			
		||||
                        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
 | 
			
		||||
                        } else {                                 // no ZLP
 | 
			
		||||
                            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;
 | 
			
		||||
                            usbcore_process_nonsetup_event(&cbcpd);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (READ_BIT(USBINEP[ep].DIEPINT, USB_OTG_DIEPINT_ITTXFE)) { // IN endpoint IN token received with Tx FIFO empty interrupt
 | 
			
		||||
                    } else 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);
 | 
			
		||||
 | 
			
		||||
                        // USBMSG("IN FIFOEMPTY [%d]\n", ep);
 | 
			
		||||
 | 
			
		||||
                        // transfer finished
 | 
			
		||||
                        // gs.ep_IN[ep].txp = false;
 | 
			
		||||
 | 
			
		||||
                        cbcpd.code = USB_CBC_IN_FIFOEMPTY;
 | 
			
		||||
                        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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() {
 | 
			
		||||
 | 
			
		||||
    uint32_t ints = USBG->GINTSTS;
 | 
			
		||||
 | 
			
		||||
    // USB reset
 | 
			
		||||
@ -753,15 +844,16 @@ void OTG_FS_IRQHandler() {
 | 
			
		||||
    // ST calls speed negotiation the enumeration, normally this
 | 
			
		||||
    // interrupt fires only before even communication is commenced)
 | 
			
		||||
    if (ints & USB_OTG_GINTSTS_ENUMDNE) {
 | 
			
		||||
        SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_ENUMDNE);   // clear interrupt
 | 
			
		||||
        usbdrv_process_event(USB_EVT_SPEEDNEG_DONE, NULL); // process event
 | 
			
		||||
        // usbdrv_push_event(USB_EVT_SPEEDNEG_DONE, NULL); // push event
 | 
			
		||||
        SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_ENUMDNE); // clear interrupt
 | 
			
		||||
        PROCESS_EVENT(USB_EVT_SPEEDNEG_DONE, NULL);      // process 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)
 | 
			
		||||
    // if (ints & USB_OTG_GINTSTS_SOF) {
 | 
			
		||||
    //     SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_SOF); // clear interrupt
 | 
			
		||||
    // }
 | 
			
		||||
    if (ints & USB_OTG_GINTSTS_SOF) {
 | 
			
		||||
        SET_BIT(USBG->GINTSTS, USB_OTG_GINTSTS_SOF); // clear interrupt
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // USB Suspend
 | 
			
		||||
    if (ints & USB_OTG_GINTSTS_USBSUSP) {
 | 
			
		||||
@ -771,7 +863,7 @@ void OTG_FS_IRQHandler() {
 | 
			
		||||
 | 
			
		||||
    // OUT endpoint interrupt
 | 
			
		||||
    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);
 | 
			
		||||
        //  if (USBD->DAINT & (1 << 16)) {
 | 
			
		||||
        //      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
 | 
			
		||||
        USBMSG("RX DONE\n");
 | 
			
		||||
        // 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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // IN endpoint interrupt
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
#define CORE_USB_USB_DRIVER
 | 
			
		||||
 | 
			
		||||
//#include "utils/gen_queue.h"
 | 
			
		||||
// #include "utils/gen_queue.h"
 | 
			
		||||
 | 
			
		||||
#include "usb_common_types.h"
 | 
			
		||||
 | 
			
		||||
//#define USBDBGMSG
 | 
			
		||||
// #define USBDBGMSG
 | 
			
		||||
 | 
			
		||||
#define USB_NUM_OF_ENDPOINTS (4)
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,15 @@
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t max_packet_size; // maximum packet size
 | 
			
		||||
@ -26,7 +35,10 @@ typedef struct {
 | 
			
		||||
    uint8_t is_configured; // the endpoint is in use
 | 
			
		||||
    uint16_t fifo_address; // address in the FIFO
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
@ -58,8 +70,11 @@ typedef struct {
 | 
			
		||||
    uint16_t state;                               // FSM state
 | 
			
		||||
    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
 | 
			
		||||
    // Queue *event_queue;                           // event queue
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
// USB received packet status
 | 
			
		||||
@ -90,8 +105,8 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
// callback codes
 | 
			
		||||
typedef enum {
 | 
			
		||||
    USB_CBC_OUT, // OUT done!
 | 
			
		||||
    USB_CBC_IN_DONE, // IN done!
 | 
			
		||||
    USB_CBC_OUT,          // OUT done!
 | 
			
		||||
    USB_CBC_IN_DONE,      // IN done!
 | 
			
		||||
    USB_CBC_IN_FIFOEMPTY, // could not serve IN request, since Tx FIFO was empty
 | 
			
		||||
} 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
 | 
			
		||||
#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
 | 
			
		||||
 | 
			
		||||
void usbdrv_set_address(uint8_t addr); // set device address
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user