2237|3

1942

帖子

2

TA的资源

版主

楼主
 

【环境专家之智能手表】Part11:手表绑定与解绑 [复制链接]

 

1.介绍

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

2.下位机设计

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

图1

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

void phone_communication_init(void)
{
	int32_t retval = 0;
	//读取Flash中的ID
	retval = I2CEeprom_Initialize(EEPROM_I2C_ADDR, EEPROM_PAGE_SIZE, &eeprom);
	retval = I2CEeprom_Read(0, (uint8_t*)bind_id, sizeof(bind_id), &eeprom);
	if (retval == I2C_EEPROM_OK)
	{
		eeprom_status = 0;
	}
}

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

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

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->length <= ICS_CHARACTERISTIC_VALUE_LENGTH)
            {
                memcpy(&cs_res.rx_value, param->value, param->length);
                cs_res.rx_value_length = param->length;
                phone_rec_data(param->value, param->length);
            }
            else
            {
                status = ATT_ERR_INVALID_ATTRIBUTE_VAL_LEN;
            }
            break;

        //....
        }
    }

    //....
}

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

void phone_rec_data(uint8_t *data, uint8_t length)
{
	if(data == NULL || length == 0)
		return;

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

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

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

void phone_send_data(uint8_t *data, uint8_t length)
{
	BLE_ICS_Notify(data, length);	//发送给手机
}

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

3.APP设计

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

图2

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

图3

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

图4

则定义如下的服务和特征值:

    String remoteServiceUUID="e093f3b5-00a3-a9e5-9eca-40016e0edc24";
    String writeCharacteristic = "e093f3b7-00a3-a9e5-9eca-40036e0edc24";
    String notifyCharacteristic = "e093f3b6-00a3-a9e5-9eca-40026e0edc24";

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

        //发送手机绑定
        PhoneBindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                byte[] buff = new byte[7];
                String Bind_ID_String;
                int Bind_ID_Int;

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

                buff[0] = 0x01;
                buff[1] = (byte)(Bind_ID_Int / 100000 % 10 + 0x30);
                buff[2] = (byte)(Bind_ID_Int / 10000 % 10 + 0x30);
                buff[3] = (byte)(Bind_ID_Int / 1000 % 10 + 0x30);
                buff[4] = (byte)(Bind_ID_Int / 100 % 10 + 0x30);
                buff[5] = (byte)(Bind_ID_Int / 10 % 10 + 0x30);
                buff[6] = (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[1];

                buff[0] = 0x03;

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

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

                switch(ReceiveBuff[0])
                {
                    case 0x02:
                        if(ReceiveBuff[1] == 0x00) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("绑定并连接成功");
                        }
                        else if(ReceiveBuff[1] == 0x01) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("连接成功");
                        }
                        else {
                            ConfigurationStateTextView.setTextColor(0xffff0000);
                            ConfigurationStateTextView.setText("绑定失败");
                        }
                        break;
                    case 0x04:
                        if(ReceiveBuff[1] == 0x00) {
                            ConfigurationStateTextView.setTextColor(0xff0000ff);
                            ConfigurationStateTextView.setText("解绑成功");
                        }
                        else {
                            ConfigurationStateTextView.setTextColor(0xffff0000);
                            ConfigurationStateTextView.setText("解绑失败");
                        }
                        break;
                }

这样APP的绑定和解绑功能就好了。

最终的效果如下图5所示:

图5

4.总结

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

最新回复

请问楼主采用什么软件和语言编写app的?  详情 回复 发表于 2021-6-28 10:01
点赞 关注
 
 

回复
举报

2万

帖子

71

TA的资源

管理员

沙发
 

谢谢分享 。

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 
 

回复

28

帖子

10

TA的资源

一粒金砂(中级)

板凳
 

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

点评

使用JAVA需要,APP开发环境是Android Studio  详情 回复 发表于 2021-6-28 12:57
 
 
 

回复

1942

帖子

2

TA的资源

版主

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

使用JAVA需要,APP开发环境是Android Studio
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表