/** * @brief Default data transmitted callback. * @details The application must use this function as callback for the IN * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number */ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { size_t n; SerialUSBDriver *sdup = usbp->param; (void)ep; chSysLockFromIsr(); chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); if ((n = chOQGetFullI(&sdup->oqueue)) > 0) { /* The endpoint cannot be busy, we are in the context of the callback, so it is safe to transmit without a check.*/ chSysUnlockFromIsr(); usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, n); chSysLockFromIsr(); usbStartTransmitI(usbp, ep); } else if (!(usbp->epc[ep]->in_state->txsize & (usbp->epc[ep]->in_maxsize - 1))) { /* Transmit zero sized packet in case the last one has maximum allowed size. Otherwise the recipient may expect more data coming soon and not return buffered data to app. See section 5.8.3 Bulk Transfer Packet Size Constraints of the USB Specification document.*/ chSysUnlockFromIsr(); usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, 0); chSysLockFromIsr(); usbStartTransmitI(usbp, ep); } chSysUnlockFromIsr(); }
/** * @brief Notification of data inserted into the output queue. * * @param[in] qp the queue pointer. */ static void onotify(io_queue_t *qp) { size_t n; HIDDebugDriver *hiddp = qGetLink(qp); /* If the USB driver is not in the appropriate state then transactions * must not be started.*/ if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) || (hiddp->state != HIDDEBUG_READY)) { return; } /* If there is not an ongoing transaction and the output queue contains * enough data then a new transaction is started.*/ if(!usbGetTransmitStatusI(hiddp->config->usbp, hiddp->config->ep_in)) { if((n = oqGetFullI(&hiddp->oqueue)) >= DEBUG_TX_SIZE) { osalSysUnlock(); usbPrepareQueuedTransmit(hiddp->config->usbp, hiddp->config->ep_in, &hiddp->oqueue, DEBUG_TX_SIZE); osalSysLock(); (void)usbStartTransmitI(hiddp->config->usbp, hiddp->config->ep_in); } } }
static void msc_sendstatus(USBDriver *usbp) { msc_state = MSC_SENDING_CSW; chSysLockFromIsr(); usbStartTransmitI(usbp, MSC_DATA_IN_EP, (uint8_t *)&CSW, sizeof CSW); chSysUnlockFromIsr(); }
/** * @brief Default data transmitted callback. * @details The application must use this function as callback for the IN * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number */ void hidDebugDataTransmitted(USBDriver *usbp, usbep_t ep) { HIDDebugDriver *hiddp = usbp->in_params[ep - 1U]; size_t n; if(hiddp == NULL) { return; } osalSysLockFromISR(); /* rearm the flush timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); /* see if we've transmitted everything */ if((n = oqGetFullI(&hiddp->oqueue)) == 0) { chnAddFlagsI(hiddp, CHN_OUTPUT_EMPTY); } /* Check if there's enough data in the queue to send again */ if(n >= DEBUG_TX_SIZE) { /* The endpoint cannot be busy, we are in the context of the callback, * so it is safe to transmit without a check.*/ osalSysUnlockFromISR(); usbPrepareQueuedTransmit(usbp, ep, &hiddp->oqueue, DEBUG_TX_SIZE); osalSysLockFromISR(); (void)usbStartTransmitI(usbp, ep); } osalSysUnlockFromISR(); }
/** * @brief Notification of data inserted into the output queue. * * @param[in] qp the queue pointer. */ static void onotify(io_queue_t *qp) { size_t n; SerialUSBDriver *sdup = qGetLink(qp); /* If the USB driver is not in the appropriate state then transactions must not be started.*/ if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || (sdup->state != SDU_READY)) { return; } /* If there is not an ongoing transaction and the output queue contains data then a new transaction is started.*/ if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { if ((n = oqGetFullI(&sdup->oqueue)) > 0U) { osalSysUnlock(); usbPrepareQueuedTransmit(sdup->config->usbp, sdup->config->bulk_in, &sdup->oqueue, n); osalSysLock(); (void) usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in); } } }
/** * @brief SOF handler. * @details The SOF interrupt is used for automatic flushing of incomplete * buffers pending in the output queue. * * @param[in] sdup pointer to a @p SerialUSBDriver object * * @iclass */ void sduSOFHookI(SerialUSBDriver *sdup) { /* If the USB driver is not in the appropriate state then transactions must not be started.*/ if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || (sdup->state != SDU_READY)) { return; } /* If there is already a transaction ongoing then another one cannot be started.*/ if (usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { return; } /* Checking if there only a buffer partially filled, if so then it is enforced in the queue and transmitted.*/ if (obqTryFlushI(&sdup->obqueue)) { size_t n; uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); osalDbgAssert(buf != NULL, "queue is empty"); usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); } }
/** * @brief Default EP0 OUT callback. * @details This function is used by the low level driver as default handler * for EP0 OUT events. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number, always zero * * @notapi */ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { (void)ep; switch (usbp->ep0state) { case USB_EP0_RX: /* Receive phase over, sending the zero sized status packet.*/ usbp->ep0state = USB_EP0_SENDING_STS; usbPrepareTransmit(usbp, 0, NULL, 0); chSysLockFromIsr(); usbStartTransmitI(usbp, 0); chSysUnlockFromIsr(); return; case USB_EP0_WAITING_STS: /* Status packet received, it must be zero sized, invoking the callback if defined.*/ if (usbGetReceiveTransactionSizeI(usbp, 0) != 0) break; if (usbp->ep0endcb != NULL) usbp->ep0endcb(usbp); usbp->ep0state = USB_EP0_WAITING_SETUP; return; default: ; } /* Error response, the state machine goes into an error state, the low level layer will have to reset it to USB_EP0_WAITING_SETUP after receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); usbp->ep0state = USB_EP0_ERROR; }
void hid_transmit(USBDriver *usbp) { usbPrepareTransmit(usbp, HID_IN_EP_ADDRESS, (uint8_t *)&hid_in_data, sizeof (hid_in_data)); chSysLockFromISR(); usbStartTransmitI(usbp, HID_IN_EP_ADDRESS); palSetPadMode(GPIOD, 14, PAL_MODE_OUTPUT_PUSHPULL); palClearPad(GPIOD, 14); chSysUnlockFromISR(); }
/** * @brief Default EP0 IN callback. * @details This function is used by the low level driver as default handler * for EP0 IN events. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number, always zero * * @notapi */ void _usb_ep0in(USBDriver *usbp, usbep_t ep) { size_t max; (void)ep; switch (usbp->ep0state) { case USB_EP0_TX: max = (size_t)get_hword(&usbp->setup[6]); /* If the transmitted size is less than the requested size and it is a multiple of the maximum packet size then a zero size packet must be transmitted.*/ if ((usbp->ep0n < max) && ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0U)) { usbPrepareTransmit(usbp, 0, NULL, 0); osalSysLockFromISR(); (void) usbStartTransmitI(usbp, 0); osalSysUnlockFromISR(); usbp->ep0state = USB_EP0_WAITING_TX0; return; } /* Falls into, it is intentional.*/ case USB_EP0_WAITING_TX0: /* Transmit phase over, receiving the zero sized status packet.*/ usbp->ep0state = USB_EP0_WAITING_STS; #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) usbPrepareReceive(usbp, 0, NULL, 0); osalSysLockFromISR(); (void) usbStartReceiveI(usbp, 0); osalSysUnlockFromISR(); #else usb_lld_end_setup(usbp, ep); #endif return; case USB_EP0_SENDING_STS: /* Status packet sent, invoking the callback if defined.*/ if (usbp->ep0endcb != NULL) { usbp->ep0endcb(usbp); } usbp->ep0state = USB_EP0_WAITING_SETUP; return; case USB_EP0_WAITING_SETUP: case USB_EP0_WAITING_STS: case USB_EP0_RX: /* All the above are invalid states in the IN phase.*/ osalDbgAssert(false, "EP0 state machine error"); /* Falling through is intentional.*/ case USB_EP0_ERROR: /* Error response, the state machine goes into an error state, the low level layer will have to reset it to USB_EP0_WAITING_SETUP after receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); usbp->ep0state = USB_EP0_ERROR; return; default: osalDbgAssert(false, "EP0 state machine invalid state"); } }
static void msc_transmit(USBDriver *usbp, const uint8_t *p, size_t n) { if (n > CBW.dCBWDataTransferLength) n = CBW.dCBWDataTransferLength; CSW.dCSWDataResidue = CBW.dCBWDataTransferLength - (uint32_t)n; chSysLockFromIsr(); usbStartTransmitI(usbp, MSC_DATA_IN_EP, p, n); chSysUnlockFromIsr(); }
static msg_t tUsbTx(void *arg) { (void)arg; chRegSetThreadName("usbTx"); msg_t msg; usbPacket *usbBufp; enum {UsbTxComleteID = 0, UsbResetID = 1, UsbConfiguredID = 2}; EventListener elUsbTxComplete; EventListener elUsbReset; EventListener elUsbConfigured; eventmask_t activeEvents; chEvtRegister(&esUsbTxComplete, &elUsbTxComplete, UsbTxComleteID); chEvtRegister(&esUsbReset, &elUsbReset, UsbResetID); chEvtRegister(&esUsbConfigured, &elUsbConfigured, UsbConfiguredID); // Wait for the USB system to be configured. and clear all other event flags. chEvtWaitOne(EVENT_MASK(UsbConfiguredID)); chEvtGetAndClearEvents(EVENT_MASK(UsbTxComleteID) | EVENT_MASK(UsbResetID)); while (TRUE) { chMBFetch (&usbTXMailbox, &msg, TIME_INFINITE); // Check if USB has been reconfigured while waiting for message from sysctrl activeEvents = chEvtGetAndClearEvents(EVENT_MASK(UsbConfiguredID)); if (activeEvents == EVENT_MASK(UsbConfiguredID)) { // If so, clear the reset event since it is no longer relevant. activeEvents = chEvtGetAndClearEvents(EVENT_MASK(UsbResetID)); } // Typecast Mailbox message to command package pointer for readability usbBufp = (usbPacket*)msg; // Prepare transmit and start the transmission. This operation will return immediately usbPrepareTransmit(usbp, EP_IN, usbBufp->packet, (size_t)usbBufp->size); chSysLock(); usbStartTransmitI(usbp, EP_IN); chSysUnlock(); //Check for events from the USB system. activeEvents = chEvtWaitAny(EVENT_MASK(UsbTxComleteID) | EVENT_MASK(UsbResetID)); if (activeEvents == EVENT_MASK(UsbResetID)) { chEvtWaitOne(EVENT_MASK(UsbConfiguredID)); // Clear any events that has occurred while the usb was not configured. chEvtGetAndClearEvents(EVENT_MASK(UsbTxComleteID) | EVENT_MASK(UsbResetID)); } usbFreeMailboxBuffer (usbBufp); } return 0; }
/** * @brief Default data transmitted callback. * @details The application must use this function as callback for the IN * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep IN endpoint number */ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { uint8_t *buf; size_t n; SerialUSBDriver *sdup = usbp->in_params[ep - 1U]; if (sdup == NULL) { return; } osalSysLockFromISR(); /* Signaling that space is available in the output queue.*/ chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ if (usbp->epc[ep]->in_state->txsize > 0U) { obqReleaseEmptyBufferI(&sdup->obqueue); } /* Checking if there is a buffer ready for transmission.*/ buf = obqGetFullBufferI(&sdup->obqueue, &n); if (buf != NULL) { /* The endpoint cannot be busy, we are in the context of the callback, so it is safe to transmit without a check.*/ usbStartTransmitI(usbp, ep, buf, n); } else if ((usbp->epc[ep]->in_state->txsize > 0U) && ((usbp->epc[ep]->in_state->txsize & ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { /* Transmit zero sized packet in case the last one has maximum allowed size. Otherwise the recipient may expect more data coming soon and not return buffered data to app. See section 5.8.3 Bulk Transfer Packet Size Constraints of the USB Specification document.*/ usbStartTransmitI(usbp, ep, usbp->setup, 0); } else { /* Nothing to transmit.*/ } osalSysUnlockFromISR(); }
void send_data(){ usbStatus=1; if(initUSB){ usbPrepareTransmit(usbp, EP_IN, transferBuf, sizeof transferBuf); chSysLock(); usbStartTransmitI(usbp, EP_IN); chSysUnlock(); /* chSequentialStreamWrite(&SDU1, buf, sizeof buf - 1); */ } initUSB=0; // else failed }
/** * @brief Default data transmitted callback. * @details The application must use this function as callback for the IN * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number */ void sduDataTransmitted(USBDriver *usbp, usbep_t ep) { size_t n; SerialUSBDriver *sdup = usbp->in_params[ep - 1U]; if (sdup == NULL) { return; } osalSysLockFromISR(); chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY); /*lint -save -e9013 [15.7] There is no else because it is not needed.*/ if ((n = oqGetFullI(&sdup->oqueue)) > 0U) { /* The endpoint cannot be busy, we are in the context of the callback, so it is safe to transmit without a check.*/ osalSysUnlockFromISR(); usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, n); osalSysLockFromISR(); (void) usbStartTransmitI(usbp, ep); } else if ((usbp->epc[ep]->in_state->txsize > 0U) && ((usbp->epc[ep]->in_state->txsize & ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { /* Transmit zero sized packet in case the last one has maximum allowed size. Otherwise the recipient may expect more data coming soon and not return buffered data to app. See section 5.8.3 Bulk Transfer Packet Size Constraints of the USB Specification document.*/ osalSysUnlockFromISR(); usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, 0); osalSysLockFromISR(); (void) usbStartTransmitI(usbp, ep); } /*lint -restore*/ osalSysUnlockFromISR(); }
/** * @brief Default EP0 OUT callback. * @details This function is used by the low level driver as default handler * for EP0 OUT events. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number, always zero * * @notapi */ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { (void)ep; switch (usbp->ep0state) { case USB_EP0_RX: /* Receive phase over, sending the zero sized status packet.*/ usbp->ep0state = USB_EP0_SENDING_STS; #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) usbPrepareTransmit(usbp, 0, NULL, 0); osalSysLockFromISR(); (void) usbStartTransmitI(usbp, 0); osalSysUnlockFromISR(); #else usb_lld_end_setup(usbp, ep); #endif return; case USB_EP0_WAITING_STS: /* Status packet received, it must be zero sized, invoking the callback if defined.*/ #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) if (usbGetReceiveTransactionSizeI(usbp, 0) != 0U) { break; } #endif if (usbp->ep0endcb != NULL) { usbp->ep0endcb(usbp); } usbp->ep0state = USB_EP0_WAITING_SETUP; return; case USB_EP0_WAITING_SETUP: case USB_EP0_TX: case USB_EP0_WAITING_TX0: case USB_EP0_SENDING_STS: /* All the above are invalid states in the IN phase.*/ osalDbgAssert(false, "EP0 state machine error"); /* Falling through is intentional.*/ case USB_EP0_ERROR: /* Error response, the state machine goes into an error state, the low level layer will have to reset it to USB_EP0_WAITING_SETUP after receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); usbp->ep0state = USB_EP0_ERROR; return; default: osalDbgAssert(false, "EP0 state machine invalid state"); } }
/* * data Transmitted Callback */ void dataTransmitted(USBDriver *usbp, usbep_t ep){ (void) usbp; (void) ep; // exit on USB reset if(!usbStatus) return; usbPrepareTransmit(usbp, EP_IN, transferBuf, sizeof transferBuf); chSysLockFromIsr(); usbStartTransmitI(usbp, EP_IN); chSysUnlockFromIsr(); }
static void send_extra_report(uint8_t report_id, uint16_t data) { osalSysLock(); if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { osalSysUnlock(); return; } report_extra_t report = { .report_id = report_id, .usage = data }; usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t)); osalSysUnlock(); }
/** * @brief Performs a transmit transaction on an IN endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] buf buffer where to fetch the data to be transmitted * @param[in] n transaction size * * @return The operation status. * @retval MSG_OK operation performed successfully. * @retval MSG_RESET driver not in @p USB_ACTIVE state or the operation * has been aborted by an USB reset or a transition to * the @p USB_SUSPENDED state. * * @api */ msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { msg_t msg; osalSysLock(); if (usbGetDriverStateI(usbp) != USB_ACTIVE) { osalSysUnlock(); return MSG_RESET; } usbStartTransmitI(usbp, ep, buf, n); msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread); osalSysUnlock(); return msg; }
/** * @brief Default EP0 IN callback. * @details This function is used by the low level driver as default handler * for EP0 IN events. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number, always zero * * @notapi */ void _usb_ep0in(USBDriver *usbp, usbep_t ep) { size_t max; (void)ep; switch (usbp->ep0state) { case USB_EP0_TX: max = usbFetchWord(&usbp->setup[6]); /* If the transmitted size is less than the requested size and it is a multiple of the maximum packet size then a zero size packet must be transmitted.*/ if ((usbp->ep0n < max) && ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0)) { usbPrepareTransmit(usbp, 0, NULL, 0); chSysLockFromIsr(); usbStartTransmitI(usbp, 0); chSysUnlockFromIsr(); usbp->ep0state = USB_EP0_WAITING_TX0; return; } /* Falls into, it is intentional.*/ case USB_EP0_WAITING_TX0: /* Transmit phase over, receiving the zero sized status packet.*/ usbp->ep0state = USB_EP0_WAITING_STS; usbPrepareReceive(usbp, 0, NULL, 0); chSysLockFromIsr(); usbStartReceiveI(usbp, 0); chSysUnlockFromIsr(); return; case USB_EP0_SENDING_STS: /* Status packet sent, invoking the callback if defined.*/ if (usbp->ep0endcb != NULL) usbp->ep0endcb(usbp); usbp->ep0state = USB_EP0_WAITING_SETUP; return; default: ; } /* Error response, the state machine goes into an error state, the low level layer will have to reset it to USB_EP0_WAITING_SETUP after receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); usbp->ep0state = USB_EP0_ERROR; }
/** * @brief Notification of filled buffer inserted into the output buffers queue. * * @param[in] bqp the buffers queue pointer. */ static void obnotify(io_buffers_queue_t *bqp) { size_t n; SerialUSBDriver *sdup = bqGetLinkX(bqp); /* If the USB driver is not in the appropriate state then transactions must not be started.*/ if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) || (sdup->state != SDU_READY)) { return; } /* Checking if there is already a transaction ongoing on the endpoint.*/ if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in)) { /* Trying to get a full buffer.*/ uint8_t *buf = obqGetFullBufferI(&sdup->obqueue, &n); if (buf != NULL) { /* Buffer found, starting a new transaction.*/ usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in, buf, n); } } }
void send_mouse(report_mouse_t *report) { osalSysLock(); if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { osalSysUnlock(); return; } if(usbGetTransmitStatusI(&USB_DRIVER, MOUSE_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ if (osalThreadSuspendTimeoutS(&(&USB_DRIVER)->epc[MOUSE_IN_EPNUM]->in_state->thread, MS2ST(10)==MSG_TIMEOUT)) { osalSysUnlock(); return; } } usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t)); osalSysUnlock(); }
/** * @brief Default data transmitted callback. * @details The application must use this function as callback for the IN * data endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number */ void mscDataTransmitted(USBDriver *usbp, usbep_t ep) { switch (msc_state) { case MSC_DATA_IN: CSW.dCSWSignature = MSC_CSW_SIGNATURE; CSW.dCSWTag = CBW.dCBWTag; chSysLockFromIsr(); usbStartTransmitI(usbp, ep, (uint8_t *)&CSW, sizeof CSW); chSysUnlockFromIsr(); msc_state = MSC_SENDING_CSW; break; case MSC_SENDING_CSW: chSysLockFromIsr(); usbStartReceiveI(usbp, MSC_DATA_OUT_EP, (uint8_t *)&CBW, sizeof CBW); chSysUnlockFromIsr(); msc_state = MSC_IDLE; break; default: ; } }
/* callback */ static void hid_debug_flush_cb(void *arg) { HIDDebugDriver *hiddp = (HIDDebugDriver *)arg; size_t i, n; uint8_t buf[DEBUG_TX_SIZE]; osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) || (hiddp->state != HIDDEBUG_READY)) { /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); return; } /* don't do anything if the queue or has enough stuff in it */ if(((n = oqGetFullI(&hiddp->oqueue)) == 0) || (n >= DEBUG_TX_SIZE)) { /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); return; } /* there's stuff hanging in the queue - so dequeue and send */ for(i = 0; i < n; i++) buf[i] = (uint8_t)oqGetI(&hiddp->oqueue); for(i = n; i < DEBUG_TX_SIZE; i++) buf[i] = 0; osalSysUnlockFromISR(); usbPrepareTransmit(hiddp->config->usbp, hiddp->config->ep_in, buf, DEBUG_TX_SIZE); osalSysLockFromISR(); (void)usbStartTransmitI(hiddp->config->usbp, hiddp->config->ep_in); /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); }
static msg_t initUsbTransfer(void *arg) { (void)arg; uint8_t i; chRegSetThreadName("initUsbTransfer"); while (TRUE) { //wait until enough ADC data is aquired or an overflow is detected while((((p1+BUFFLEN-p2)%BUFFLEN)<IN_PACKETSIZE) && !overflow){ chThdSleepMilliseconds(1); } // copy the ADC data to the USB transfer buffer for (i=0;i<IN_PACKETSIZE;i++){ transferBuf[i]=((uint8_t*) data)[p2]; //if an overflow is detected, write the overflow count. // in a real application this has to be send on another channel if(overflow){ transferBuf[i]= overflow; overflow=0; } p2 = (p2+1)%BUFFLEN; } //wait for the last transmission to complete while(transmitting){ chThdSleepMilliseconds(1); } transmitting = 1; usbPrepareTransmit(usbp, EP_IN, transferBuf, IN_PACKETSIZE); chSysLock(); usbStartTransmitI(usbp, EP_IN); chSysUnlock(); } return 0; }
/** * @brief Notification of data inserted into the output queue. */ static void onotify(GenericQueue *qp) { size_t n; SerialUSBDriver *sdup = chQGetLink(qp); /* If the USB driver is not in the appropriate state then transactions must not be started.*/ if (usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) return; /* If there is not an ongoing transaction and the output queue contains data then a new transaction is started.*/ if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP) && ((n = chOQGetFullI(&sdup->oqueue)) > 0)) { chSysUnlock(); usbPrepareQueuedTransmit(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP, &sdup->oqueue, n); chSysLock(); usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP); } }
/** * @brief Notification of data inserted into the output queue. */ static void onotify(GenericQueue *qp) { size_t n; BulkUSBDriver *bdup = chQGetLink(qp); /* If the USB driver is not in the appropriate state then transactions must not be started.*/ if ((usbGetDriverStateI(bdup->config->usbp) != USB_ACTIVE) || (bdup->state != BDU_READY)) return; /* If there is not an ongoing transaction and the output queue contains data then a new transaction is started.*/ if (!usbGetTransmitStatusI(bdup->config->usbp, bdup->config->bulk_in) && ((n = chOQGetFullI(&bdup->oqueue)) > 0)) { chSysUnlock(); usbPrepareQueuedTransmit(bdup->config->usbp, bdup->config->bulk_in, &bdup->oqueue, n); chSysLock(); usbStartTransmitI(bdup->config->usbp, bdup->config->bulk_in); } }
/* Idle requests timer code * callback (called from ISR, unlocked state) */ static void keyboard_idle_timer_cb(void *arg) { USBDriver *usbp = (USBDriver *)arg; osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ if(usbGetDriverStateI(usbp) != USB_ACTIVE) { /* do not rearm the timer, should be enabled on IDLE request */ osalSysUnlockFromISR(); return; } #ifdef NKRO_ENABLE if(!keymap_config.nkro && keyboard_idle) { #else /* NKRO_ENABLE */ if(keyboard_idle) { #endif /* NKRO_ENABLE */ /* TODO: are we sure we want the KBD_ENDPOINT? */ if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) { usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE); } /* rearm the timer */ chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp); } /* do not rearm the timer if the condition above fails * it should be enabled again on either IDLE or SET_PROTOCOL requests */ osalSysUnlockFromISR(); } /* LED status */ uint8_t keyboard_leds(void) { return (uint8_t)(keyboard_led_stats & 0xFF); } /* prepare and start sending a report IN * not callable from ISR or locked state */ void send_keyboard(report_keyboard_t *report) { osalSysLock(); if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { osalSysUnlock(); return; } osalSysUnlock(); #ifdef NKRO_ENABLE if(keymap_config.nkro) { /* NKRO protocol */ /* need to wait until the previous packet has made it through */ /* can rewrite this using the synchronous API, then would wait * until *after* the packet has been transmitted. I think * this is more efficient */ /* busy wait, should be short and not very common */ osalSysLock(); if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread); } usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t)); osalSysUnlock(); } else #endif /* NKRO_ENABLE */ { /* boot protocol */ /* need to wait until the previous packet has made it through */ /* busy wait, should be short and not very common */ osalSysLock(); if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread); } usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE); osalSysUnlock(); } keyboard_report_sent = *report; }
/** * @brief Default EP0 SETUP callback. * @details This function is used by the low level driver as default handler * for EP0 SETUP events. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number, always zero * * @notapi */ void _usb_ep0setup(USBDriver *usbp, usbep_t ep) { size_t max; usbp->ep0state = USB_EP0_WAITING_SETUP; usbReadSetup(usbp, ep, usbp->setup); /* First verify if the application has an handler installed for this request.*/ if (!(usbp->config->requests_hook_cb) || !(usbp->config->requests_hook_cb(usbp))) { /* Invoking the default handler, if this fails then stalls the endpoint zero as error.*/ if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) || !default_handler(usbp)) { /* Error response, the state machine goes into an error state, the low level layer will have to reset it to USB_EP0_WAITING_SETUP after receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); _usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED); usbp->ep0state = USB_EP0_ERROR; return; } } #if (USB_SET_ADDRESS_ACK_HANDLING == USB_SET_ADDRESS_ACK_HW) if (usbp->setup[1] == USB_REQ_SET_ADDRESS) { /* Zero-length packet sent by hardware */ return; } #endif /* Transfer preparation. The request handler must have populated correctly the fields ep0next, ep0n and ep0endcb using the macro usbSetupTransfer().*/ max = usbFetchWord(&usbp->setup[6]); /* The transfer size cannot exceed the specified amount.*/ if (usbp->ep0n > max) usbp->ep0n = max; if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) { /* IN phase.*/ if (usbp->ep0n > 0) { /* Starts the transmit phase.*/ usbp->ep0state = USB_EP0_TX; usbPrepareTransmit(usbp, 0, usbp->ep0next, usbp->ep0n); osalSysLockFromISR(); usbStartTransmitI(usbp, 0); osalSysUnlockFromISR(); } else { /* No transmission phase, directly receiving the zero sized status packet.*/ usbp->ep0state = USB_EP0_WAITING_STS; #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) usbPrepareReceive(usbp, 0, NULL, 0); osalSysLockFromISR(); usbStartReceiveI(usbp, 0); osalSysUnlockFromISR(); #else usb_lld_end_setup(usbp, ep); #endif } } else { /* OUT phase.*/ if (usbp->ep0n > 0) { /* Starts the receive phase.*/ usbp->ep0state = USB_EP0_RX; usbPrepareReceive(usbp, 0, usbp->ep0next, usbp->ep0n); osalSysLockFromISR(); usbStartReceiveI(usbp, 0); osalSysUnlockFromISR(); } else { /* No receive phase, directly sending the zero sized status packet.*/ usbp->ep0state = USB_EP0_SENDING_STS; #if (USB_EP0_STATUS_STAGE == USB_EP0_STATUS_STAGE_SW) usbPrepareTransmit(usbp, 0, NULL, 0); osalSysLockFromISR(); usbStartTransmitI(usbp, 0); osalSysUnlockFromISR(); #else usb_lld_end_setup(usbp, ep); #endif } } }