- auto ZLP reconsidered and removed, ZLP is always appended to transfers featuring a size divisible by max packet size

- EEM tweaked
This commit is contained in:
Wiesner András 2024-05-01 18:33:22 +02:00
parent 6406222be3
commit f6e3d48476
6 changed files with 28 additions and 200 deletions

View File

@ -14,16 +14,14 @@
static USB_EemState eems = {0}; static USB_EemState eems = {0};
static uint8_t netbBuf[USB_EEM_FIFO_SIZE]; // Network bound FIFO memory // static uint8_t netbBuf[USB_EEM_FIFO_SIZE]; // Network bound FIFO memory
static uint8_t hostbBuf[USB_EEM_FIFO_SIZE]; // Host bound FIFO memory static uint8_t hostbBuf[USB_EEM_FIFO_SIZE]; // Host bound FIFO memory
#define EEM_EVENT_QUEUE_LENGTH (16) #define EEM_EVENT_QUEUE_LENGTH (16)
#define EEM_FRAME_QUEUE_LENGTH (24) #define EEM_FRAME_QUEUE_LENGTH (8)
#define EEM_PCKT_SIZE (64) #define EEM_PCKT_SIZE (64)
#define EEM_TRANSFER_UNIT (128) #define EEM_TRANSFER_UNIT (128)
static uint8_t transferBuffer[EEM_TRANSFER_UNIT]; // transfer buffer
void usb_eem_thread(void *); void usb_eem_thread(void *);
void usb_eem_init(uint8_t data_ep) { void usb_eem_init(uint8_t data_ep) {
@ -37,7 +35,7 @@ void usb_eem_init(uint8_t data_ep) {
eems.eventQueue = osMessageQueueNew(EEM_EVENT_QUEUE_LENGTH, sizeof(uint8_t), NULL); eems.eventQueue = osMessageQueueNew(EEM_EVENT_QUEUE_LENGTH, sizeof(uint8_t), NULL);
// create network bound and host bound FIFOs // create network bound and host bound FIFOs
bfifo_create(&(eems.hostbFifo), netbBuf, USB_EEM_FIFO_SIZE); // bfifo_create(&(eems.hostbFifo), netbBuf, USB_EEM_FIFO_SIZE);
bfifo_create(&(eems.netbFifo), hostbBuf, USB_EEM_FIFO_SIZE); bfifo_create(&(eems.netbFifo), hostbBuf, USB_EEM_FIFO_SIZE);
// create queue for hostbound frames // create queue for hostbound frames
@ -47,6 +45,9 @@ void usb_eem_init(uint8_t data_ep) {
eems.hostbState = EEM_IDLE; eems.hostbState = EEM_IDLE;
eems.netbState = EEM_IDLE; eems.netbState = EEM_IDLE;
// turn network bound autoarm on
eems.netbAutoArm = true;
// no EchoResponse is queued // no EchoResponse is queued
eems.echoRespQueued = false; eems.echoRespQueued = false;
@ -81,6 +82,11 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
if ((cbevt->ep == eems.data_ep)) { // verify endpoint if ((cbevt->ep == eems.data_ep)) { // verify endpoint
bfifo_push(&(eems.netbFifo), cbevt->data, cbevt->size); // store portion of netbound packet bfifo_push(&(eems.netbFifo), cbevt->data, cbevt->size); // store portion of netbound packet
usb_eem_push_event(EEM_EVT_NETBOUND_PCKT_RECEIVED); // push notification usb_eem_push_event(EEM_EVT_NETBOUND_PCKT_RECEIVED); // push notification
if (bfifo_get_free(&eems.netbFifo) < EEM_PCKT_SIZE) { // don't autoarm if OUT no more packets can be stored
eems.netbAutoArm = false;
cbevt->arm_out_endpoint = false;
}
} }
break; break;
@ -101,7 +107,7 @@ int usb_eem_process_and_return(USB_CallbackEvent *cbevt) {
// MSG("---\n"); // MSG("---\n");
// } // }
} else { // no data is waiting for transmission } else { // no data is waiting for transmission
usbcore_schedule_transmission(eems.data_ep, NULL, 0); // send ZLP //usbcore_schedule_transmission(eems.data_ep, NULL, 0); // send ZLP
} }
// if FIFO is empty or flushed, then send notification // if FIFO is empty or flushed, then send notification
@ -208,6 +214,12 @@ void usb_eem_process_networkbound() {
// pop data from the packet // pop data from the packet
bfifo_pop(bf, eems.netbFrameSize, 0); bfifo_pop(bf, eems.netbFrameSize, 0);
// if free size is greater then the size of a single USB packet, then arm the endpoint
if ((eems.netbAutoArm == false) && (bfifo_get_free(bf) > EEM_PCKT_SIZE)) {
eems.netbAutoArm = true;
usbcore_schedule_reception(eems.data_ep, EEM_PCKT_SIZE);
}
// MSG("PKT OK! %u\n", eems.netbFrameSize); // MSG("PKT OK! %u\n", eems.netbFrameSize);
eems.netbState = EEM_IDLE; eems.netbState = EEM_IDLE;
@ -217,11 +229,6 @@ void usb_eem_process_networkbound() {
} }
void usb_eem_process_hostbound() { 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 /*// check that forward buffer is indeed empty
BFifo * bf = &eems.hostbFifo; BFifo * bf = &eems.hostbFifo;
if (bfifo_get_used(bf) > 0) { if (bfifo_get_used(bf) > 0) {
@ -240,6 +247,11 @@ void usb_eem_process_hostbound() {
// release frame // release frame
dynmem_free(oldEemFrame); dynmem_free(oldEemFrame);
// see if there are some packets waiting for transmission
if (osMessageQueueGetCount(eems.hostbFrameQ) == 0) {
return; // no packets
}
// at this point, we can safely pop from the frame queue, popping will not block, // at this point, we can safely pop from the frame queue, popping will not block,
// and the forward queue is certainly empty // and the forward queue is certainly empty

View File

@ -9,7 +9,7 @@
#include <etherlib/etherlib.h> #include <etherlib/etherlib.h>
#define USB_EEM_FIFO_SIZE (2048) #define USB_EEM_FIFO_SIZE (8192)
typedef enum { typedef enum {
EEM_ECHO = 0, // Echo EEM_ECHO = 0, // Echo
@ -44,11 +44,12 @@ typedef struct {
EthInterface * intf; // interface for packet interception and injection EthInterface * intf; // interface for packet interception and injection
uint8_t data_ep; // bulk data in and out endpoint pair uint8_t data_ep; // bulk data in and out endpoint pair
osMessageQueueId_t eventQueue; // event queue osMessageQueueId_t eventQueue; // event queue
BFifo hostbFifo; // Hostbound FIFO // BFifo hostbFifo; // Hostbound FIFO
BFifo netbFifo; // Network bound FIFO BFifo netbFifo; // Network bound FIFO
USB_EemFsmState netbState; // state of host bound operations USB_EemFsmState netbState; // state of host bound operations
uint16_t netbFrameSize; // size of network bound packet uint16_t netbFrameSize; // size of network bound packet
uint16_t netbSizeLeft; // number of bytes expected from the host sending into current network bound packet uint16_t netbSizeLeft; // number of bytes expected from the host sending into current network bound packet
bool netbAutoArm; // signal, that the netbound endpoint should be autoarmed or not
USB_EemFsmState hostbState; // state of network bound operations USB_EemFsmState hostbState; // state of network bound operations
osMessageQueueId_t hostbFrameQ; // queue for hostbound message pointers osMessageQueueId_t hostbFrameQ; // queue for hostbound message pointers
USB_EemFrame * hostbFrame; // hostbound frame USB_EemFrame * hostbFrame; // hostbound frame

3
usb.c
View File

@ -215,7 +215,6 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
cbevt.subtype = USB_CBEVST_IN_REQ; cbevt.subtype = USB_CBEVST_IN_REQ;
} }
cbevt.dir = USB_IN; cbevt.dir = USB_IN;
cbevt.enable_autozlp = true; // by default, enable auto ZLP
break; break;
} }
@ -233,8 +232,6 @@ void usbcore_process_nonsetup_event(USBDRV_CallbackCompound *cbcpd) {
if (cbevt.arm_out_endpoint) { if (cbevt.arm_out_endpoint) {
usbdrv_autoarm_OUT_endpoint(cbcpd->ep); usbdrv_autoarm_OUT_endpoint(cbcpd->ep);
} }
} else if (cbevt.dir == USB_IN) {
usbdrv_enable_autozlp(cbcpd->ep, cbevt.enable_autozlp); // handle auto ZLP setting
} }
} }
} }

View File

@ -29,7 +29,6 @@ typedef struct {
const uint8_t * reply_data; // reply data const uint8_t * reply_data; // reply data
uint8_t reply_size; // reply size uint8_t reply_size; // reply size
bool arm_out_endpoint; // automatically arm OUT endpoint at the end of the current transmission bool arm_out_endpoint; // automatically arm OUT endpoint at the end of the current transmission
bool enable_autozlp; // enable automatic ZLP transmission based on transfer size
} USB_CallbackEvent; } USB_CallbackEvent;
#endif /* CORE_USB_USB_CALLBACK_EVENT */ #endif /* CORE_USB_USB_CALLBACK_EVENT */

View File

@ -284,7 +284,6 @@ void usbdrv_build_fifo() {
if (cfg->is_configured) { if (cfg->is_configured) {
cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size)); // correct FIFO size if necessary cfg->fifo_size = CEIL4(MAX(USB_MIN_GROSS_TX_FIFO_SIZE, 2 * cfg->max_packet_size)); // correct FIFO size if necessary
cfg->fifo_address = next_fifo_addr; // store FIFO address cfg->fifo_address = next_fifo_addr; // store FIFO address
cfg->auto_zlp = true; // turn on automatic ZLP appending
cfg->zlp_next = false; cfg->zlp_next = false;
// cfg->txp = false; // no transfer is in progress // cfg->txp = false; // no transfer is in progress
next_fifo_addr += cfg->fifo_size; // advance next address next_fifo_addr += cfg->fifo_size; // advance next address
@ -488,14 +487,8 @@ void usbdrv_fetch_received_data(uint8_t ep, uint16_t len) {
// write data to specific endpoint FIFO // write data to specific endpoint FIFO
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) { 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 // determine if a transmission is in progress or not
bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA); 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 uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
@ -600,10 +593,6 @@ void usbdrv_autoarm_OUT_endpoint(uint8_t ep) {
gs.ep_OUT[ep].autoarm = true; gs.ep_OUT[ep].autoarm = true;
} }
void usbdrv_enable_autozlp(uint8_t ep, bool en) {
gs.ep_IN[ep].auto_zlp = en;
}
// ---------------- // ----------------
void usbdrv_set_address(uint8_t addr) { void usbdrv_set_address(uint8_t addr) {
@ -774,7 +763,7 @@ void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
// gs.ep_IN[ep].txp = false; // gs.ep_IN[ep].txp = false;
// see if a ZLP transmission was queued // see if a ZLP transmission was queued
if (/*gs.ep_IN[ep].auto_zlp && */ gs.ep_IN[ep].zlp_next) { if (gs.ep_IN[ep].zlp_next) {
usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
} else { // no ZLP } else { // no ZLP
USBMSG("IN [%d]\n", ep); USBMSG("IN [%d]\n", ep);
@ -889,170 +878,3 @@ void OTG_FS_IRQHandler() {
return; return;
} }
// ---------------
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
// // determine if a transmission is in progress or not
// if (gs.ep_IN[ep].txp) {
// return 0;
// }
// // determine if a transmission is in progress or not
// // bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA); // transmission in progress
// // transmission may only be commenced if last transmission has concluded
// /*if (READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA)) {
// return 0;
// }*/
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
// // determine final write size
// uint32_t freeSize = 0;
// // if (len > 0) { // only poll DTXFSTS if (len > 0) (see datasheet)
// freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
// //}
// // if (gs.ep_IN[ep].txp && (freeSize == 0)) {
// // return 0;
// // }
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
// // if transmission is in progress, then remaining transmission bytes also limits transmission size
// if (gs.ep_IN[ep].txp) {
// uint16_t bytesLeft = USBINEP[ep].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ;
// writeSize = MIN(writeSize, bytesLeft);
// // if this was the last write, then disable Tx empty interrupt
// if (bytesLeft <= mps) {
// USBD->DIEPEMPMSK &= ~((uint32_t)(1 << ep));
// } else { // if not, turn it back on
// USBD->DIEPEMPMSK |= ((uint32_t)(1 << ep));
// }
// } else { // if no transmission was in progress, then setup endpoint for transmission
// // calculate packet count based on max packet size
// uint16_t packet_count = 1; // for ZLPs
// if (writeSize > 0) { // if length is nonzero
// packet_count = len / mps + (((len % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
// }
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (len > 0) && ((len % mps) == 0);
// // program DIEPTSIZ with transfer length
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | len;
// // enable endpoint and cancel responding NAK
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
// // enable FIFO empty interrupt, only if further write operations will follow
// // DO NOT enable this interrupt source when dealing with EP0!
// if ((ep != 0) && (writeSize < len)) {
// USBD->DIEPEMPMSK |= (1 << ep);
// }
// // set transfer in progress
// gs.ep_IN[ep].txp = true;
// }
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // push full dwords
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
// uint32_t floorlen_dwords = writeSize >> 2;
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
// uint16_t i0 = 4 * i;
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
// p[i] = dword;
// }
// // push the remaining partial dword
// uint8_t rem_bytes = writeSize & 0b11;
// if (rem_bytes > 0) {
// uint32_t rem_dword = 0;
// uint16_t rem_start = writeSize - rem_bytes;
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
// rem_dword = (rem_dword << 8) | data[i];
// }
// *p = rem_dword;
// }
// // unmask USB interrupts
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // return with written size
// return writeSize;
// }
// EZ MŰKÖDIK, DE CSAK RÖVID TRANSFEREKRE
// uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
// /*WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_XFRSIZ, len);
// WRITE_FIELD(USBINEP[ep].DIEPTSIZ, USB_OTG_DIEPTSIZ_PKTCNT, 1);*/
// // determine if a transmission is in progress or not
// bool txp = READ_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA);
// if (txp) {
// return 0;
// }
// uint16_t mps = gs.ep_IN[ep].max_packet_size; // fetch maximum packet size
// // determine final write size
// uint32_t freeSize = USBINEP[ep].DTXFSTS * sizeof(uint32_t); // get free transmit buffer size
// uint16_t writeSize = MIN(freeSize, len); // limit transmit size to free size
// // calculate packet count based on max packet size
// uint16_t packet_count = 1; // for ZLPs
// if (writeSize > 0) { // if length is nonzero
// packet_count = writeSize / mps + (((writeSize % mps) > 0) ? 1 : 0); // a transfer may contain multiple packets
// }
// // set zlp_next if transfer size is integer multiple of max packet size and auto ZLP is on
// gs.ep_IN[ep].zlp_next = gs.ep_IN[ep].auto_zlp && (writeSize > 0) && ((writeSize % mps) == 0);
// // program DIEPTSIZ with transfer length
// USBINEP[ep].DIEPTSIZ = /*(packet_count << USB_OTG_DIEPTSIZ_MULCNT_Pos) |*/ (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | writeSize;
// // enable endpoint and cancel responding NAK
// SET_BIT(USBINEP[ep].DIEPCTL, USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK);
// // set transfer in progress
// //gs.ep_IN[ep].txp = true;
// // disable ALL USB interrupts to prevent access to specific registers (see errata)
// CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // push full dwords
// volatile uint32_t *p = (uint32_t *)USBFIFO(ep);
// uint32_t floorlen_dwords = writeSize >> 2;
// for (uint16_t i = 0; i < floorlen_dwords; i++) {
// uint16_t i0 = 4 * i;
// uint32_t dword = data[i0] | (data[i0 + 1] << 8) | (data[i0 + 2] << 16) | (data[i0 + 3] << 24);
// p[i] = dword;
// }
// // push the remaining partial dword
// uint8_t rem_bytes = writeSize & 0b11;
// if (rem_bytes > 0) {
// uint32_t rem_dword = 0;
// uint16_t rem_start = writeSize - rem_bytes;
// for (int16_t i = writeSize - 1; i >= rem_start; i--) {
// rem_dword = (rem_dword << 8) | data[i];
// }
// *p = rem_dword;
// }
// // unmask USB interrupts
// SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT);
// // return with written size
// return writeSize;
// }

View File

@ -35,10 +35,8 @@ typedef struct {
uint8_t is_configured; // the endpoint is in use uint8_t is_configured; // the endpoint is in use
uint16_t fifo_address; // address in the FIFO uint16_t fifo_address; // address in the FIFO
uint16_t fifo_size; // FIFO size uint16_t fifo_size; // FIFO size
bool8_t 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 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 autoarm; // automatically arm endpoint (for OUT endpoints)
//bool8_t txp; // transfer in progress
} USBDRV_EpConfig; } USBDRV_EpConfig;
typedef enum { typedef enum {
@ -155,7 +153,6 @@ uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len);
#define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0) #define USBDRV_ARM_IN_ZLP(ep) usbdrv_arm_IN_endpoint((ep), NULL, 0)
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) 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_autoarm_OUT_endpoint(uint8_t ep); // automatically re-arm OUT endpoint at the and of the current OUT transfer
void usbdrv_enable_autozlp(uint8_t ep, bool en); // enable or disable automatic ZLP appending to the transaction
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir); // get endpoint interrupt flag