【环境专家之智能手表】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开发其实只要有模板,就不会有太大的问题,会修改就可以了,下一篇为设置蓝牙广播名称和手表时间。
|