w494143467 发表于 2021-6-26 12:41

【环境专家之智能手表】Part11:手表绑定与解绑

<p><span style="font-size:20px;"><strong>1.介绍</strong></span></p>

<p>首先第一步需要做手机与APP的绑定,其实主要是绑定手表,不让手表与其他用户进行连接,如果任何一个用户都可以连接手表的话,那肯定是不行的,所以需要有一个绑定与解绑的功能作为软连接的第一道门槛,只有绑定或校验成功之后,才能进行数据交互,否则不能进行数据交互,所以我就先实现该功能。</p>

<p><span style="font-size:20px;"><strong>2.下位机设计</strong></span></p>

<p>首先定义协议,目前只定义绑定和解绑的协议,后续设置名字,获取历史数据等协议等到后面开发的时候再进行设计,绑定和解绑协议如下图所示:</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p style="text-align: center;">图1</p>

<p>ID需要掉电存储的,所以上电的时候需要读取EEPROM中的数据,那么初始化的代码如下:</p>

<pre>
<code class="language-cpp">void phone_communication_init(void)
{
        int32_t retval = 0;
        //读取Flash中的ID
        retval = I2CEeprom_Initialize(EEPROM_I2C_ADDR, EEPROM_PAGE_SIZE, &amp;eeprom);
        retval = I2CEeprom_Read(0, (uint8_t*)bind_id, sizeof(bind_id), &amp;eeprom);
        if (retval == I2C_EEPROM_OK)
        {
                eeprom_status = 0;
        }
}</code></pre>

<p>其中【eeprom_status】表示eeprom的状态,可能会因为长期使用,导致EEPROM损坏,所以当读取失败时,需要设置为下一块存储区域。</p>

<p>然后就是蓝牙的接收和发送了,蓝牙的接收在如下的代码中:</p>

<pre>
<code class="language-cpp">static int BLE_ICS_GATTC_WriteReqInd(ke_msg_id_t const msg_id,
      struct gattc_write_req_ind const *param, ke_task_id_t const dest_id,
      ke_task_id_t const src_id)
{
    //....

    if (status == GAP_ERR_NO_ERROR)
    {
      switch (att_num)
      {
      //....
      case ICS_IDX_RX_VALUE_VAL:
            if (param-&gt;length &lt;= ICS_CHARACTERISTIC_VALUE_LENGTH)
            {
                memcpy(&amp;cs_res.rx_value, param-&gt;value, param-&gt;length);
                cs_res.rx_value_length = param-&gt;length;
                phone_rec_data(param-&gt;value, param-&gt;length);
            }
            else
            {
                status = ATT_ERR_INVALID_ATTRIBUTE_VAL_LEN;
            }
            break;

      //....
      }
    }

    //....
}</code></pre>

<p>其中【phone_rec_data】函数为我接收数据的函数,对于绑定和解绑的实现内容如下:</p>

<pre>
<code class="language-cpp">void phone_rec_data(uint8_t *data, uint8_t length)
{
        if(data == NULL || length == 0)
                return;

        switch(data)
        {
        case PHONE_BAND:
        {
                uint8_t send_buff = {PHONE_BAND_ACK, 0};
                if(bind_id == 0)
                {
                        memcpy(bind_id, &amp;data, sizeof(bind_id));
                        I2CEeprom_Write(0, (uint8_t*)bind_id, sizeof(bind_id), &amp;eeprom);        //写入Flash
                        connect_state = 1;
                }
                else
                {
                        if(memcmp(bind_id, &amp;data, sizeof(bind_id)) == 0)        //和绑定中的ID一致
                        {
                                send_buff = 1;        //连接成功
                                connect_state = 1;
                        }
                        else
                        {
                                send_buff = 2;        //ID与绑定ID对不上
                        }
                }
                phone_send_data(send_buff, sizeof(send_buff));        //回复绑定状态
                break;
        }
        case PHONE_UNTIE:
        {
                uint8_t send_buff = {PHONE_UNTIE_ACK, 0};
                if(bind_id == 0)
                        send_buff = 1;        //已经没有绑定ID了
                else
                {
                        memset(bind_id, 0, sizeof(bind_id));
            I2CEeprom_Write(0, (uint8_t*)bind_id, sizeof(bind_id), &amp;eeprom);        //写入Flash
                        connect_state = 0;
                }
                phone_send_data(send_buff, sizeof(send_buff));        //回复解绑状态
                break;
        }
        }
}</code></pre>

<p>绑定的时候先判断是否已经有绑定ID,如果有则判断该手机绑定的ID与存储的ID是否相同,如果相同则绑定成功,如果不相同则绑定失败,只有连接成功之后才能进行解绑,解绑之后存储的ID会清除,其中【connect_state】变量为软连接成功标志位,只有当这个变量为1时才能进行设置与数据交互。</p>

<p>蓝牙发送采用的是Notify方式,直接调用【BLE_ICS_Notify】函数即可,这里我给它封装了一层,这样便于后期的修改与添加相关的功能。</p>

<pre>
<code class="language-cpp">void phone_send_data(uint8_t *data, uint8_t length)
{
        BLE_ICS_Notify(data, length);        //发送给手机
}
</code></pre>

<p>这样手机端的绑定与解绑功能就做完了。</p>

<p><span style="font-size:20px;"><strong>3.APP设计</strong></span></p>

<p>APP设计相对比较多,我就挑一些重点和大家说,首先是设备搜索界面(图2),这里会列出此次设计的所有手表蓝牙,最上方的输入框为过滤功能,主要是筛选出以【#R】为开头的蓝牙名称,因为所有手表都会以【#R】为开头,用户只能修改后面的内容。</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p style="text-align: center;">图2</p>

<p>找到自己的设备之后,进入二级界面,也就是绑定与解绑界面,这里后续还会添加设置界面以及数据获取界面,由于不是专业做Android的,所以界面都是最原始的控件样式,界面显示如图3所示,最下面的是调试数据功能,主要打印出蓝牙通信的内容,方便调试。</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p style="text-align: center;">图3</p>

<p>讲解完界面,就讲解一下代码部分,连接成功之后需要查找服务和特征值,通过其他调试软件查看到手表的服务和特征值如下图4所示:</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p style="text-align: center;">图4</p>

<p>则定义如下的服务和特征值:</p>

<pre>
<code class="language-java">    String remoteServiceUUID="e093f3b5-00a3-a9e5-9eca-40016e0edc24";
    String writeCharacteristic = "e093f3b7-00a3-a9e5-9eca-40036e0edc24";
    String notifyCharacteristic = "e093f3b6-00a3-a9e5-9eca-40026e0edc24";</code></pre>

<p>定义完成之后,开一个回调读取【notifyCharacteristic】特征值中的内容就可以接收蓝牙的数据,往【writeCharacteristic】特征值中写入数据,这样蓝牙就可以收到手机发送的数据了。然后编写绑定和解绑按钮的Ckick事件,发送绑定和解绑命令,代码如下:</p>

<pre>
<code class="language-java">      //发送手机绑定
      PhoneBindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                byte[] buff = new byte;
                String Bind_ID_String;
                int Bind_ID_Int;

                Bind_ID_String = PhoneBindIDEdit.getText().toString();
                Bind_ID_Int = Integer.parseInt(Bind_ID_String);

                buff = 0x01;
                buff = (byte)(Bind_ID_Int / 100000 % 10 + 0x30);
                buff = (byte)(Bind_ID_Int / 10000 % 10 + 0x30);
                buff = (byte)(Bind_ID_Int / 1000 % 10 + 0x30);
                buff = (byte)(Bind_ID_Int / 100 % 10 + 0x30);
                buff = (byte)(Bind_ID_Int / 10 % 10 + 0x30);
                buff = (byte)(Bind_ID_Int % 10 + 0x30);

                Send_Data_Ble(buff, buff.length);
                Toast.makeText(mContext, "手机绑定连接", Toast.LENGTH_SHORT).show();
            }
      });

      DisBindButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v){
                byte[] buff = new byte;

                buff = 0x03;

                Send_Data_Ble(buff, buff.length);
                Toast.makeText(mContext, "解除手机绑定", Toast.LENGTH_SHORT).show();
            }
      });</code></pre>

<p>最后就是接收数据,通过接收到的数据修改状态(文本)即可,具体代码如下:</p>

<pre>
<code class="language-java">                switch(ReceiveBuff)
                {
                  case 0x02:
                        if(ReceiveBuff == 0x00) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("绑定并连接成功");
                        }
                        else if(ReceiveBuff == 0x01) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("连接成功");
                        }
                        else {
                            ConfigurationStateTextView.setTextColor(0xffff0000);
                            ConfigurationStateTextView.setText("绑定失败");
                        }
                        break;
                  case 0x04:
                        if(ReceiveBuff == 0x00) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("解绑成功");
                        }
                        else {
                            ConfigurationStateTextView.setTextColor(0xffff0000);
                            ConfigurationStateTextView.setText("解绑失败");
                        }
                        break;
                }</code></pre>

<p>这样APP的绑定和解绑功能就好了。</p>

<p>最终的效果如下图5所示:</p>

<p class="imagemiddle" style="text-align: center;"></p>

<p style="text-align: center;">图5</p>

<p><span style="font-size:20px;"><strong>4.总结</strong></span></p>

<p>手表的绑定和解绑其实属于数据通信部分,只要蓝牙能够进行数据通信,其实这一部分只是时间问题,没有什么困难,APP开发其实只要有模板,就不会有太大的问题,会修改就可以了,下一篇为设置蓝牙广播名称和手表时间。</p>

soso 发表于 2021-6-28 09:32

<p>谢谢分享 。</p>

物联创客 发表于 2021-6-28 10:01

<p>请问楼主采用什么软件和语言编写app的?</p>

w494143467 发表于 2021-6-28 12:57

请问楼主采用什么软件和语言编写app的?

使用JAVA需要,APP开发环境是Android Studio
页: [1]
查看完整版本: 【环境专家之智能手表】Part11:手表绑定与解绑