- 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)
|
||||
|
||||
// ----------------
|
||||
|
||||
|
275
class/eem.c
275
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 ((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,14 +60,37 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
159
desc/usb_desc.c
159
desc/usb_desc.c
@ -1,66 +1,6 @@
|
||||
#include "usb_desc.h"
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
const USB_DeviceDesc devDesc = {
|
||||
/* Device Descriptor */
|
||||
const USB_DeviceDesc devDesc = { /* Device Descriptor */
|
||||
0x12, //bLength
|
||||
UD_Device, //bDescriptorType
|
||||
0x200, //bcdUSB
|
||||
@ -77,8 +17,7 @@ const USB_DeviceDesc devDesc = {
|
||||
0x1, //bNumConfigurations
|
||||
};
|
||||
|
||||
const USB_DeviceQualifierDesc devQualDesc = {
|
||||
/* Device Qualifier descriptor */
|
||||
const USB_DeviceQualifierDesc devQualDesc = { /* Device Qualifier descriptor */
|
||||
0x9, //bLength
|
||||
UD_DeviceQualifier, //bDescriptorType
|
||||
0x200, //bcdUSB
|
||||
@ -90,19 +29,17 @@ const USB_DeviceQualifierDesc devQualDesc = {
|
||||
};
|
||||
|
||||
const FullConfigurations0 fullConfDescs0 = {
|
||||
{
|
||||
/* Configuration descriptor */
|
||||
{ /* Configuration descriptor */
|
||||
0x9, //bLength
|
||||
UD_Configuration, //bDescriptorType
|
||||
sizeof(struct _FullConfigurations0), //wTotalLength
|
||||
0x2, // bNumInterfaces
|
||||
0x3, //bNumInterfaces
|
||||
0x1, //bConfigurationValue
|
||||
0x0, //iConfiguration
|
||||
USB_CONFIG_ATTR_USB1_1_FLAG, //bmAttributes
|
||||
0x32, //bMaxPower
|
||||
}, //config
|
||||
{
|
||||
/* Interface descriptor : 0 */
|
||||
{ /* Interface descriptor : 0 */
|
||||
0x9, //bLength
|
||||
UD_Interface, //bDescriptorType
|
||||
0x0, //bInterfaceNumber
|
||||
@ -113,38 +50,33 @@ const FullConfigurations0 fullConfDescs0 = {
|
||||
0x1, //bInterfaceProtocol
|
||||
0x0, //iInterface
|
||||
}, //intf0
|
||||
{
|
||||
/* Header Functional descriptor */
|
||||
{ /* Header Functional descriptor */
|
||||
0x5, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x0, //bDescriptorSubType
|
||||
0x110, //bcdCDC
|
||||
}, //intf0hfd
|
||||
{
|
||||
/* Abstract Control Management Functional descriptor */
|
||||
{ /* Abstract Control Management Functional descriptor */
|
||||
0x4, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x2, //bDescriptorSubType
|
||||
0x2, //bmCapabilities
|
||||
}, //intf0acmfd
|
||||
{
|
||||
/* Abstract Control Management Functional descriptor */
|
||||
{ /* Union Functional descriptor */
|
||||
0x5, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x6, //bDescriptorSubType
|
||||
0x0, //bMasterInterface
|
||||
0x1, //bSlaveInterface0
|
||||
}, //intf0ufd
|
||||
{
|
||||
/* Call Management Functional descriptor */
|
||||
{ /* Call Management Functional descriptor */
|
||||
0x5, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x1, //bDescriptorSubType
|
||||
0x0, //bmCapabilities
|
||||
0x1, //dDataInterface
|
||||
}, //intf0cmfd
|
||||
{
|
||||
/* Endpoint descriptor : 2 in */
|
||||
{ /* Endpoint descriptor : 2 in */
|
||||
0x7, //bLength
|
||||
UD_Endpoint, //bDescriptorType
|
||||
(USB_IN << 7) | (2), //bEndpointAddress
|
||||
@ -152,8 +84,7 @@ const FullConfigurations0 fullConfDescs0 = {
|
||||
0x40, //wMaxPacketSize
|
||||
0x2, //bInterval
|
||||
}, //ep2in
|
||||
{
|
||||
/* Interface descriptor : 1 */
|
||||
{ /* Interface descriptor : 1 */
|
||||
0x9, //bLength
|
||||
UD_Interface, //bDescriptorType
|
||||
0x1, //bInterfaceNumber
|
||||
@ -164,26 +95,82 @@ const FullConfigurations0 fullConfDescs0 = {
|
||||
0x0, //bInterfaceProtocol
|
||||
0x0, //iInterface
|
||||
}, //intf1
|
||||
{
|
||||
/* Endpoint descriptor : 1 in */
|
||||
{ /* Endpoint descriptor : 1 in */
|
||||
0x7, //bLength
|
||||
UD_Endpoint, //bDescriptorType
|
||||
(USB_IN << 7) | (1), //bEndpointAddress
|
||||
UT_Bulk, //bmAttributes
|
||||
0x40, //wMaxPacketSize
|
||||
0x0, // bInterval
|
||||
0x14, //bInterval
|
||||
}, //ep1in
|
||||
{
|
||||
/* Endpoint descriptor : 1 out */
|
||||
{ /* Endpoint descriptor : 1 out */
|
||||
0x7, //bLength
|
||||
UD_Endpoint, //bDescriptorType
|
||||
(USB_OUT << 7) | (1), //bEndpointAddress
|
||||
UT_Bulk, //bmAttributes
|
||||
0x40, //wMaxPacketSize
|
||||
0x0, // bInterval
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
|
17
usb.c
17
usb.c
@ -205,6 +205,7 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
|
||||
cbevt.data = cbcpd->data;
|
||||
cbevt.size = cbcpd->size;
|
||||
cbevt.dir = USB_OUT;
|
||||
cbevt.arm_out_endpoint = true;
|
||||
break;
|
||||
}
|
||||
case USB_CBC_IN_FIFOEMPTY:
|
||||
@ -214,6 +215,7 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
|
||||
cbevt.subtype = USB_CBEVST_IN_REQ;
|
||||
}
|
||||
cbevt.dir = USB_IN;
|
||||
cbevt.enable_autozlp = true; // by default, enable auto ZLP
|
||||
break;
|
||||
}
|
||||
|
||||
@ -225,9 +227,22 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
|
||||
// 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 */
|
||||
|
365
usb_driver.c
365
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,9 +282,11 @@ 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_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->zlp_next = false; // clear ZLP next
|
||||
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
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// program DIEPTSIZ with transfer length
|
||||
USBINEP[ep].DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) | (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
|
||||
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
|
||||
@ -754,14 +845,15 @@ void OTG_FS_IRQHandler() {
|
||||
// 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
|
||||
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;
|
||||
// }
|
24
usb_driver.h
24
usb_driver.h
@ -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
|
||||
@ -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