说一下最无语的一个开发经历吧,之前开发一个智能家居的WiFi模组,具体哪家的就不说了,用到的主要功能就是UART,WIFI,MQTT,BLE
等功能,大体流程是是手机通过蓝牙将配网信息发送给WiFi模组,WiFi模组连接上网络后将串口数据通过MQTT发送到平台,同时还可以将平台的数据通过UART
发给设备,实现远程控制的目的,开发过程中简直就是一步一个坑啊:
UART:
UART
部分初始化代码如下(省略一些配置):
int uart_getchar(char *inbuf, int *len)
{
if (inbuf == NULL)
{
os_printf("inbuf_null\r\n");
return 0;
}
while (bk_uart_recv(UART_DEMO_POART1, &inbuf[*len], 1, BEKEN_WAIT_FOREVER) == 0)
{
if (*len >= IN_SIZE)//每次中断读取最大量为19字节,长数据会多次触发 连续读取,以下为数据长度判断
{
*len = 0;
overflow = 1;
return -1;
}
if (overflow == 1 && inbuf[*len] == '\r')
{
os_printf("Error: input buffer overflow\r\n");
*len = 0;
overflow = 0;
return -1;
}
if (inbuf[*len] == '\n')//以回车判断数据结尾
continue;
if (inbuf[*len] == '\r')
{
inbuf[*len] = '\0';
*len = 0;
return 1;
}
(*len)++;
}
return 0;
}
static void uart_recv_sema_callback(int uport, void *param)
{
uint32_t cont = bk_uart_get_length_in_buffer(UART_DEMO_POART1);
os_printf("bk_uart_get_length_in_buffer:%d\r\n", cont);
rtos_set_semaphore(&rx_sema);
}
void uart_dome_init(void)
{
int ret = -1, cont = 0;
char rbuff[IN_SIZE] = {0};
bk_uart_initialize(UART_DEMO_POART1, &demo_uart1_config[0], NULL);
rtos_init_semaphore(&rx_sema, 32);
bk_uart_set_rx_callback(UART_DEMO_POART1, uart_recv_sema_callback, NULL);
while (1)
{
if (rtos_get_semaphore(&rx_sema, BEKEN_WAIT_FOREVER) == kNoErr);
{
ret = uart_getchar(rbuff, &cont);
if (ret == 1)
{
ret = 0;
demo_uart_test_send(rbuff, cont);
cont = 0;
}
}
}
}
从demo上看初始化了一个回调函数uart_recv_sema_callback
,以为时串口接收完成一段数据会进入回调,其实不然。长度小于21的数据进一次回调,超过21的会进回调多次,也许就是初始化信号量数量为32的原因。由于串口协议没最后的回车换行,所以用这个demo无法判断数据结束,使用串口发给模组发一组数据日志如下:
bk_uart_get_length_in_buffer:21
bk_uart_get_length_in_buffer:41
bk_uart_get_length_in_buffer:61
bk_uart_get_length_in_buffer:81
bk_uart_get_length_in_buffer:101
bk_uart_get_length_in_buffer:121
uart rx fifo full
bk_uart_get_length_in_buffer:128
由于发送数据超过了128字节(RX FIFO最大128字节),日志里面有底层输出uart rx fifo full
,最大就只能接收128字节。这样子主循环里面会多次收到信号量,进行多次循环,与开发需求不符,稍作修改如下:
int uart_getchar(char *inbuf, int timeout)
{
uint8_t length = 0, length_1 = 0;
for(int i = 0; i <= timeout; i ++)
{
length_1 = bk_uart_get_length_in_buffer(UART_DEMO_POART1);
if (length_1 == length)
{
i ++;
}
else
{
i = 0;
length = length_1;
}
rtos_delay_milliseconds(1);
}
bk_uart_recv(UART_DEMO_POART1, inbuf, length, BEKEN_NO_WAIT);
return length;
}
void uart_dome_init(void)
{
int cont = 0, timeout = 3;
char rbuff[128] = {0};
rtos_init_semaphore(&au_rx_sema, 9);
bk_uart_initialize(UART_DEMO_POART1, &au_uart_config[0], NULL);
bk_uart_set_rx_callback( UART_DEMO_POART1, au_rx_callback, NULL);
bk_uart_send(UART_DEMO_POART1, "1234567890ABCDEFGHIJKLMNOPQRSTUVWSYZ", 36);
while(true)
{
if (rtos_get_semaphore(&au_rx_sema, BEKEN_WAIT_FOREVER) == kNoErr)
{
cont = uart_getchar(rbuff, timeout);
os_printf("uart cont:%d\r\n", cont);
if(0 != cont)
{
print_hex_dump("UART:", rbuff, cont);
}
}
}
}
给模组发数据日志如下:
bk_uart_get_length_in_buffer:21
bk_uart_get_length_in_buffer:41
bk_uart_get_length_in_buffer:61
bk_uart_get_length_in_buffer:81
bk_uart_get_length_in_buffer:101
bk_uart_get_length_in_buffer:121
bk_uart_get_length_in_buffer:121
uart cont:121
UART:31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31
uart cont:0
uart cont:0
uart cont:0
uart cont:0
uart cont:0
uart cont:0
现象:还是会进中断多次,可以自动判断数据结束,一次发送数据不能超过128字节,遵循能用就行
的原则,暂且先这么用,屏蔽掉回调里面的日志就可以了。后面如果有发送是数据量比较大的情况可以更改一下uart_getchar
的逻辑。中间也做过一些其他的尝试,例如使用OSStatus bk_uart_recv( bk_uart_t uart, void *data, uint32_t size, uint32_t timeout );
超时机制,无论timeout
设置为多少,现象都是一样,查看源码才发现该参数直接没有用,没有用,没有用。还有就是API手册和SDK根本对不上,对不上,对不上。
WIFI:
WiFi连接过程中有时候带汉字的WiFi名称连接不上,查看demo发现在连接之前有个UTF-8的转换:
就是这个函数,通过蓝牙发过来的数据编码格式就是UTF-8
,这里再转换一下反而出错了。将蓝牙发过来的数据格式改成GB-2312
或者将此处的转换删除即可。
简直了,以后选型模组还是需要先看下资料是否齐全,省的全网都找不到资料,只有一个多年没有维护的API手册还与SDK对应不上,开发过程极其不爽。