我想要将usbd_cdc_acm
中的usbd_user_ev_handler
和cdc_acm_user_ev_handler
嵌入到light_switch_client
当中,来代替原来light_switch_client
中的button_event_handler
,从而实现我通过串口助手向usb
发送简单的命令如'on', 'off'字符串,然后通过此来发送generic_onoff_client_set
等操作而不是通过按钮
将usbd_cdc_acm嵌入到light_switch_client出现的问题
现在我遇到的问题是,当我对串口发送任意字符时,开发板会出现如下的状况
然后卡住
相关代码如下:
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:
{
/*Set up the first transfer*/
ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
m_cdc_data_array,
1);
UNUSED_VARIABLE(ret);
//ret = app_timer_stop(m_blink_cdc);
//APP_ERROR_CHECK(ret);
//bsp_board_led_on(LED_CDC_ACM_CONN);
//NRF_LOG_INFO("CDC ACM port opened");
break;
}
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
//NRF_LOG_INFO("CDC ACM port closed");
//if (m_usb_connected)
//{
// ret_code_t ret = app_timer_start(m_blink_cdc,
// APP_TIMER_TICKS(LED_BLINK_INTERVAL),
// (void *) LED_CDC_ACM_CONN);
// APP_ERROR_CHECK(ret);
//}
break;
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
break;
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
{
generic_onoff_set_params_t set_params;
model_transition_t transition_params;
static uint8_t tid = 0;
set_params.tid = tid++;
if (tid % 2 == 0) set_params.on_off = APP_STATE_OFF;
else set_params.on_off = APP_STATE_ON;
transition_params.delay_ms = APP_ONOFF_DELAY_MS;
transition_params.transition_time_ms = APP_ONOFF_TRANSITION_TIME_MS;
(void)access_model_reliable_cancel(m_clients[0].model_handle);
(void)generic_onoff_client_set(&m_clients[0], &set_params, &transition_params);
hal_led_pin_set(BSP_LED_0, set_params.on_off);
//ret_code_t ret;
//static uint8_t index = 0;
//index++;
//do
//{
// if ((m_cdc_data_array[index - 1] == '\n') ||
// (m_cdc_data_array[index - 1] == '\r') ||
// (index >= (244)))
// {
// if (index > 1)
// {
// uint16_t length = (uint16_t)index;
// if (length + sizeof(ENDLINE_STRING) < 244)
// {
// memcpy(m_cdc_data_array + length, ENDLINE_STRING, sizeof(ENDLINE_STRING));
// length += sizeof(ENDLINE_STRING);
// }
// generic_onoff_set_params_t set_params;
// model_transition_t transition_params;
// static uint8_t tid = 0;
// if (m_cdc_data_array[0] == 'o' && m_cdc_data_array[1] == "n") {
// set_params.on_off = APP_STATE_ON;
// } else {
// set_params.on_off = APP_STATE_OFF;
// }
// set_params.tid = tid++;
// transition_params.delay_ms = APP_ONOFF_DELAY_MS;
// transition_params.transition_time_ms = APP_ONOFF_TRANSITION_TIME_MS;
// (void)access_model_reliable_cancel(m_clients[0].model_handle);
// (void)generic_onoff_client_set(&m_clients[0], &set_params, &transition_params);
// hal_led_pin_set(BSP_LED_0, set_params.on_off);
// }
// index = 0;
// }
// /*Get amount of data transferred*/
// //size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
// //NRF_LOG_DEBUG("RX: size: %lu char: %c", size, m_cdc_data_array[index - 1]);
// /* Fetch data until internal buffer is empty */
// ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
// &m_cdc_data_array[index],
// 1);
// if (ret == NRF_SUCCESS)
// {
// index++;
// }
//}
//while (ret == NRF_SUCCESS);
//break;
}
default:
break;
}
}
static void usbd_user_ev_handler(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:
break;
case 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");
//ret_code_t err_code = app_timer_stop(m_blink_cdc);
//APP_ERROR_CHECK(err_code);
//bsp_board_led_off(LED_CDC_ACM_CONN);
m_usb_connected = false;
app_usbd_stop();
}
break;
case APP_USBD_EVT_POWER_READY:
{
//NRF_LOG_INFO("USB ready");
//ret_code_t err_code = app_timer_start(m_blink_cdc,
// APP_TIMER_TICKS(LED_BLINK_INTERVAL),
// (void *) LED_CDC_ACM_CONN);
//APP_ERROR_CHECK(err_code);
m_usb_connected = true;
app_usbd_start();
}
break;
default:
break;
}
}
zqaking 你可以参考官方的cdc的示例工程,或者可以利用rtt实现输入或输出的功能
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE
:原来我引用的也是官方例程,之前也是卡起了,然后改成这样了。
不过这样显然更不行,没有判断回车换行符,好像输入的时候一直卡在这里。因此我又改回原来的
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
{
ret_code_t ret;
static uint8_t index = 0;
static char StrTrue[] = "begin is ok\r\r\n";
static char StrFalse[] = "end is ok\r\r\n";
static char cmp[] = "on\r\r\n";
index++;
do
{
if ((m_cdc_data_array[index - 1] == '\n') ||
(m_cdc_data_array[index - 1] == '\r') ||
(index >= (244)))
{
if (index > 1)
{
generic_onoff_set_params_t set_params;
model_transition_t transition_params;
uint32_t status = NRF_SUCCESS;
static uint8_t tid = 0;
nrf_gpio_pin_toggle(BSP_LED_0);
uint16_t length = (uint16_t)index;
if (length + sizeof(ENDLINE_STRING) < 244)
{
memcpy(m_cdc_data_array + length, ENDLINE_STRING, sizeof(ENDLINE_STRING));
length += sizeof(ENDLINE_STRING);
}
if (strcmp(m_cdc_data_array, cmp) == 0)
set_params.on_off = APP_STATE_ON;
else
set_params.on_off = APP_STATE_OFF;
set_params.tid = tid++;
transition_params.delay_ms = APP_ONOFF_DELAY_MS;
transition_params.transition_time_ms = APP_ONOFF_TRANSITION_TIME_MS;
//(void)access_model_reliable_cancel(m_clients[0].model_handle);
app_usbd_cdc_acm_write(&m_app_cdc_acm, StrTrue, sizeof(StrTrue) / sizeof(StrTrue[0]));
status = generic_onoff_client_set_unack(&m_clients[1], &set_params,
&transition_params, APP_UNACK_MSG_REPEAT_COUNT);
app_usbd_cdc_acm_write(&m_app_cdc_acm, StrFalse, sizeof(StrFalse) / sizeof(StrFalse[0]));
}
index = 0;
}
/*Get amount of data transferred*/
//size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
//NRF_LOG_DEBUG("RX: size: %lu char: %c", size, m_cdc_data_array[index - 1]);
/* Fetch data until internal buffer is empty */
ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
&m_cdc_data_array[index],
1);
if (ret == NRF_SUCCESS)
{
index++;
}
}
while (ret == NRF_SUCCESS);
break;
}
但这个的问题就是在配置app key成功后再通过generic_onoff_client_set_unack()就会卡起,其他情况正常。
zqaking 你可以单步跳进generic_onoff_client_set_unack()这个函数看看吗?我一时半会也看不出什么问题
Wireless-Tech
抱歉,额。我通过另一种方式解决了这个问题。
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
{
ret_code_t ret;
static uint8_t index = 0;
index++;
do
{
if ((m_cdc_data_array[index - 1] == '\n') ||
(m_cdc_data_array[index - 1] == '\r') ||
(index >= (244)))
{
if (index > 1)
{
nrf_gpio_pin_toggle(BSP_LED_0);
uint16_t length = (uint16_t)index;
if (length + sizeof(ENDLINE_STRING) < 244)
{
memcpy(m_cdc_data_array + length, ENDLINE_STRING, sizeof(ENDLINE_STRING));
length += sizeof(ENDLINE_STRING);
}
if (strcmp(m_cdc_data_array, "on\r\r\n") == 0) SetState = true;
else SetState = false;
DataChange = true;
}
index = 0;
}
/* Fetch data until internal buffer is empty */
ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
&m_cdc_data_array[index],
1);
if (ret == NRF_SUCCESS)
{
index++;
}
}
while (ret == NRF_SUCCESS);
break;
}
在这里我添加了一个DataChange
变量来判断一次USB CDC ACM
事件。然后自定义一个定时器对此的触发事件
APP_TIMER_DEF(zqaking_timer_id);
static void zqaking_app_timer_handler(void * p_unused)
{
if (DataChange)
{
//app_usbd_cdc_acm_write(&m_app_cdc_acm, my_data_buffer, my_data_buffer_lenght);
DataChange = false;
uint32_t status;
generic_onoff_set_params_t set_params;
model_transition_t transition_params;
static uint8_t tid = 0;
if (SetState) set_params.on_off = APP_STATE_ON;
else set_params.on_off = APP_STATE_OFF;
SetState = false;
set_params.tid = tid++;
transition_params.delay_ms = APP_ONOFF_DELAY_MS;
transition_params.transition_time_ms = APP_ONOFF_TRANSITION_TIME_MS;
status = hx_model_client_opcode_tx_unreliable(&m_hx_model_client[0], (uint8_t *)str, (uint16_t)StrLen, APP_UNACK_MSG_REPEAT_COUNT);
if (status == NRF_SUCCESS) app_usbd_cdc_acm_write(&m_app_cdc_acm, str, StrLen);
status = generic_onoff_client_set_unack(&m_clients[1], &set_params,
&transition_params, APP_UNACK_MSG_REPEAT_COUNT);
}
}
static void start(void)
{ ···
ERROR_CHECK(app_timer_create(&zqaking_timer_id, APP_TIMER_MODE_REPEATED, zqaking_app_timer_handler));
ERROR_CHECK(app_timer_start(zqaking_timer_id, 6000, NULL));
···
};
zqaking
这样就能成功发送,之前不行的原因我觉得可能是USB
和mesh
之间有时钟的冲突。因为我在这个过程中乱尝试的时候,添加的定时器是app_timer.c
中timer2
,然后也出现了相类似的情况也是卡住四个led灯全亮。后来才知道它和mesh
使用的app_timer_mesh.c
不能够兼容。不过我不太确定是否真的是这样
另外说明一下
ERROR_CHECK(app_timer_create(&zqaking_timer_id, APP_TIMER_MODE_REPEATED, zqaking_app_timer_handler));
ERROR_CHECK(app_timer_start(zqaking_timer_id, 6000, NULL));
我在使用app_timer_mesh
本来使用了APP_TIMER_TICKS
,但是好像没有成功,重新改为6000
才好。不知道是不是两类定时器之间的差别
Wireless-Tech
还是感谢大佬让我看RTT
内容,发现RTT
中定时器才想到这个方法