// The function returns false to signal that no more bytes can be passed to be // sent (put into the TX buffer) until UART transmission is done. static bool tx_buf_put(uint8_t data_byte) { ASSERT(m_tx_bytes < SER_PHY_HCI_SLIP_TX_BUF_SIZE); mp_tx_buf[m_tx_bytes] = data_byte; ++m_tx_bytes; bool flush = false; ser_phy_hci_slip_evt_type_t slip_evt_type = NO_EVENT; if (m_tx_phase == PHASE_ACK_END) { // Send buffer, then signal that an acknowledge packet has been sent. flush = true; slip_evt_type = SER_PHY_HCI_SLIP_EVT_ACK_SENT; } else if (m_tx_phase == PHASE_PACKET_END) { // Send buffer, then signal that a packet with payload has been sent. flush = true; slip_evt_type = SER_PHY_HCI_SLIP_EVT_PKT_SENT; } else if (m_tx_bytes >= SER_PHY_HCI_SLIP_TX_BUF_SIZE) { // Send buffer (because it is filled up), but don't signal anything, // since the packet sending is not complete yet. flush = true; } if (flush) { // If some TX transfer is being done at the moment, a new one cannot be // started, it must be scheduled to be performed later. if (m_tx_in_progress) { m_tx_pending_evt_type = slip_evt_type; m_tx_pending = true; // No more buffers available, can't continue filling. return false; } if (m_port_open) { m_tx_in_progress = true; m_tx_evt_type = slip_evt_type; APP_ERROR_CHECK(app_usbd_cdc_acm_write(&m_app_cdc_acm, mp_tx_buf, m_tx_bytes)); } // Switch to the second buffer. mp_tx_buf = (mp_tx_buf == m_tx_buf0) ? m_tx_buf1 : m_tx_buf0; m_tx_bytes = 0; } return true; }
static ret_code_t cli_cdc_acm_write(const void * p_data, size_t length, size_t * p_cnt) { ret_code_t ret; do { ret = app_usbd_cdc_acm_write(&nrf_cli_cdc_acm, p_data, length); if (ret == NRF_SUCCESS && p_cnt) { *p_cnt = length; } } while(ret == NRF_ERROR_BUSY); return ret; }
static void processTransmit(void) { // If some data was requested to send while port was closed, send it now. if ((sUsbState.mTxBuffer != NULL) && isPortOpened()) { if (app_usbd_cdc_acm_write(&sAppCdcAcm, sUsbState.mTxBuffer, sUsbState.mTxSize) == NRF_SUCCESS) { sUsbState.mTransferInProgress = true; sUsbState.mTxBuffer = NULL; sUsbState.mTxSize = 0; } } else if (sUsbState.mTransferDone) { otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "otPlatUartSendDone"); sUsbState.mTransferDone = false; sUsbState.mTransferInProgress = false; otPlatUartSendDone(); } }
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength) { otError error = OT_ERROR_NONE; otEXPECT_ACTION(sUsbState.mTransferInProgress == false, error = OT_ERROR_BUSY); otEXPECT_ACTION(sUsbState.mTxBuffer == NULL, error = OT_ERROR_BUSY); if (!isPortOpened()) { // If port is closed, queue the message until it can be sent. sUsbState.mTxBuffer = aBuf; sUsbState.mTxSize = aBufLength; } else { otEXPECT_ACTION(app_usbd_cdc_acm_write(&sAppCdcAcm, aBuf, aBufLength) == NRF_SUCCESS, error = OT_ERROR_FAILED); sUsbState.mTransferInProgress = true; } exit: return error; }
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_cdc_acm_user_event_t event) { app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst); switch (event) { case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: NRF_LOG_DEBUG("EVT_PORT_OPEN"); if (!m_port_open) { ret_code_t ret_code; m_port_open = true; do { ret_code = app_usbd_cdc_acm_read(p_cdc_acm, &m_rx_byte, 1); if (ret_code == NRF_SUCCESS) { ser_phi_hci_rx_byte(m_rx_byte); } else if (ret_code != NRF_ERROR_IO_PENDING) { APP_ERROR_CHECK(ret_code); } } while (ret_code == NRF_SUCCESS); } break; case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE: NRF_LOG_DEBUG("EVT_PORT_CLOSE"); if (m_tx_in_progress) { m_ser_phy_hci_slip_event.evt_type = SER_PHY_HCI_SLIP_EVT_PKT_SENT; m_ser_phy_hci_slip_event_handler(&m_ser_phy_hci_slip_event); m_tx_in_progress = false; } m_port_open = false; break; case APP_USBD_CDC_ACM_USER_EVT_TX_DONE: // If there is a pending transfer (the second buffer is ready to // be sent), start it immediately. if (m_tx_pending) { APP_ERROR_CHECK(app_usbd_cdc_acm_write(p_cdc_acm, mp_tx_buf, m_tx_bytes)); // Switch to the buffer that has just been sent completely // and now can be filled again. mp_tx_buf = (mp_tx_buf == m_tx_buf0) ? m_tx_buf1 : m_tx_buf0; m_tx_bytes = 0; m_ser_phy_hci_slip_event.evt_type = m_tx_evt_type; m_tx_evt_type = m_tx_pending_evt_type; m_tx_pending = false; } else { m_tx_in_progress = false; m_ser_phy_hci_slip_event.evt_type = m_tx_evt_type; } // If needed, notify the upper layer that the packet transfer is // complete (note that this notification may result in another // packet send request, so everything must be cleaned up above). if (m_ser_phy_hci_slip_event.evt_type != NO_EVENT) { m_ser_phy_hci_slip_event_handler(&m_ser_phy_hci_slip_event); } // And if the sending process is not yet finished, look what is // to be done next. if (m_tx_phase != PHASE_IDLE) { tx_buf_fill(); } break; case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: { ret_code_t ret_code; do { ser_phi_hci_rx_byte(m_rx_byte); ret_code = app_usbd_cdc_acm_read(p_cdc_acm, &m_rx_byte, 1); } while (ret_code == NRF_SUCCESS); } break; default: break; } }