manhuami2007 发表于 2022-3-16 15:35

【沁恒RISC-V内核 CH582】 7- 使用CH582蓝牙的notify主动上传数据

<div class="parsedown-markdown">
<blockquote>
<p>前面使用CH582作为GATT服务器,实现了read和write的操作,这两个操作都是客户端主动发起的。而服务器使用notify的方式则能主动的上传数据。本文介绍如何通过CH582作为服务器,如何通过notify上传数据。</p>
</blockquote>

<p>具有notify权限的特征需要多一个属性:<strong>客户特征配置</strong> 。这个属性需要具有读写权限,其作用是:用于客户端配置服务器的这个特征是否notify的。因此具有notify权限的特征需要包含以下属性:</p>

<ol>
        <li>特征声明</li>
        <li>特征值</li>
        <li>客户特征配置</li>
        <li>特征用户描述(可选)</li>
</ol>

<p>本实例仍然是在&quot;BLE-Peripheral&quot;工程中修改代码。实现notify功能主要包括以下步骤:</p>

<ol>
        <li>在属性表中增加相关的特征</li>
        <li>实现特征的客户配置文件初始化</li>
        <li>实现notify发送函数,并加入到定时发送的函数中</li>
</ol>

<h5>1.在属性表中增加相关的特征</h5>

<pre>
<code class="language-cpp">static uint8 simpleProfileChar8Props = GATT_PROP_NOTIFY;
static uint8 simpleProfileChar8 = { 0 }; /*存放特征值的缓存区*/
static gattCharCfg_t simpleProfileChar8Config;/*保存客户配置信息,用于客户特征配置属性*/
static uint8 simpleProfileChar8UserDesp[] = "Characteristic 8\0";
/*在属性表中添加*/
// Characteristic 8 Declaration
{
    { ATT_BT_UUID_SIZE, characterUUID },
    GATT_PERMIT_READ,
    0,
    &amp;simpleProfileChar8Props
},
// Characteristic Value 8
{
    { ATT_BT_UUID_SIZE, simpleProfilechar8UUID },
    0,
    0,
    simpleProfileChar8
},
// Characteristic 8 configuration
{
    { ATT_BT_UUID_SIZE, clientCharCfgUUID },
    GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    0,
    (uint8 *)simpleProfileChar8Config
},
// Characteristic 8 User Description
{
    { ATT_BT_UUID_SIZE, charUserDescUUID },
    GATT_PERMIT_READ,
    0,
    simpleProfileChar8UserDesp
},</code></pre>

<h5>2.实现特征的客户配置文件初始化</h5>

<p>在<code>bStatus_t SimpleProfile_AddService( uint32 services )</code> 函数中增加对&ldquo;客户特征配置&rdquo;属性中的值的初始化,<code>GATTServApp_InitCharCfg(INVALID_CONNHANDLE,simpleProfileChar8Config);</code> 。</p>

<p>同时,还要在连接断开的回调函数中增加上面的初始化函数。</p>

<p>完整的 <code>bStatus_t SimpleProfile_AddService( uint32 services )</code> 如下:</p>

<pre>
<code class="language-cpp">bStatus_t SimpleProfile_AddService( uint32 services )
{
uint8 status = SUCCESS;

// Initialize Client Characteristic Configuration attributes
GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar4Config );
GATTServApp_InitCharCfg(INVALID_CONNHANDLE,simpleProfileChar8Config);/*新增加的用于初始化“客户特征配置”属性中的值*/
// Register with Link DB to receive link status change callback
linkDB_Register( simpleProfile_HandleConnStatusCB );

if ( services &amp; SIMPLEPROFILE_SERVICE )
{
    // Register GATT attribute list and CBs with GATT Server App
    status = GATTServApp_RegisterService( simpleProfileAttrTbl,
                                          GATT_NUM_ATTRS( simpleProfileAttrTbl ),
                                          GATT_MAX_ENCRYPT_KEY_SIZE,
                                          &amp;simpleProfileCBs );
}

return ( status );
}</code></pre>

<p>而连接断开的回调函数就是上面代码中的 <code>simpleProfile_HandleConnStatusCB</code> 。其完整代码如下:</p>

<pre>
<code>static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType )
{
// Make sure this is not loopback connection
if ( connHandle != LOOPBACK_CONNHANDLE )
{
    // Reset Client Char Config if connection has dropped
    if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
         ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &amp;&amp;
         ( !linkDB_Up( connHandle ) ) ) )
    {
      GATTServApp_InitCharCfg( connHandle, simpleProfileChar4Config );
      GATTServApp_InitCharCfg( connHandle, simpleProfileChar8Config );
    }
}
}</code></pre>

<h5>3. 实现notify发送函数,并加入到定时发送的函数中</h5>

<pre>
<code class="language-c">//function at peripheral.c
static void periphercalChar8Notify(uint8_t *pValue,uint16_t len)
{
attHandleValueNoti_t noti;
noti.len = len;
noti.pValue = GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );
if( noti.pValue )
{
    tmos_memcpy( noti.pValue, pValue, noti.len );
    if(get_simple_profile_notify_8(peripheralConnList.connHandle, &amp;noti)!= SUCCESS){
      GATT_bm_free( (gattMsg_t *)&amp;noti, ATT_HANDLE_VALUE_NOTI );
    }
}
}
//function at gattprofile.c
bStatus_t get_simple_profile_notify_8(uint16 connHandle,attHandleValueNoti_t *pNoti)
{
uint16 value = GATTServApp_ReadCharCfg( connHandle, simpleProfileChar8Config );
bStatus_t status=0;
if ( value &amp; GATT_CLIENT_CFG_NOTIFY )
{
    pNoti-&gt;handle = simpleProfileAttrTbl.handle;

    status = GATT_Notification( connHandle, pNoti, FALSE );
    PRINT("NOTIFY_8_1 0x%02Xn",status);
    return status;
}
return bleIncorrectMode;
}</code></pre>

<p>注意上面的两个函数没有在一个文件中。函数 <code>bStatus_t get_simple_profile_notify_8(uint16 connHandle,attHandleValueNoti_t *pNoti)</code> 和属性表在同一个文件中,这个函数的主要作用是得到特征值的handle,然后调用 <code>GATT_Notification( connHandle, pNoti, FALSE );</code> 将数据发送出去。</p>

<p>这里还要注意一下 <code>GATT_Notification( connHandle, pNoti, FALSE );</code>的第2个参数必须是通过函数 <code>GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );</code> 动态申请的内存才能正常工作,否则的话会导致连接一直断开的情况。</p>

<p>下一步就是将发送函数加入到定时发送的函数中,定时发送是用的TMOS。</p>

<pre>
<code class="language-c">static void performPeriodicTask( void )
{
uint8 notiData = { 0x88 };
uint8_t n8_data = {0x12,0x34};
n8_data = my_count;
peripheralChar4Notify( notiData, SIMPLEPROFILE_CHAR4_LEN );
periphercalChar8Notify(n8_data,SIMPLEPROFILE_CHAR8_LEN);
}</code></pre>

<h5>4. 效果</h5>

<p>从下图中可以看出,当打卡notify后,开始主动上传数据。</p>

<p></p>
</div>

lugl4313820 发表于 2022-3-16 17:38

<p>感谢分享,我仔细拜读了你的经验,这里有两个疑问&nbsp;这个-i是不是&amp;noti,然后我定义了</p>

<p>&nbsp;烧写程序后,没能接收到CHAR8的数据。真心希望你能帮忙解答一下,char4的88我这里是可以接收到的。谢谢了。</p>

manhuami2007 发表于 2022-3-16 20:18

lugl4313820 发表于 2022-3-16 17:38
感谢分享,我仔细拜读了你的经验,这里有两个疑问&nbsp;这个-i是不是&amp;noti,然后我定义了

&nbsp;烧写 ...

<p>第一个红框是&amp;noti,不知道你那里为什么显示的是i。</p>

<p>你在TMOS里增加上传的函数了吗?就是这个函数: static void performPeriodicTask( void )</p>

lugl4313820 发表于 2022-3-16 20:29

manhuami2007 发表于 2022-3-16 20:18
第一个红框是&amp;noti,不知道你那里为什么显示的是i。

你在TMOS里增加上传的函数了吗?就是这个函数: ...

<p>善意的提醒一下,相信我,你有没有回头看下自己的帖子。</p>

lugl4313820 发表于 2022-3-16 20:32

<p>其实我更建议你提把工程上传,这样大家收获更深。谢谢</p>

manhuami2007 发表于 2022-3-16 20:54

lugl4313820 发表于 2022-3-16 20:32
其实我更建议你提把工程上传,这样大家收获更深。谢谢

<p></p>

<p>我在手机上看是没有问题的,不知道为什么网页上有问题了。<img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/face-with-cold-sweat_1f613.png" width="28" /></p>

manhuami2007 发表于 2022-3-16 20:57

<p></p>

<p>&nbsp;</p>

<p>这个是工程文件,我又做了一些更改,增加了OLED和I2C的功能,所以可能跟我帖子里的代码有点区别,但是不影响NOTIFY的使用。</p>

manhuami2007 发表于 2022-3-16 20:59

lugl4313820 发表于 2022-3-16 20:32
其实我更建议你提把工程上传,这样大家收获更深。谢谢

<p>我把工程文件上传了,你可能需要在你那里的例程文件夹里打开,要不可能会找不到库文件。</p>

lugl4313820 发表于 2022-3-16 20:59

manhuami2007 发表于 2022-3-16 20:57
&nbsp;

这个是工程文件,我又做了一些更改,增加了OLED和I2C的功能,所以可能跟我帖子里的代码有点 ...

<p>非常感谢您的支持,希望EEWORLD越来越来越好,有你这样的支持,中国定能走向世界,引领未来!</p>

manhuami2007 发表于 2022-3-16 21:01

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3128261&amp;ptid=1196861" target="_blank"><font color="#999999">lugl4313820 发表于 2022-3-16 20:59</font></a></font> 非常感谢您的支持,希望EEWORLD越来越来越好,有你这样的支持,中国定能走向世界,引领未来!</blockquote>
</div>

<p><img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/face-with-tears-of-joy_1f602.png" width="28" /> 谢谢夸奖,惭愧惭愧。咱们一起学习,一起进步。</p>

freebsder 发表于 2022-3-17 23:10

<p>现在当个嵌入式工程师简直又要会点硬件又会点底层又要协议又要网页还要app。。。</p>

manhuami2007 发表于 2022-3-18 10:15

freebsder 发表于 2022-3-17 23:10
现在当个嵌入式工程师简直又要会点硬件又会点底层又要协议又要网页还要app。。。

<p>是的,FPGA,linux,安卓,网页,python感觉都要学,硬件也要做的可靠稳定<img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/face-with-tears-of-joy_1f602.png" width="28" />。需要学的太多了</p>

manhuami2007 发表于 2022-3-18 10:16

fly007008009 发表于 2022-3-17 22:26
&nbsp;已经自己搞定;
此人不可信,言而无信;不想发就直接说&nbsp; 【不想发送】
我都没有QQ邮箱,哪 ...

<p>不知道你为啥这么说,咱们没有联系过啊</p>

lugl4313820 发表于 2022-3-19 07:49

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3128250&amp;ptid=1196861" target="_blank"><font color="#999999">manhuami2007 发表于 2022-3-16 20:18</font></a></font> 第一个红框是&amp;noti,不知道你那里为什么显示的是i。 你在TMOS里增加上传的函数了吗?就是这个函数: ...</blockquote>
</div>

<p>static void performPeriodicTask(void)<br />
{<br />
&nbsp; &nbsp; uint8_t notiData = {0x88};<br />
&nbsp; &nbsp; uint8_t n8_data = {0x12,0x34};<br />
&nbsp; &nbsp; n8_data = 0x01;<br />
&nbsp; &nbsp; peripheralChar4Notify(notiData, SIMPLEPROFILE_CHAR4_LEN);</p>

<p>&nbsp; &nbsp; periphercalChar8Notify(n8_data,SIMPLEPROFILE_CHAR8_LEN);<br />
}</p>

<p>我是添加了这个任务函数的</p>

lugl4313820 发表于 2022-3-19 07:59

可把工程发给你,帮我看看是什么回事吗?

manhuami2007 发表于 2022-3-19 17:57

lugl4313820 发表于 2022-3-19 07:59
可把工程发给你,帮我看看是什么回事吗?

<p>好的,我私信给你我的邮箱地址</p>

yaoquan5201314 发表于 2022-4-10 22:31

<p>mark一下,抽空学习经验。</p>
页: [1]
查看完整版本: 【沁恒RISC-V内核 CH582】 7- 使用CH582蓝牙的notify主动上传数据