不爱胡萝卜的仓鼠 发表于 2024-8-27 11:16

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

<div class='showpostmsg'> 本帖最后由 不爱胡萝卜的仓鼠 于 2024-8-27 11:14 编辑

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

<p>&nbsp;</p>

<p><strong><span style="font-size:24px;">测试方案</span></strong></p>

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

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

<p>&nbsp;</p>

<p><strong><span style="font-size:24px;">1.client端代码修改</span></strong></p>

<p><strong><span style="font-size:18px;">1.1 发送函数</span></strong></p>

<p>参照之前找到的发送函数&ldquo;sle_uart_client_read_int_handler&rdquo;,写一个我自己用的发送函数,我把他放在sle_uart.c中</p>

<pre>
<code class="language-cpp">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-&gt;data_len = length;
    sle_uart_send_param-&gt;data = (uint8_t *)buffer;
    ssapc_write_req(0, g_sle_uart_conn_id, sle_uart_send_param);
}
</code></pre>

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

<pre>
<code class="language-cpp">void my_sle_send_data(const char *buffer, uint16_t length);
</code></pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:18px;">1.2 发送TASK的创建及摧毁函数</span></strong></p>

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

<p>&nbsp;</p>

<p><strong><span style="font-size:16px;">1.2.1创建发送task函数</span></strong></p>

<pre>
<code class="language-cpp">#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);
    }
}</code></pre>

<p>这里会创建一个TASK,名字叫&ldquo;sendTask&rdquo;</p>

<p>配置其stack的大小:SLE_SEND_TASK_STACK_SIZE</p>

<p>TASK实际干活的函数:send_task</p>

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

<p>&nbsp;</p>

<p><span style="font-size:16px;"><strong>1.2.2摧毁发送task函数</strong></span></p>

<pre>
<code class="language-cpp">static void destroy_send_task(void)
{
    osal_kthread_destroy(send_task_handle, 0);
}</code></pre>

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

<pre>
<code> * @param stop_flag 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.
</code></pre>

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

<p>&nbsp;</p>

<p><strong><span style="font-size:18px;">1.3 实际干活的发送函数</span></strong></p>

<pre>
<code class="language-cpp">#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 = {"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 &gt; SLE_SEND_CNT_MAX)
      {
            osal_printk("******send test data over******\r\n");
            destroy_send_task();
      }
    }

    return NULL;
}
</code></pre>

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

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

<p>如果发送到max次数,我就会摧毁task</p>

<p>&nbsp;</p>

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

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

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

<pre>
<code class="language-cpp">/**
* @brief                SLE client pair完成回调
* @param   conn_id 连接 ID。
* @param   addr    地址。
* @param   status执行结果错误码。
* @return      none
*/
voidsle_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-&gt;addr, addr-&gt;addr, addr-&gt;addr);
    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, &amp;info);

      create_send_task();
    }
}
</code></pre>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">/**
* @brief                SLE client 连接状态改变
* @param   conn_id    连接 ID。
* @param   addr       地址。
* @param   conn_state 连接状态 { @ref sle_acb_state_t }。
* @param   pair_state 配对状态 { @ref sle_pair_state_t }。
* @param   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(&amp;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(&amp;g_sle_uart_remote_addr);
      /* 再次开启SCAN */
      sle_uart_start_scan();
    }
    /* 其他未知情况 */
    else
    {
      osal_printk("%s status error\r\n", SLE_UART_CLIENT_LOG);
    }
}
</code></pre>

<p>&nbsp;</p>

<p>好了,代码的修改到此就完成了。我把整个代码仓放到github上了,<a href="https://github.com/BUYITAO/StarLink_BearPi-Pico-H2821" target="_blank">https://github.com/BUYITAO/StarLink_BearPi-Pico-H2821</a></p>

<p>&nbsp;</p>

<p><strong><span style="font-size:24px;">2.测试及结果</span></strong></p>

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

<p>&nbsp;</p>

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

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

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

<p>&nbsp;</p>

<div></div>

<div></div>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

walker2048 发表于 2024-8-27 13:57

<p>短距离不丢包很正常</p>

晚风吹散 发表于 2024-10-22 14:00

<p>仓鼠老师,我下载您文中github链接的代码仓,搜索不到my_sle_send_data、create_send_task&hellip;&hellip;等等这些函数和相关的变量、定义啊,请问是后来修改了吗<img height="53" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/sad.gif" width="54" /></p>

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

不爱胡萝卜的仓鼠 发表于 2024-10-22 14:19

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

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

晚风吹散 发表于 2024-10-23 09:31

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

<p>好的,非常感谢!</p>

晚风吹散 发表于 2024-10-23 17:09

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

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

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>2. 您有遇到过,sle_uart.c里,&ldquo;#if defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_<strong>SERVER</strong>)&rdquo;下的内容,和 &ldquo;#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_<strong>CLIENT</strong>)&rdquo;下的内容,全部都是暗色的情况吗?</p>

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

<p> &nbsp;</p>

<p> &nbsp;</p>

不爱胡萝卜的仓鼠 发表于 2024-10-25 10:03

晚风吹散 发表于 2024-10-23 17:09
另外想咨询您几个问题,不胜感激:

1. 海思Hispark IDE中,当我在系统配置 - application 中,切换了Ser ...

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

<p>&nbsp;</p>

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

晚风吹散 发表于 2024-10-25 11:16

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

<p>好的,再次感谢您<img height="59" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/wanwan061.gif" width="67" /></p>
页: [1]
查看完整版本: [BearPi-Pico H2821]测评 ⑥丢包及连接稳定性测试