257 lines
7.3 KiB
C
257 lines
7.3 KiB
C
#include "nrf.h"
|
|
|
|
#include "app_usbd.h"
|
|
#include "app_usbd_cdc_acm.h"
|
|
#include "app_usbd_cdc_types.h"
|
|
#include "app_usbd_serial_num.h"
|
|
|
|
#include "nrf_log.h"
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "message_buffer.h"
|
|
#include "semphr.h"
|
|
#include "stream_buffer.h"
|
|
#include "task.h"
|
|
|
|
#define DEBUG_ACM_CDC_READ 1
|
|
|
|
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usbd_cdc_acm_user_event_t event);
|
|
|
|
#define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN1
|
|
#define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN2
|
|
#define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT2
|
|
|
|
APP_USBD_CDC_ACM_GLOBAL_DEF(cdc_acm_inst,
|
|
cdc_acm_user_ev_handler,
|
|
NRF_CDC_ACM_COMM_INTERFACE,
|
|
NRF_CDC_ACM_DATA_INTERFACE,
|
|
CDC_ACM_COMM_EPIN,
|
|
CDC_ACM_DATA_EPIN,
|
|
CDC_ACM_DATA_EPOUT,
|
|
APP_USBD_CDC_COMM_PROTOCOL_AT_V250);
|
|
|
|
static SemaphoreHandle_t usbd_ready_rx_done_sem = NULL;
|
|
static SemaphoreHandle_t usbd_ready_tx_done_sem = NULL;
|
|
static SemaphoreHandle_t usbd_evt_queue_sem = NULL;
|
|
static MessageBufferHandle_t usbd_tx_message = NULL;
|
|
static MessageBufferHandle_t usbd_rx_message = NULL;
|
|
static bool is_port_closed = true;
|
|
|
|
static void usbd_isr_handler(app_usbd_internal_evt_t const *const p_event, bool queued)
|
|
{
|
|
if (queued)
|
|
{
|
|
BaseType_t xHigherPriorityTaskWoken = false;
|
|
xSemaphoreGiveFromISR(usbd_evt_queue_sem, &xHigherPriorityTaskWoken);
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
}
|
|
|
|
static void usbd_state_proc(app_usbd_event_type_t event)
|
|
{
|
|
switch (event)
|
|
{
|
|
case APP_USBD_EVT_DRV_SUSPEND:
|
|
break;
|
|
case APP_USBD_EVT_DRV_RESUME:
|
|
break;
|
|
case APP_USBD_EVT_STARTED:
|
|
NRF_LOG_INFO("APP_USBD_EVT_STARTED");
|
|
break;
|
|
case APP_USBD_EVT_STOPPED:
|
|
NRF_LOG_INFO("APP_USBD_EVT_STOPPED");
|
|
app_usbd_disable();
|
|
break;
|
|
case APP_USBD_EVT_POWER_DETECTED:
|
|
NRF_LOG_INFO("USB power detected");
|
|
if (!nrf_drv_usbd_is_enabled())
|
|
{
|
|
app_usbd_enable();
|
|
}
|
|
break;
|
|
case APP_USBD_EVT_POWER_REMOVED:
|
|
NRF_LOG_INFO("USB power removed");
|
|
app_usbd_stop();
|
|
break;
|
|
case APP_USBD_EVT_POWER_READY:
|
|
NRF_LOG_INFO("USB ready");
|
|
app_usbd_start();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void usbd_ser_send_task(void *p_arg)
|
|
{
|
|
static uint8_t buf[512];
|
|
for (;;)
|
|
{
|
|
size_t send_size = xStreamBufferReceive(usbd_tx_message, buf, sizeof(buf), portMAX_DELAY);
|
|
if (send_size && is_port_closed == false)
|
|
{
|
|
ret_code_t ret_code = app_usbd_cdc_acm_write(&cdc_acm_inst, buf, send_size);
|
|
switch (ret_code)
|
|
{
|
|
case NRF_SUCCESS:
|
|
xSemaphoreTake(usbd_ready_tx_done_sem, pdMS_TO_TICKS(1000));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usbd_cdc_acm_user_event_t event)
|
|
{
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
switch (event)
|
|
{
|
|
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
|
|
is_port_closed = false;
|
|
xSemaphoreGiveFromISR(usbd_ready_rx_done_sem, &xHigherPriorityTaskWoken);
|
|
break;
|
|
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
|
|
is_port_closed = true;
|
|
break;
|
|
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
|
|
xSemaphoreGiveFromISR(usbd_ready_tx_done_sem, &xHigherPriorityTaskWoken);
|
|
break;
|
|
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
|
|
xSemaphoreGiveFromISR(usbd_ready_rx_done_sem, &xHigherPriorityTaskWoken);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
|
|
static void usbd_ser_recv_task(void *arg)
|
|
{
|
|
static uint8_t recv[NRFX_USBD_EPSIZE];
|
|
static uint32_t recv_size;
|
|
for (;;)
|
|
{
|
|
if (is_port_closed)
|
|
{
|
|
xSemaphoreTake(usbd_ready_rx_done_sem, portMAX_DELAY);
|
|
}
|
|
|
|
taskENTER_CRITICAL();
|
|
xSemaphoreTake(usbd_ready_rx_done_sem, 0);
|
|
taskEXIT_CRITICAL();
|
|
|
|
ret_code_t ret_code = app_usbd_cdc_acm_read_any(&cdc_acm_inst, recv, NRFX_USBD_EPSIZE);
|
|
|
|
switch (ret_code)
|
|
{
|
|
case NRF_SUCCESS:
|
|
recv_size = xMessageBufferSend(usbd_rx_message, recv, app_usbd_cdc_acm_rx_size(&cdc_acm_inst), portMAX_DELAY);
|
|
break;
|
|
case NRF_ERROR_IO_PENDING:
|
|
xSemaphoreTake(usbd_ready_rx_done_sem, portMAX_DELAY);
|
|
recv_size = xMessageBufferSend(usbd_rx_message, recv, app_usbd_cdc_acm_rx_size(&cdc_acm_inst), portMAX_DELAY);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#if (DEBUG_ACM_CDC_READ == 1)
|
|
{
|
|
static uint8_t str[256];
|
|
memcpy(str, recv, recv_size);
|
|
str[recv_size] = '\0';
|
|
NRF_LOG_INFO("%s", str);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void usbd_evt_task(void *arg)
|
|
{
|
|
app_usbd_serial_num_generate();
|
|
|
|
app_usbd_config_t usbd_config = {
|
|
.ev_isr_handler = usbd_isr_handler,
|
|
.ev_state_proc = usbd_state_proc,
|
|
};
|
|
|
|
ret_code_t ret;
|
|
ret = app_usbd_init(&usbd_config);
|
|
APP_ERROR_CHECK(ret);
|
|
|
|
extern ret_code_t nrf_dfu_trigger_usb_init(void);
|
|
ret = nrf_dfu_trigger_usb_init();
|
|
APP_ERROR_CHECK(ret);
|
|
|
|
app_usbd_class_inst_t const *pxInst = app_usbd_cdc_acm_class_inst_get(&cdc_acm_inst);
|
|
ret = app_usbd_class_append(pxInst);
|
|
APP_ERROR_CHECK(ret);
|
|
|
|
app_usbd_enable();
|
|
|
|
app_usbd_start();
|
|
|
|
for (;;)
|
|
{
|
|
xSemaphoreTake(usbd_evt_queue_sem, portMAX_DELAY);
|
|
do {
|
|
} while (app_usbd_event_queue_process());
|
|
}
|
|
}
|
|
|
|
void usbd_init(void)
|
|
{
|
|
usbd_ready_rx_done_sem = xSemaphoreCreateBinary();
|
|
usbd_ready_tx_done_sem = xSemaphoreCreateBinary();
|
|
usbd_evt_queue_sem = xSemaphoreCreateBinary();
|
|
usbd_tx_message = xMessageBufferCreate(512);
|
|
usbd_rx_message = xMessageBufferCreate(512);
|
|
|
|
xTaskCreate(usbd_evt_task, "usb_evt", 1024, NULL, 3, NULL);
|
|
xTaskCreate(usbd_ser_recv_task, "usb_recv", 256, NULL, 3, NULL);
|
|
xTaskCreate(usbd_ser_send_task, "usb_send", 256, NULL, 3, NULL);
|
|
}
|
|
|
|
int32_t usbd_ser_write(uint8_t *p_data, uint32_t size, TickType_t timeout)
|
|
{
|
|
int32_t ret = 0;
|
|
|
|
if (size)
|
|
{
|
|
if (timeout)
|
|
{
|
|
xMessageBufferSend(usbd_tx_message, p_data, size, timeout);
|
|
}
|
|
else
|
|
{
|
|
taskENTER_CRITICAL();
|
|
xMessageBufferSend(usbd_tx_message, p_data, size, 0);
|
|
taskEXIT_CRITICAL();
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t usbd_ser_read(uint8_t *p_data, uint32_t size, TickType_t timeout)
|
|
{
|
|
int32_t ret = 0;
|
|
|
|
if (size)
|
|
{
|
|
if (timeout)
|
|
{
|
|
ret = xMessageBufferReceive(usbd_rx_message, p_data, size, timeout);
|
|
}
|
|
else
|
|
{
|
|
taskENTER_CRITICAL();
|
|
ret = xMessageBufferReceive(usbd_rx_message, p_data, size, 0);
|
|
taskEXIT_CRITICAL();
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|