[原创] [BearPi-Pico H2821]测评 ⑥丢包及连接稳定性测试

不爱胡萝卜的仓鼠   2024-8-27 11:16 楼主

上两篇我们查了一下SLE server和client端的demo,怎么运行的,收发应该调用那些接口已经清楚了,就可以开始做丢包及连接稳定性测试了

 

测试方案

server端代码不用动,client端连接server后,创建一个TASK,定时用SLE向server发数据,并计数,发送到最大次数后,停止发送,摧毁task。

然后提取双方日志,查看中途是否有断连、收发次数是否有缺少

 

1.client端代码修改

1.1 发送函数

参照之前找到的发送函数“sle_uart_client_read_int_handler”,写一个我自己用的发送函数,我把他放在sle_uart.c中

void my_sle_send_data(const char *buffer, uint16_t length)
{
    ssapc_write_param_t *sle_uart_send_param = get_g_sle_uart_send_param();
    uint16_t g_sle_uart_conn_id = get_g_sle_uart_conn_id();
    sle_uart_send_param->data_len = length;
    sle_uart_send_param->data = (uint8_t *)buffer;
    ssapc_write_req(0, g_sle_uart_conn_id, sle_uart_send_param);
}

然后需要声明一下函数,但是我没有找到在sle_uart.h,那就放到sle_uart_client.h中(虽然这样不太合适,但是我有点想偷懒,不想创建一个sle_uart.h)

void my_sle_send_data(const char *buffer, uint16_t length);

 

 

1.2 发送TASK的创建及摧毁函数

定时发送我选择创建一个task,专门用于发送。SDK的OS使用的是Lite OS,我之前没有用过,但是看了一下demo中串口TASK的创建代码,感觉和FreeRTOS差不多,而且SDK还套了一层OSAL,使用起来还是很简单的

 

1.2.1创建发送task函数

#define SLE_SEND_TASK_PRIO              28
#define SLE_SEND_TASK_STACK_SIZE        0x1200

osal_task *send_task_handle = NULL;

static void create_send_task(void)
{
    send_task_handle = osal_kthread_create((osal_kthread_handler)send_task, 0, "sendTask",
                                      SLE_SEND_TASK_STACK_SIZE);
    if (send_task_handle != NULL)
    {
        osal_kthread_set_priority(send_task_handle, SLE_SEND_TASK_PRIO);
    }
}

这里会创建一个TASK,名字叫“sendTask”

配置其stack的大小:SLE_SEND_TASK_STACK_SIZE

TASK实际干活的函数:send_task

如果创建成功,send_task_handle就会被赋值,那我们就可以拿着他去设置task的优先级为:SLE_SEND_TASK_PRIO

 

1.2.2摧毁发送task函数

static void destroy_send_task(void)
{
    osal_kthread_destroy(send_task_handle, 0);
}

摧毁函数很简单,就只要调用这一个函数即可,第一个参数时刚才我们创建task时得到的handle,第二个参数我没太理解,SDK的原文是如下

 * @param stop_flag [in] Indicates whether the current thread exits. If the value of stop_flag is 0,
 * The current thread does not exit. The stop flag is not 0.

指示当前线程是否退出,0:退出;非0:不退出。 我不太能理解,摧毁task不是就应该停止了吗?为什么还能摧毁task但是不退出线程?

 

1.3 实际干活的发送函数

#define SLE_SEND_CNT_MAX                10000

uint8_t g_sle_connect_state = 0;


static void *send_task(const char *arg)
{
    int send_cnt = 1;
    unused(arg);
    char data[34] = {"send test data, send cnt = 000000"};

    /* delay 5s,保证发现SSAP特征值等业务跑完 */
    osal_msleep(1000 * 5);
    while (1)
    {
        osal_printk("send task running\r\n");
        /* 检查一下是否连上 */
        if (g_sle_connect_state == 1)
        {
            snprintf(data, sizeof(data), "send test data, send cnt = %06d", send_cnt);
            osal_printk("send cnt = %06d\r\n", send_cnt);
            my_sle_send_data(data, sizeof(data) - 1);
            send_cnt++;
        }
        /* delay 500ms */
        osal_msleep(500);

        /* 判断是否发送到max */
        if (send_cnt > SLE_SEND_CNT_MAX)
        {
            osal_printk("******send test data over******\r\n");
            destroy_send_task();
        }
    }

    return NULL;
}

当发送task创建后,这个函数就会被运行,进来后我先delay一会儿。主要是为了保证交换MTU、发现特征值等操作完成,因为我会在连接成功后去创建task。之后就定时发送数据,每发送一次send_cnt就会+1,他会体现在日志和发送的数据中,便于后续分析日志。还会判断是否断连、是否发送到max次数。

如果断连我就不会再发送(这儿我不摧毁task,在断连的cb中我会摧毁task)

如果发送到max次数,我就会摧毁task

 

1.4 创建/摧毁发送task函数调用及连接状态标志位置位

我会在配对成功的cb中创建task。在连接成功cb中置连接标志位。(星闪连接有2步,连接+配对,那么我就认为配对成功才算是双方真正的连上了)

在断连cb中摧毁task并清除连接标志位。

/**
 * @brief		SLE client pair完成回调
 * @param[in]   conn_id 连接 ID。
 * @param[in]   addr    地址。
 * @param[in]   status  执行结果错误码。
 * [url=home.php?mod=space&uid=784970]@return[/url]      none
 */
void  sle_uart_client_sample_pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status)
{
    osal_printk("%s pair complete conn_id:%d, addr:%02x***%02x%02x\n", SLE_UART_CLIENT_LOG, conn_id,
                addr->addr[0], addr->addr[4], addr->addr[5]);
    if (status == 0)
    {
        ssap_exchange_info_t info = {0};
        info.mtu_size = SLE_MTU_SIZE_DEFAULT;
        info.version = 1;
        /* 请求交换SSAP信息 */
        ssapc_exchange_info_req(0, g_sle_uart_conn_id, &info);

        create_send_task();
    }
}

 

/**
 * @brief		SLE client 连接状态改变
 * @param[in]   conn_id    连接 ID。
 * @param[in]   addr       地址。
 * @param[in]   conn_state 连接状态 { [url=home.php?mod=space&uid=1064992]@ref[/url] sle_acb_state_t }。
 * @param[in]   pair_state 配对状态 { @ref sle_pair_state_t }。
 * @param[in]   disc_reason 断链原因 { @ref sle_disc_reason_t }。
 * @return      none
 */
static void sle_uart_client_sample_connect_state_changed_cbk(uint16_t conn_id, const sle_addr_t *addr,
                                                             sle_acb_state_t conn_state, sle_pair_state_t pair_state,
                                                             sle_disc_reason_t disc_reason)
{
    unused(addr);
    unused(pair_state);
    osal_printk("%s conn state changed disc_reason:0x%x\r\n", SLE_UART_CLIENT_LOG, disc_reason);
    g_sle_uart_conn_id = conn_id;
    /* 已经连上 */
    if (conn_state == SLE_ACB_STATE_CONNECTED)
    {
        g_sle_connect_state = 1;
        osal_printk("%s SLE_ACB_STATE_CONNECTED\r\n", SLE_UART_CLIENT_LOG);
        /* 配对状态是未配对 */
        if (pair_state == SLE_PAIR_NONE)
        {
            /* 开始配对 */
            sle_pair_remote_device(&g_sle_uart_remote_addr);
        }
#ifdef CONFIG_SAMPLE_SUPPORT_LOW_LATENCY_TYPE
        sle_uart_client_sample_set_phy_param();
        osal_msleep(SLE_UART_TASK_DELAY_MS);
        sle_low_latency_rx_enable();
        sle_low_latency_set(get_g_sle_uart_conn_id(), true, SLE_UART_LOW_LATENCY_2K);
        osal_printk("%s sle_low_latency_rx_enable \r\n", SLE_UART_CLIENT_LOG);      //这句话应该在这儿,不应该放外面
#endif  
    }
    /* 未连接(还能有未连接?怎么会有这种状态?) */
    else if (conn_state == SLE_ACB_STATE_NONE)
    {
        osal_printk("%s SLE_ACB_STATE_NONE\r\n", SLE_UART_CLIENT_LOG);
    }
    /* 断连 */
    else if (conn_state == SLE_ACB_STATE_DISCONNECTED)
    {
        g_sle_connect_state = 0;
        destroy_send_task();
        osal_printk("%s SLE_ACB_STATE_DISCONNECTED\r\n", SLE_UART_CLIENT_LOG);
        /* 移除配对设备 */
        sle_remove_paired_remote_device(&g_sle_uart_remote_addr);
        /* 再次开启SCAN */
        sle_uart_start_scan();
    }
    /* 其他未知情况 */
    else
    {
        osal_printk("%s status error\r\n", SLE_UART_CLIENT_LOG);
    }
}

 

好了,代码的修改到此就完成了。我把整个代码仓放到github上了,https://github.com/BUYITAO/StarLink_BearPi-Pico-H2821

 

2.测试及结果

server端先上电,然后client上电。之后代码会自动连上,自动发数据。我代码中设置的是500ms发送一次,总共发送1W次。等着他跑完看日志即可。

 

测试环境:正常办公环境(环境中大约有50多个BLE设备在ADV,连接的BLE数量未知,但数量也不会太少,这个环境对于BLE是会有一点影响,不过我们是SLE,应该没啥影响)。板卡距离:1m

 

server.jpg
client.jpg

测试结果:未断连,为丢包。(日志附件)

 

server日志.DAT (1.22 MB)
(下载次数: 5, 2024-8-27 11:14 上传)
client日志.DAT (2.1 MB)
(下载次数: 4, 2024-8-27 11:14 上传)
本帖最后由 不爱胡萝卜的仓鼠 于 2024-8-27 11:14 编辑

回复评论 (7)

短距离不丢包很正常

点赞  2024-8-27 13:57

仓鼠老师,我下载您文中github链接的代码仓,搜索不到my_sle_send_data、create_send_task……等等这些函数和相关的变量、定义啊,请问是后来修改了吗

另外,创建发送task函数时,这个函数应该创建在哪里呢?

点赞  2024-10-22 14:00
引用: 晚风吹散 发表于 2024-10-22 14:00 仓鼠老师,我下载您文中github链接的代码仓,搜索不到my_sle_send_data、create_send_task…… ...

你下载下来后要把当前分支置到最新的一次提交,默认拉下来应该是在首次提交的那个位置上

点赞 (1) 2024-10-22 14:19
引用: 不爱胡萝卜的仓鼠 发表于 2024-10-22 14:19 你下载下来后要把当前分支置到最新的一次提交,默认拉下来应该是在首次提交的那个位置上

好的,非常感谢!

点赞  2024-10-23 09:31

另外想咨询您几个问题,不胜感激:

1. 海思Hispark IDE中,当我在系统配置 - application 中,切换了Server sample / Client sample后,需要重新编译一遍吗?

image.png  

 

2. 您有遇到过,sle_uart.c里,“#if defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_SERVER)”下的内容,和 “#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT)”下的内容,全部都是暗色的情况吗?

IDE似乎默认这两个define都没有生效,故而全部置灰(但烧录的程序可以正常运行)。这给我的代码阅读、修改带来了很大困扰。

image.png  

image.png  

  • image.png
点赞  2024-10-23 17:09
引用: 晚风吹散 发表于 2024-10-23 17:09 另外想咨询您几个问题,不胜感激: 1. 海思Hispark IDE中,当我在系统配置 - application 中,切换了Ser ...

需要重新编译,他本质上就是设置编译脚本中的define,为了避免这个值在某个.h中有使用,最好是清除全编一次。

 

第二个问题,也是由上面的事情导致的,他这个define是没有明确的值的,只有在编译时才会从编译脚本中得到,当vscode读.c.h文件时他是无法得到define的具体值,那他就按默认值来了,所以他显示的和你配置的会不一致

点赞 (1) 2024-10-25 10:03
引用: 不爱胡萝卜的仓鼠 发表于 2024-10-25 10:03 需要重新编译,他本质上就是设置编译脚本中的define,为了避免这个值在某个.h中有使用,最好是清除全编一 ...

好的,再次感谢您

点赞  2024-10-25 11:16
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复