/*********************************************************************************** * @fn usbInProcess * * @brief Handle traffic flow from RF to USB. * * @param none * * @return none */ static void usbInProcess(void) { //uint8 length; // USB ready to accept new IN packet halIntOff(); oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(4); // The IN endpoint is ready to accept data if ( USBFW_IN_ENDPOINT_DISARMED() ) { if (usb_sendack) { // modify and return received packet usbfwWriteFifo(&USBF4, usb_buffer[2], &usb_buffer[0]); usb_sendack = 0; // Flag USB IN buffer as not ready (disarming EP4) USBFW_SELECT_ENDPOINT(4); USBFW_ARM_IN_ENDPOINT(); // Send data to the host } /* // Number of bytes present in RF buffer length= bufNumBytes(&rbTxBuf); if (length>0) { // Limit the size if (length > USB_MAX_PACKET_SIZE) { length = USB_MAX_PACKET_SIZE; } // Read from UART TX buffer bufGet(&rbTxBuf,buffer,length); // Write to USB FIFO usbfwWriteFifo(&USBF4, length, buffer); // Flag USB IN buffer as not ready (disarming EP4) USBFW_SELECT_ENDPOINT(4); USBFW_ARM_IN_ENDPOINT(); // Send data to the host }*/ } USBFW_SELECT_ENDPOINT(oldEndpoint); halIntOn(); }
/*********************************************************************************** * @fn halUartPollRx * * @brief Poll for data from USB. * * @param none * * @return none */ void halUartPollRx(void) { uint8 cnt; uint8 ep = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(4); /* If the OUT endpoint has received a complete packet. */ if (USBFW_OUT_ENDPOINT_DISARMED()) { halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); /* Get length of USB packet, this operation must not be interrupted. */ cnt = USBFW_GET_OUT_ENDPOINT_COUNT_LOW(); cnt += USBFW_GET_OUT_ENDPOINT_COUNT_HIGH() >> 8; HAL_EXIT_CRITICAL_SECTION(intState); while (cnt--) { halUartRxQ[halUartRxT++] = HWREG(USB_F4); } USBFW_ARM_OUT_ENDPOINT(); /* If the USB has transferred in more Rx bytes, reset the Rx idle timer. */ /* Re-sync the shadow on any 1st byte(s) received. */ if (rxTick == 0) { rxShdw = ST0; } rxTick = HAL_UART_USB_IDLE; } else if (rxTick)
/*********************************************************************************** * @fn usbOutProcess * * @brief Handle traffic flow from USB to RF. * * @param none * * @return none */ static void usbOutProcess(void) { uint8 length, nToSend; // If new packet is ready in USB FIFO halIntOff(); oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(4); if (USBFW_OUT_ENDPOINT_DISARMED() ) { // Get length of USB packet, this operation must not be interrupted. length = USBFW_GET_OUT_ENDPOINT_COUNT_LOW(); length+= (int)(USBFW_GET_OUT_ENDPOINT_COUNT_HIGH()) >> 8; // Calculate number of bytes available in RF buffer; and the number // of bytes we may transfer in this operation. nToSend= MIN(BUF_SIZE - bufNumBytes(&rbRxBuf), length); // Space available in UART RX buffer ? if (nToSend>0) { // Read from USB FIFO usbfwReadFifo(&USBF4, nToSend, buffer); // Write to radio TX buffer bufPut(&rbRxBuf,buffer,nToSend); // If entire USB packet is read from buffer if (length == nToSend) { USBFW_SELECT_ENDPOINT(4); USBFW_ARM_OUT_ENDPOINT(); } } } USBFW_SELECT_ENDPOINT(oldEndpoint); halIntOn(); }
/************************************************************************************************** * @fn hidSendHidInReport * * @brief Send HID Consumer Control report. * * input parameters * * @param pReport - report to be sent * @param endPoint - endPoint associated with report. * @param len - length of report * * output parameters * * None. * * @return TRUE if report was sent; FALSE otherwise. */ uint8 hidSendHidInReport(uint8 *pReport, uint8 endPoint, uint8 len) { uint8 result = FALSE; if (endPoint < 6) { uint8 ea = halIntLock(); USBFW_SELECT_ENDPOINT(endPoint); if (!(USBCSIL & USBCSIL_INPKT_RDY)) { usbfwWriteFifo(((&USBF0) + (endPoint << 1)), len, pReport); USBCSIL |= USBCSIL_INPKT_RDY; result = TRUE; } halIntUnlock(ea); } return result; }
uint8_t hidSendMouseInReport(void) { uint8_t result = false; bool intDisabled = IntMasterDisable(); USBFW_SELECT_ENDPOINT(2); if(!(HWREG(USB_CSIL) & USB_CSIL_INPKTRDY_M)) { // // Send the report // usbfwWriteFifo(USB_F2, sizeof(MOUSE_IN_REPORT), &hidData.mouseInReport); HWREG(USB_CSIL) |= USB_CSIL_INPKTRDY_M; result = true; } if(!intDisabled) { IntMasterEnable(); } return result; }
/** \brief Internally used function that configures all endpoints for the specified interface * * The new endpoint setup overwrites the old, without any warning. Unused endpoints keep their current * setup. The user is responsible for ensuring that no endpoint buffers overwrite each other, and that * interfaces do not cause conflicts. The pUsbDblbufLutInfo table must contain an entry for each * interface descriptor to define endpoint double-buffering. * * \param[in] *pInterface * A pointer to the interface descriptor */ static void ConfigureEndpoints(USB_INTERFACE_DESCRIPTOR __xdata *pInterface) { uint8 n; uint16 maxpRegValue; uint8 csRegValue; uint8 endpoint; USB_ENDPOINT_DESCRIPTOR __xdata *pEndpoint; DBLBUF_LUT_INFO __xdata *pUsbDblbufLutInfo; // Locate the double buffer settings if (!pInterface->bNumEndpoints) { return; } pUsbDblbufLutInfo = (DBLBUF_LUT_INFO __xdata*) usbDescriptorMarker.pUsbDblbufLut; while (pUsbDblbufLutInfo->pInterface != pInterface) { pUsbDblbufLutInfo++; } // For each endpoint in this interface for (n = 0; n < pInterface->bNumEndpoints; n++) { if (pEndpoint = usbdpFindNext(DESC_TYPE_ENDPOINT, 0)) { // Get the endpoint index endpoint = pEndpoint->bEndpointAddress & 0x0F; USBFW_SELECT_ENDPOINT(endpoint); csRegValue = 0x00; maxpRegValue = (pEndpoint->wMaxPacketSize + 7) >> 3; // For IN endpoints... if (pEndpoint->bEndpointAddress & 0x80) { // Clear data toggle, and flush twice (due to double buffering) USBCSIL = USBCSIL_CLR_DATA_TOG | USBCSIL_FLUSH_PACKET; USBCSIL = USBCSIL_FLUSH_PACKET; // USBCSIH if ((pEndpoint->bmAttributes & EP_ATTR_TYPE_BM) == EP_ATTR_ISO) csRegValue |= USBCSIH_ISO; // ISO flag if (pUsbDblbufLutInfo->inMask & (1 << endpoint)) csRegValue |= USBCSIH_IN_DBL_BUF; // Double buffering USBCSIH = csRegValue; // Max transfer size USBMAXI = maxpRegValue; // Endpoint status usbfwData.pEpInStatus[endpoint - 1] = EP_IDLE; // For OUT endpoints... } else { // Clear data toggle, and flush twice (due to double buffering) USBCSOL = USBCSOL_CLR_DATA_TOG | USBCSOL_FLUSH_PACKET; USBCSOL = USBCSOL_FLUSH_PACKET; // USBCSOH if ((pEndpoint->bmAttributes & EP_ATTR_TYPE_BM) == EP_ATTR_ISO) csRegValue |= USBCSOH_ISO; // ISO flag if (pUsbDblbufLutInfo->outMask & (1 << endpoint)) csRegValue |= USBCSOH_OUT_DBL_BUF; // Double buffering USBCSOH = csRegValue; // Max transfer size USBMAXO = maxpRegValue; // Endpoint status usbfwData.pEpOutStatus[endpoint - 1] = EP_IDLE; } USBFW_SELECT_ENDPOINT(0); } }
/** \brief Internal function used for the very similar \ref SET_FEATURE and \ref CLEAR_FEATURE requests * * This function either sets or clears the specified feature on the specified recipient. * * \param[in] set * When TRUE, the feature is set. When FALSE, the feature is cleared. * * \return * TRUE if the selected feature is supported by the USB library. FALSE to indicate that * \ref usbsrHookClearFeature() or \ref usbsrHookSetFeature() must be called. */ static uint8 ChangeFeature(uint8 set) { uint8 endpoint; // Sanity check if (usbSetupHeader.length || (usbfwData.usbState != DEV_CONFIGURED) && (usbSetupHeader.index != 0)) { usbfwData.ep0Status = EP_STALL; // Handle based on recipient } else { switch (usbSetupHeader.requestType & RT_MASK_RECIP) { // Device case RT_RECIP_DEV: // Sanity check if (LO_UINT16(usbSetupHeader.value) != DEVICE_REMOTE_WAKEUP) { return FALSE; } else { usbfwData.remoteWakeup = set; usbsrHookProcessEvent(set ? USBSR_EVENT_REMOTE_WAKEUP_ENABLED : USBSR_EVENT_REMOTE_WAKEUP_DISABLED, 0); } break; // Endpoint case RT_RECIP_IF: return FALSE; // Endpoint case RT_RECIP_EP: endpoint = LO_UINT16(usbSetupHeader.index) & 0x7F; // Sanity check if (LO_UINT16(usbSetupHeader.value) != ENDPOINT_HALT) { return FALSE; } else if (endpoint > 5) { usbfwData.ep0Status = EP_STALL; } else { USBFW_SELECT_ENDPOINT(endpoint); // IN if (LO_UINT16(usbSetupHeader.index) & 0x80) { USBCSIL = set ? USBCSIL_SEND_STALL : USBCSIL_CLR_DATA_TOG; usbfwData.pEpInStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE; usbsrHookProcessEvent(set ? USBSR_EVENT_EPIN_STALL_SET : USBSR_EVENT_EPIN_STALL_CLEARED, endpoint); // OUT } else { USBCSOL = set ? USBCSOL_SEND_STALL : USBCSOL_CLR_DATA_TOG; usbfwData.pEpOutStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE; usbsrHookProcessEvent(set ? USBSR_EVENT_EPOUT_STALL_SET : USBSR_EVENT_EPOUT_STALL_CLEARED, endpoint); } USBFW_SELECT_ENDPOINT(0); } break; default: usbfwData.ep0Status = EP_STALL; break; } } return TRUE; } // ChangeFeature
// ************************ USB interrupt event processing ************************* void usbirqHookProcessEvents(void) { T1CNTL=0; if (usbirqData.eventMask & USBIRQ_EVENT_EP5IN){ if (isFifoEmpty()==0){ struct UsbISR * msg = (struct UsbISR *)osal_msg_allocate(sizeof(struct UsbISR) ); msg->msg.event = EVENT_USB_ISR; msg->isr = eventSendFifo; osal_msg_send(zusbTaskId, (uint8 *)msg); } } if (usbirqData.eventMask & USBIRQ_EVENT_EP2OUT){ uint8 oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(2); uint8 length = USBFW_GET_OUT_ENDPOINT_COUNT_LOW(); if (length > MAX_DATE_SIZE_2){ length = MAX_DATE_SIZE_2; } if (length) { struct UsbISR * msg =NULL; uint8 code = USBF2; switch( code){ case ENABLE_INFO_MESSAGE: usbOn=1; break; case REQ_RESET: msg = (struct UsbISR *)osal_msg_allocate(sizeof(struct UsbISR) ); msg->msg.event = EVENT_USB_ISR; msg->isr = eventReset; break; case REQ_BIND_TABLE: { uint8 addr[2]; addr[0] = USBF2; addr[1] = USBF2; struct BindTableRequestMsg * msgReq = (struct BindTableRequestMsg *)osal_msg_allocate(sizeof(struct BindTableRequestMsg) ); msg = &(msgReq->isr); msg->isr = eventBindReq; msg->msg.event = EVENT_USB_ISR; msgReq->afAddrType.addrMode = Addr16Bit; msgReq->afAddrType.addr.shortAddr = *(uint16 *)(addr); } break; case REQ_ACTIVE_EP:{ struct ReqActiveEndpointsEvent * msgEP = (struct ReqActiveEndpointsEvent *)osal_msg_allocate(sizeof(struct ReqActiveEndpointsEvent) ); msg = &(msgEP->isr); msg->isr = eventActiveEP; msg->msg.event = EVENT_USB_ISR; msgEP->data[0] = USBF2; msgEP->data[1] = USBF2; } break; case REQ_ADD_BIND_TABLE_ENTRY: msg = createMsgForBind(); msg->isr = eventBindRequest; break; case REQ_REMOVE_BIND_TABLE_ENTRY: msg = createMsgForBind(); msg->isr = eventUnbindRequest; break; case NODE_POWER_REQUEST:{ struct ReqPowerNodeMsg * msgReq =(struct ReqPowerNodeMsg *)osal_msg_allocate(sizeof(struct ReqPowerNodeMsg) ); msg = &(msgReq->isr); msg->isr = eventReqPowerNode; msg->msg.event = EVENT_USB_ISR; msgReq->data[0] = USBF2; msgReq->data[1] = USBF2; } break; case REQ_IEEE_ADDRESS:{ struct ReqIeeeAddrMsg * msgReq = (struct ReqIeeeAddrMsg *)osal_msg_allocate(sizeof(struct ReqIeeeAddrMsg) ); msg = &(msgReq->isr); msg->isr = eventReqIeeeAddr; msg->msg.event = EVENT_USB_ISR; msgReq->data[0] = USBF2; msgReq->data[1] = USBF2; msgReq->requestType = USBF2; msgReq->startIndex = USBF2; break; } case WRITE_ATTRIBUTE_VALUE:{ struct WriteAttributeValueUsbMsg usbMsg; uint8 * data = (uint8 *)(&usbMsg); uint8 i; for(i=0; i < sizeof(struct WriteAttributeValueUsbMsg); i++){ *data = USBF2; data++; } struct WriteAttributeValueMsg * msgCmd = (struct WriteAttributeValueMsg *)osal_msg_allocate(sizeof(struct WriteAttributeValueMsg) +sizeof(zclWriteRec_t) + usbMsg.dataValueLen ); msg = &(msgCmd->isr); msg->isr = eventWriteValue; msg->msg.event = EVENT_USB_ISR; msgCmd->afAddrType.addrMode=afAddr16Bit; msgCmd->afAddrType.addr.shortAddr=usbMsg.nwkAddr; msgCmd->afAddrType.endPoint=usbMsg.endpoint; msgCmd->cluster = usbMsg.cluster; msgCmd->writeCmd.numAttr=1; msgCmd->writeCmd.attrList->attrID = usbMsg.attributeId; msgCmd->writeCmd.attrList->dataType=usbMsg.dataType; data = ((uint8 *)msgCmd) + sizeof(struct WriteAttributeValueMsg) +sizeof(zclWriteRec_t); msgCmd->writeCmd.attrList->attrData = data; for(i=0; i < usbMsg.dataValueLen; i++){ *data = USBF2; data++; } } break; case SEND_CMD:{ struct SendCmdUsbMsg usbMsg; uint8 * data = (uint8 *)(&usbMsg); uint8 i; for(i=0; i < sizeof(struct SendCmdUsbMsg); i++){ *data = USBF2; data++; } struct SendCmdMsg * msgCmd = (struct SendCmdMsg *)osal_msg_allocate(sizeof(struct SendCmdMsg) +usbMsg.dataLen ); msg = &(msgCmd->isr); msg->isr = eventSendCmd; msg->msg.event = EVENT_USB_ISR; msgCmd->cluster =usbMsg.cluster; msgCmd->cmdClusterId = usbMsg.cmdClusterId; msgCmd->afAddrType.addr.shortAddr= usbMsg.nwkAddr; msgCmd->afAddrType.addrMode = afAddr16Bit; msgCmd->afAddrType.endPoint = usbMsg.endpoint; msgCmd->dataLen = usbMsg.dataLen; data = (uint8 *)(msgCmd->data); for(i=0; i < usbMsg.dataLen; i++){ *data = USBF2; data++; } } break; case REQ_ATTRIBUTE_VALUES: { struct ReqAttributeValueMsg attr; uint8 * data = (uint8 *)(&attr); uint8 i; for(i=0; i < sizeof(struct ReqAttributeValueMsg); i++){ *data = USBF2; data++; } struct ReqAttributeMsg * msgAttr = (struct ReqAttributeMsg *)osal_msg_allocate(sizeof(struct ReqAttributeMsg) +attr.numAttributes* sizeof(uint16) ); msg = &(msgAttr->isr); msg->isr = attributeValue; msg->msg.event = EVENT_USB_ISR; msgAttr->afAddrType.addr.shortAddr = attr.nwkAddr; msgAttr->afAddrType.addrMode = afAddr16Bit; msgAttr->afAddrType.endPoint = attr.endpoint; msgAttr->numAttr = attr.numAttributes; data = (uint8 *)&msgAttr->attrID; for (uint8 i=0; i < attr.numAttributes; i++){ *data = USBF2; data++; *data = USBF2; data++; } msgAttr->cluster = attr.cluster; osal_msg_send(zusbTaskId, (uint8 *)msg); break; } case REQ_DEVICE_INFO:{ struct ReqDeviceInformationEvent * msgEP = (struct ReqDeviceInformationEvent *)osal_msg_allocate(sizeof(struct ReqDeviceInformationEvent) ); msg = &(msgEP->isr); msg->isr = eventDeviceInfo; msg->msg.event = EVENT_USB_ISR; msgEP->data[0] = USBF2; msgEP->data[1] = USBF2; } break; } if (msg != NULL) { uint8 low = T1CNTL; uint8 hi = T1CNTH; msg->time=BUILD_UINT16(low,hi); osal_msg_send(zusbTaskId, (uint8 *)msg); } /*uint8 __generic *pTemp = rxData; do { *(pTemp++) = USBF2; } while (--length);*/ } USBFW_ARM_OUT_ENDPOINT(); USBFW_SELECT_ENDPOINT(oldEndpoint); } }
/** \brief USB Setup Handler * * This function should be called either from the USB interrupt or the main loop when the \c USBIIF.EP0IF * flag has been set. Keep in mind that all bits in \c USBIIF register are cleared when the register is * read. A detailed description of the framework is found in the \ref section_setup_handler_usage * section. * * \note The USB header data is always little-endian, so if a big-endian compiler is used (such as Keil * C51), the 16-bit values in the \ref usbSetupHeader must be flipped before they are used. */ void usbfwSetupHandler(void) { uint8 controlReg; uint8 bytesNow; uint8 oldEndpoint; // Save the old index setting, then select endpoint 0 and fetch the control register oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(0); controlReg = USBCS0; // The last transfer was ended prematurely by a new SETUP packet if (controlReg & USBCS0_SETUP_END) { USBCS0 = USBCS0_CLR_SETUP_END; usbfwData.ep0Status = EP_CANCEL; if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // A STALL handshake was transmitted to the PC if (controlReg & USBCS0_SENT_STALL) { USBCS0 = 0x00; usbfwData.ep0Status = EP_IDLE; } // Receive OUT packets if (usbfwData.ep0Status == EP_RX) { // Read FIFO bytesNow = USBCNT0; usbfwReadFifo(&USBF0, bytesNow, usbSetupData.pBuffer); usbSetupData.bytesLeft -= bytesNow; usbSetupData.pBuffer += bytesNow; // Arm the endpoint USBCS0 = usbSetupData.bytesLeft ? USBCS0_CLR_OUTPKT_RDY : (USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END); // Make a call to the appropriate request handler when done if (usbSetupData.bytesLeft == 0) { if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // Return here since nothing more will happen until the next interrupt USBFW_SELECT_ENDPOINT(oldEndpoint); return; // Let the application handle the reception } else if (usbfwData.ep0Status == EP_MANUAL_RX) { ProcessFunc(); } // Receive SETUP header if (usbfwData.ep0Status == EP_IDLE) { if (controlReg & USBCS0_OUTPKT_RDY) { usbfwReadFifo(&USBF0, 8, (uint8 __xdata *) &usbSetupHeader); // Handle control transfers individually ProcessFunc = NULL; switch (usbSetupHeader.requestType & (RT_MASK_TYPE | RT_MASK_DIR)) { // Standard requests with data from the host (OUT) case RT_STD_OUT: switch (usbSetupHeader.request) { case SET_ADDRESS: usbsrSetAddress(); break; case SET_FEATURE: usbsrSetFeature(); break; case CLEAR_FEATURE: usbsrClearFeature(); break; case SET_CONFIGURATION: usbsrSetConfiguration(); break; case SET_INTERFACE: usbsrSetInterface(); break; case SET_DESCRIPTOR: /*usbsrHookSetDescriptor(); break; - unsupported */ default: usbfwData.ep0Status = EP_STALL; break; } break; // Standard requests with data to the host (IN) case RT_STD_IN: switch (usbSetupHeader.request) { case GET_STATUS: usbsrGetStatus(); break; case GET_DESCRIPTOR: usbsrGetDescriptor(); break; case GET_CONFIGURATION: usbsrGetConfiguration(); break; case GET_INTERFACE: usbsrGetInterface(); break; case SYNCH_FRAME: /*usbsrHookSynchFrame(); break; - unsupported */ default: usbfwData.ep0Status = EP_STALL; break; } break; // Vendor requests case RT_VEND_OUT: ProcessFunc = usbvrHookProcessOut; usbvrHookProcessOut(); break; case RT_VEND_IN: ProcessFunc = usbvrHookProcessIn; usbvrHookProcessIn(); break; // Class requests case RT_CLASS_OUT: ProcessFunc = usbcrHookProcessOut; usbcrHookProcessOut(); break; case RT_CLASS_IN: ProcessFunc = usbcrHookProcessIn; usbcrHookProcessIn(); break; // Unrecognized request: Stall the endpoint default: usbfwData.ep0Status = EP_STALL; break; } // Arm/stall the endpoint USBCS0 = (usbfwData.ep0Status == EP_STALL) ? (USBCS0_CLR_OUTPKT_RDY | USBCS0_SEND_STALL) : USBCS0_CLR_OUTPKT_RDY; } } // Transmit IN packets if (usbfwData.ep0Status == EP_TX) { controlReg = USBCS0_INPKT_RDY; // The last frame should contain 0 to (EP0_PACKET_SIZE - 1) bytes if (usbSetupData.bytesLeft < EP0_PACKET_SIZE) { bytesNow = usbSetupData.bytesLeft; controlReg |= USBCS0_DATA_END; // All other packets should have the maximum length } else { bytesNow = EP0_PACKET_SIZE; } // Load the FIFO and move the pointer usbfwWriteFifo(&USBF0, bytesNow, usbSetupData.pBuffer); usbSetupData.pBuffer += bytesNow; usbSetupData.bytesLeft -= bytesNow; // Arm the FIFO (even for a zero-length packet) USBCS0 = controlReg; // Make a call to the appropriate request handler when done if (bytesNow < EP0_PACKET_SIZE) { if (ProcessFunc) ProcessFunc(); usbfwData.ep0Status = EP_IDLE; } // Let the application handle the transmission } else if (usbfwData.ep0Status == EP_MANUAL_TX) { ProcessFunc(); } // Restore the old index setting USBFW_SELECT_ENDPOINT(oldEndpoint); } // usbfwSetupHandler
/** \brief Internally used function that configures all endpoints for the specified interface * * The new endpoint setup overwrites the old. Unused endpoints keep their current setup. The user is * responsible for ensuring that no endpoint buffers overwrite each other, and that interfaces do not * cause conflicts. The \ref pUsbInterfaceEpDblbufLut[] lookup table must contain an entry for each * interface descriptor to define endpoint double-buffering. * * \param[in] *pInterface * A pointer to the interface descriptor */ static void usbsrConfigureEndpoints(const USB_INTERFACE_DESCRIPTOR* pInterface) { const USB_ENDPOINT_DESCRIPTOR* pEndpoint; const USB_INTERFACE_EP_DBLBUF_LUT* pUsbInterfaceEpDblbufInfo; // // Locate the double-buffer settings // if(pInterface->bNumEndpoints) { pUsbInterfaceEpDblbufInfo = (const USB_INTERFACE_EP_DBLBUF_LUT*) pUsbInterfaceEpDblbufLut; while(pUsbInterfaceEpDblbufInfo->pInterface != pInterface) { pUsbInterfaceEpDblbufInfo++; } } // // For each endpoint in this interface // for(uint8_t n = 0; n < pInterface->bNumEndpoints; n++) { if(pEndpoint = usbdpFindNext(USB_DESC_TYPE_ENDPOINT, 0)) { // // Get the endpoint index // uint32_t endpoint = pEndpoint->bEndpointAddress & 0x0F; USBFW_SELECT_ENDPOINT(endpoint); uint32_t csRegValue = 0x00; uint32_t maxpRegValue = (pEndpoint->wMaxPacketSize + 7) >> 3; // // For IN endpoints... // if(pEndpoint->bEndpointAddress & 0x80) { // // Clear data toggle, and flush twice (due to double buffering) // HWREG(USB_CS0_CSIL) = USB_CSIL_CLRDATATOG_M | USB_CSIL_FLUSHPACKET_M; HWREG(USB_CS0_CSIL) = USB_CSIL_FLUSHPACKET_M; // // USBCSIH // if((pEndpoint->bmAttributes & USB_EP_ATTR_TYPE_BM) == USB_EP_ATTR_ISO) { // // ISO flag // csRegValue |= USB_CSIH_ISO_M; } if(pUsbInterfaceEpDblbufInfo->inMask & (1 << endpoint)) { // // Double buffering // csRegValue |= USB_CSIH_INDBLBUF_M; } HWREG(USB_CSIH) = csRegValue; // // Max transfer size // HWREG(USB_MAXI) = maxpRegValue; // // Endpoint status // usbfwData.pEpInStatus[endpoint - 1] = EP_IDLE; // // For OUT endpoints... // } else { // // Clear data toggle, and flush twice (due to double buffering) // HWREG(USB_CSOL) = USB_CSOL_CLRDATATOG_M | USB_CSOL_FLUSHPACKET_M; HWREG(USB_CSOL) = USB_CSOL_FLUSHPACKET_M; // // USBCSOH // if((pEndpoint->bmAttributes & USB_EP_ATTR_TYPE_BM) == USB_EP_ATTR_ISO) { // // ISO flag // csRegValue |= USB_CSOH_ISO_M; } if(pUsbInterfaceEpDblbufInfo->outMask & (1 << endpoint)) { // // Double buffering // csRegValue |= USB_CSOH_OUTDBLBUF_M; } HWREG(USB_CSOH) = csRegValue; // // Max transfer size // HWREG(USB_MAXO) = maxpRegValue; // // Endpoint status // usbfwData.pEpOutStatus[endpoint - 1] = EP_IDLE; } USBFW_SELECT_ENDPOINT(0); } }
/** \brief Internal function used for the very similar \c SET_FEATURE and \c CLEAR_FEATURE requests * * This function either sets or clears the specified feature on the specified recipient. * * \param[in] set * When TRUE, the feature is set. When FALSE, the feature is cleared. * * \return * TRUE if the selected feature is supported by the USB library. FALSE to indicate that * \ref usbsrHookClearFeature() or \ref usbsrHookSetFeature() must be called. */ static uint8_t usbsrChangeFeature(uint8_t set) { uint8_t endpoint; // // Sanity check // if(usbSetupHeader.length || ((usbfwData.usbState != DEV_CONFIGURED) && (usbSetupHeader.index != 0))) { usbfwData.ep0Status = EP_STALL; // // Handle based on recipient // } else { switch(usbSetupHeader.requestType & RT_MASK_RECIP) { // // Device // case RT_RECIP_DEV: // // Sanity check // if(usbSetupHeader.valueLsb != USBSR_FEATSEL_DEVICE_REMOTE_WAKEUP) { return false; } else { usbfwData.remoteWakeup = set; usbsrHookProcessEvent(set ? USBSR_EVENT_REMOTE_WAKEUP_ENABLED : USBSR_EVENT_REMOTE_WAKEUP_DISABLED, 0); } break; // // Interface // case RT_RECIP_IF: return false; // // Endpoint // case RT_RECIP_EP: endpoint = usbSetupHeader.indexLsb & 0x7F; // // Sanity check // if(usbSetupHeader.valueLsb != USBSR_FEATSEL_ENDPOINT_HALT) { return false; } else if(endpoint > 5) { usbfwData.ep0Status = EP_STALL; } else { USBFW_SELECT_ENDPOINT(endpoint); // // IN // if(usbSetupHeader.indexLsb & 0x80) { HWREG(USB_CS0_CSIL) = set ? USB_CSIL_SENDSTALL_M : USB_CSIL_CLRDATATOG_M; usbfwData.pEpInStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE; usbsrHookProcessEvent(set ? USBSR_EVENT_EPIN_STALL_SET : USBSR_EVENT_EPIN_STALL_CLEARED, endpoint); // // OUT // } else { HWREG(USB_CSOL) = set ? USB_CSOL_SENDSTALL_M : USB_CSOL_CLRDATATOG_M; usbfwData.pEpOutStatus[endpoint - 1] = set ? EP_HALT : EP_IDLE; usbsrHookProcessEvent(set ? USBSR_EVENT_EPOUT_STALL_SET : USBSR_EVENT_EPOUT_STALL_CLEARED, endpoint); } USBFW_SELECT_ENDPOINT(0); } break; default: usbfwData.ep0Status = EP_STALL; break; } } return true; }
/*********************************************************************************** * @fn usbOutProcess * * @brief Handle traffic flow from USB to RF. * * @param none * * @return none */ static void usbOutProcess(void) { uint8 length, /*nToSend,*/ packetlength=0; // If new packet is ready in USB FIFO halIntOff(); oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(4); if (USBFW_OUT_ENDPOINT_DISARMED() ) { // Get length of USB packet, this operation must not be interrupted. length = USBFW_GET_OUT_ENDPOINT_COUNT_LOW(); length+= USBFW_GET_OUT_ENDPOINT_COUNT_HIGH() >> 8; // Avoid overflow message_length = USB_MAX_MESSAGE_LENGTH; if (usb_bufferIndex + length > USB_MAX_MESSAGE_LENGTH) usb_bufferIndex=0; // Copy received bytes from FIFO to buffer usbfwReadFifo(&USBF4, length, &usb_buffer[usb_bufferIndex]); // Increase buffer index usb_bufferIndex += length; // If entire USB packet is read from buffer USBFW_SELECT_ENDPOINT(4); USBFW_ARM_OUT_ENDPOINT(); // get packet lenght from byte #2 of received packet if ((usb_bufferIndex >= 2) && (packetlength == 0)) packetlength = usb_buffer[2]; if ((usb_bufferIndex > packetlength-1) && (packetlength >= USB_MIN_MESSAGE_LENGTH)) { //extract data from packet usb_decode(); usb_bufferIndex = 0; } /* // Calculate number of bytes available in RF buffer; and the number // of bytes we may transfer in this operation. nToSend= MIN(BUF_SIZE - bufNumBytes(&rbRxBuf), length); // Space available in UART RX buffer ? if (nToSend>0) { // Read from USB FIFO usbfwReadFifo(&USBF4, nToSend, buffer); // Write to radio TX buffer bufPut(&rbRxBuf,buffer,nToSend); // If entire USB packet is read from buffer if (length == nToSend) { USBFW_SELECT_ENDPOINT(4); USBFW_ARM_OUT_ENDPOINT(); } }*/ } USBFW_SELECT_ENDPOINT(oldEndpoint); halIntOn(); }
/** \brief USB Setup Handler * * This function should be called either from the USB interrupt or the main loop when the * \c USB_IIF.EP0IF flag has been set. A detailed description of the framework is found in the * \ref section_setup_handler_usage section. */ void usbfwSetupHandler(void) { uint32_t controlReg; uint32_t oldEndpoint; uint32_t bytesNow; // // Save the old index setting, then select endpoint 0 and fetch the control register // oldEndpoint = USBFW_GET_SELECTED_ENDPOINT(); USBFW_SELECT_ENDPOINT(0); controlReg = HWREG(USB_CS0); // // Update the USB device address after the status stage // if(usbfwData.ep0Status == EP_ADDRESS) { if(!(controlReg & USB_CS0_OUTPKTRDY_M)) { uint8_t address = usbSetupHeader.valueLsb; HWREG(USB_ADDR) = address; if(usbfwData.usbState < DEV_CONFIGURED) { if(address) { usbfwData.usbState = DEV_ADDRESS; } else { usbfwData.usbState = DEV_DEFAULT; } } } usbfwData.ep0Status = EP_IDLE; } // // A STALL handshake was transmitted to the host // if(controlReg & USB_CS0_SENTSTALL_M) { HWREG(USB_CS0) = 0x00; usbfwData.ep0Status = EP_IDLE; } // // The last transfer was ended prematurely by a new SETUP packet // if(controlReg & USB_CS0_SETUPEND_M) { HWREG(USB_CS0) = USB_CS0_CLRSETUPEND_M; usbfwData.ep0Status = EP_CANCEL; if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } // // Receive OUT packets // if(usbfwData.ep0Status == EP_RX) { if(controlReg & USB_CS0_OUTPKTRDY_M) { // // Read FIFO // uint32_t bytesNow = HWREG(USB_CNT0); usbfwReadFifo(USB_F0, bytesNow, usbSetupData.pBuffer); usbSetupData.bytesLeft -= bytesNow; usbSetupData.pBuffer = ((uint8_t*) usbSetupData.pBuffer) + bytesNow; // // Arm the endpoint // if(usbSetupData.bytesLeft) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M; } else { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_DATAEND_M; } // // Make a call to the appropriate request handler when done // if(usbSetupData.bytesLeft == 0) { if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } } // // Return here since nothing more will happen until the next interrupt // USBFW_SELECT_ENDPOINT(oldEndpoint); return; // // Let the application handle the reception // } else if(usbfwData.ep0Status == EP_MANUAL_RX) { if(pProcessFunc) { pProcessFunc(); } } // // Receive SETUP header // if(usbfwData.ep0Status == EP_IDLE) { if(controlReg & USB_CS0_OUTPKTRDY_M) { usbfwReadFifo(USB_F0, 8, &usbSetupHeader); // // Handle control transfers individually // pProcessFunc = NULL; switch(usbSetupHeader.requestType & (RT_MASK_TYPE | RT_MASK_DIR)) { // // Standard requests without data or with data from the host (OUT) // case RT_STD_OUT: switch(usbSetupHeader.request) { case USBSR_REQ_SET_ADDRESS: usbsrSetAddress(); break; case USBSR_REQ_SET_FEATURE: usbsrSetFeature(); break; case USBSR_REQ_CLEAR_FEATURE: usbsrClearFeature(); break; case USBSR_REQ_SET_CONFIGURATION: usbsrSetConfiguration(); break; case USBSR_REQ_SET_INTERFACE: usbsrSetInterface(); break; case USBSR_REQ_SET_DESCRIPTOR: pProcessFunc = usbsrHookSetDescriptor; usbsrHookSetDescriptor(); break; default: usbfwData.ep0Status = EP_STALL; break; } break; // // Standard requests with data to the host (IN) // case RT_STD_IN: switch(usbSetupHeader.request) { case USBSR_REQ_GET_STATUS: usbsrGetStatus(); break; case USBSR_REQ_GET_DESCRIPTOR: usbsrGetDescriptor(); break; case USBSR_REQ_GET_CONFIGURATION: usbsrGetConfiguration(); break; case USBSR_REQ_GET_INTERFACE: usbsrGetInterface(); break; case USBSR_REQ_SYNCH_FRAME: pProcessFunc = usbsrHookSynchFrame; usbsrHookSynchFrame(); break; default: usbfwData.ep0Status = EP_STALL; break; } break; // // Vendor requests // case RT_VEND_OUT: pProcessFunc = usbvrHookProcessOut; usbvrHookProcessOut(); break; case RT_VEND_IN: pProcessFunc = usbvrHookProcessIn; usbvrHookProcessIn(); break; // // Class requests // case RT_CLASS_OUT: pProcessFunc = usbcrHookProcessOut; usbcrHookProcessOut(); break; case RT_CLASS_IN: pProcessFunc = usbcrHookProcessIn; usbcrHookProcessIn(); break; // // Unrecognized request: Stall the endpoint // default: usbfwData.ep0Status = EP_STALL; break; } // // Arm/stall the endpoint // if(usbfwData.ep0Status == EP_STALL) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_SENDSTALL_M; } else if((usbfwData.ep0Status == EP_TX) || (usbfwData.ep0Status == EP_RX)) { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M; } else { HWREG(USB_CS0) = USB_CS0_CLROUTPKTRDY_M | USB_CS0_DATAEND_M; } } } // // Transmit IN packets // if(usbfwData.ep0Status == EP_TX) { controlReg = USB_CS0_INPKTRDY_M; // // The last frame should contain 0 to (EP0_PACKET_SIZE - 1) bytes // if(usbSetupData.bytesLeft < USB_EP0_PACKET_SIZE) { bytesNow = usbSetupData.bytesLeft; controlReg |= USB_CS0_DATAEND_M; } else { // // All other packets should have the maximum length // bytesNow = USB_EP0_PACKET_SIZE; } // // Load the FIFO and move the pointer // usbfwWriteFifo(USB_F0, bytesNow, usbSetupData.pBuffer); usbSetupData.pBuffer = ((uint8_t*) usbSetupData.pBuffer) + bytesNow; usbSetupData.bytesLeft -= bytesNow; // // Arm the FIFO (even for a zero-length packet) // HWREG(USB_CS0) = controlReg; // // Make a call to the appropriate request handler when done // if(bytesNow < USB_EP0_PACKET_SIZE) { if(pProcessFunc) { pProcessFunc(); } usbfwData.ep0Status = EP_IDLE; } // // Let the application handle the transmission // } else if(usbfwData.ep0Status == EP_MANUAL_TX) { if(pProcessFunc) { pProcessFunc(); } } // // Restore the old index setting // USBFW_SELECT_ENDPOINT(oldEndpoint); }