244 lines
8.2 KiB
C
244 lines
8.2 KiB
C
/**
|
|
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form, except as embedded into a Nordic
|
|
* Semiconductor ASA integrated circuit in a product or a software update for
|
|
* such product, must reproduce the above copyright notice, this list of
|
|
* conditions and the following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* 4. This software, with or without modification, must only be used with a
|
|
* Nordic Semiconductor ASA integrated circuit.
|
|
*
|
|
* 5. Any software provided in binary form under this license must not be reverse
|
|
* engineered, decompiled, modified and/or disassembled.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
#include "sdk_common.h"
|
|
#if NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
|
|
#include "nrf_cli_cdc_acm.h"
|
|
#include "nrf_queue.h"
|
|
#include "app_error.h"
|
|
#include "nrf_assert.h"
|
|
|
|
|
|
#if APP_USBD_CONFIG_EVENT_QUEUE_ENABLE
|
|
#error "Current CLI CDC implementation supports only USB with event queue disabled (see APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)"
|
|
#endif
|
|
|
|
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
|
|
app_usbd_cdc_acm_user_event_t event);
|
|
|
|
/*lint -save -e26 -e40 -e64 -e123 -e505 -e651*/
|
|
|
|
/**
|
|
* @brief CDC_ACM class instance.
|
|
* */
|
|
APP_USBD_CDC_ACM_GLOBAL_DEF(nrf_cli_cdc_acm,
|
|
cdc_acm_user_ev_handler,
|
|
NRF_CLI_CDC_ACM_COMM_INTERFACE,
|
|
NRF_CLI_CDC_ACM_DATA_INTERFACE,
|
|
NRF_CLI_CDC_ACM_COMM_EPIN,
|
|
NRF_CLI_CDC_ACM_DATA_EPIN,
|
|
NRF_CLI_CDC_ACM_DATA_EPOUT,
|
|
APP_USBD_CDC_COMM_PROTOCOL_AT_V250
|
|
);
|
|
|
|
/*lint -restore*/
|
|
|
|
NRF_QUEUE_DEF(uint8_t,
|
|
m_rx_queue,
|
|
2*NRF_DRV_USBD_EPSIZE,
|
|
NRF_QUEUE_MODE_OVERFLOW);
|
|
|
|
static char m_rx_buffer[NRF_DRV_USBD_EPSIZE];
|
|
|
|
static nrf_cli_cdc_acm_internal_t * mp_internal;
|
|
|
|
/**
|
|
* @brief Set new buffer and process any data if already present
|
|
*
|
|
* This is internal function.
|
|
* The result of its execution is the library waiting for the event of the new data.
|
|
* If there is already any data that was returned from the CDC internal buffer
|
|
* it would be processed here.
|
|
*/
|
|
static void cdc_acm_process_and_prepare_buffer(app_usbd_cdc_acm_t const * p_cdc_acm)
|
|
{
|
|
for (;;)
|
|
{
|
|
if (!nrf_queue_is_empty(&m_rx_queue))
|
|
{
|
|
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, mp_internal->p_cb->p_context);
|
|
}
|
|
ret_code_t ret = app_usbd_cdc_acm_read_any(&nrf_cli_cdc_acm,
|
|
m_rx_buffer,
|
|
sizeof(m_rx_buffer));
|
|
if (ret == NRF_SUCCESS)
|
|
{
|
|
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
|
|
size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
|
|
ASSERT(size == qsize);
|
|
UNUSED_VARIABLE(qsize);
|
|
}
|
|
else if (ret == NRF_ERROR_IO_PENDING)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
APP_ERROR_CHECK(ret);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief User event handler.
|
|
* */
|
|
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:
|
|
{
|
|
/*Setup first transfer*/
|
|
cdc_acm_process_and_prepare_buffer(p_cdc_acm);
|
|
break;
|
|
}
|
|
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
|
|
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, mp_internal->p_cb->p_context);
|
|
break;
|
|
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
|
|
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, mp_internal->p_cb->p_context);
|
|
break;
|
|
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
|
|
{
|
|
/*Get amount of data transfered*/
|
|
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
|
|
size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
|
|
ASSERT(size == qsize);
|
|
UNUSED_VARIABLE(qsize);
|
|
|
|
/*Setup next transfer*/
|
|
cdc_acm_process_and_prepare_buffer(p_cdc_acm);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static ret_code_t cli_cdc_acm_init(nrf_cli_transport_t const * p_transport,
|
|
void const * p_config,
|
|
nrf_cli_transport_handler_t evt_handler,
|
|
void * p_context)
|
|
{
|
|
UNUSED_PARAMETER(p_config);
|
|
nrf_cli_cdc_acm_internal_t * p_internal =
|
|
CONTAINER_OF(p_transport, nrf_cli_cdc_acm_internal_t, transport);
|
|
p_internal->p_cb->handler = evt_handler;
|
|
p_internal->p_cb->p_context = p_context;
|
|
|
|
mp_internal = p_internal;
|
|
return NRF_SUCCESS;
|
|
}
|
|
|
|
static ret_code_t cli_cdc_acm_uninit(nrf_cli_transport_t const * p_transport)
|
|
{
|
|
UNUSED_PARAMETER(p_transport);
|
|
return NRF_SUCCESS;
|
|
}
|
|
|
|
static ret_code_t cli_cdc_acm_enable(nrf_cli_transport_t const * p_transport,
|
|
bool blocking)
|
|
{
|
|
UNUSED_PARAMETER(p_transport);
|
|
if (blocking)
|
|
{
|
|
return NRF_ERROR_NOT_SUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
return NRF_SUCCESS;
|
|
}
|
|
}
|
|
|
|
static ret_code_t cli_cdc_acm_read(nrf_cli_transport_t const * p_transport,
|
|
void * p_data,
|
|
size_t length,
|
|
size_t * p_cnt)
|
|
{
|
|
ASSERT(p_cnt);
|
|
UNUSED_PARAMETER(p_transport);
|
|
size_t size = nrf_queue_out(&m_rx_queue, p_data, length);
|
|
*p_cnt = size;
|
|
|
|
return NRF_SUCCESS;
|
|
}
|
|
|
|
static ret_code_t cli_cdc_acm_write(nrf_cli_transport_t const * p_transport,
|
|
void const * p_data,
|
|
size_t length,
|
|
size_t * p_cnt)
|
|
{
|
|
ASSERT(p_cnt);
|
|
UNUSED_PARAMETER(p_transport);
|
|
ret_code_t ret;
|
|
|
|
ret = app_usbd_cdc_acm_write(&nrf_cli_cdc_acm, p_data, length);
|
|
if (ret == NRF_SUCCESS || ret == NRF_ERROR_INVALID_STATE)
|
|
{
|
|
*p_cnt = length;
|
|
ret = NRF_SUCCESS;
|
|
}
|
|
else if (ret == NRF_ERROR_BUSY)
|
|
{
|
|
*p_cnt = 0;
|
|
ret = NRF_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Nothing to do */
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
const nrf_cli_transport_api_t nrf_cli_cdc_acm_transport_api = {
|
|
.init = cli_cdc_acm_init,
|
|
.uninit = cli_cdc_acm_uninit,
|
|
.enable = cli_cdc_acm_enable,
|
|
.read = cli_cdc_acm_read,
|
|
.write = cli_cdc_acm_write,
|
|
};
|
|
|
|
#endif // NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
|