【环境专家之智能手表】Part12:手表名称和时间的配置
[复制链接]
1.介绍
手表出厂肯定会用同一个固件,那么名字肯定都是一样的,所以每个用户拿到手里会去修改手表的名字,同时手表需要存储数据的话需要自己跑时间戳,这样才能知道自己这条数据时采集至何时,那么说了就开始动手干吧!
2.下位机设计
首先还是需要定义协议,在之前的基础之上添加相关的协议,协议内容如下图1:
图1
首先是修改名字,这里目前最多10字节,一个汉字占用两个字节,十个字节五个汉字基本够大家使用,如果是英文的话,十个字母也是完全足够的。
设置名字的话,需要先修改一下设置名字的API,在名字的开头添加上【#R】这两个字符,代表着该广播设备为【环境专家之智能手表】,具体修改为如下:
void BDK_BLE_SetLocalName(const char* name)
{
uint32_t name_len;
if (ble_env.state == BLE_STATE_OFF)
{
BDK_BLE_Initialize();
}
if (name != NULL)
{
uint8_t name_temp[12] = {'#', 'R'};
memcpy(&name_temp[2], name, 10);
name_len = 12;
if (name_len <= BDK_BLE_LOCAL_NAME_MAX_LENGTH)
{
memcpy(ble_env.local_name, name_temp, name_len);
ble_env.local_name_len = name_len;
}
}
}
当然这个广播名字需要存储在Flash中,这个还是比较简单的,如果Flash中没有名字,则使用默认名字【Downhole】,最终显示在广播中的就是【#RDownhole】,所以名字的初始化如下所示:
void phone_communication_init(void)
{
int32_t retval = 0;
//.....
retval = I2CEeprom_Read(BIND_NAME_ADDR, (uint8_t*)watch_name, sizeof(watch_name), &eeprom);
if(watch_name[0] == 0x00)
{
memcpy(watch_name, (uint8_t *)"Downhole ", 10); //默认名字
}
//.....
}
最后就是接收到设置名称的数据时的处理代码了,具体如下:
case PHONE_SET_NAME:
{
uint8_t send_buff[2] = {PHONE_SET_NAME_ACK, 0};
memcpy(watch_name, &data[1], 10); //设置广播名字
BDK_BLE_SetLocalName(watch_name);
I2CEeprom_Write(BIND_NAME_ADDR, (uint8_t*)watch_name, sizeof(watch_name), &eeprom);
phone_send_data(send_buff, sizeof(send_buff)); //回复名字设置
break;
}
为什么只判断第一位,因为只要设置名字,那么第一位数据肯定不是【0x00】,初始化完成之后,调用设置广播名字的函数即可【BDK_BLE_SetLocalName】。
接下来是设置时间,设置时间之前肯定需要有一个时间戳能够在手表上跑,所以先定义一个全局变量,存储时间戳,然后定义一个接口用于获取时间戳和让时间戳加一,【add_time_utc】该函数放在一个1S的定时中即可,代码如下:
my_time_t time_utc = 0;
uint32_t get_time_utc(void)
{
return time_utc;
}
void add_time_utc(void)
{
time_utc++;
}
时间戳不需要掉电存储,为什么呢,因为掉电之后,就算再快上电,时间戳的时间也会比现实时间滞后,而时间错了之后存储的数据是无效的,那么只需要设定开机未设置时间,则不对数据进行存储就可以了。
所以设置时间和查询时间的解析处理代码如下:
case PHONE_SET_TIME:
{
uint8_t send_buff[2] = {PHONE_SET_TIME_ACK, 0};
struct my_tm t;
t.tm_year = data[1] + 2000;
t.tm_mon = data[2];
t.tm_mday = data[3];
t.tm_hour = data[4];
t.tm_min = data[5];
t.tm_sec = data[6];
time_utc = mktime(t);
printf("time_utc:%d\r\n", time_utc);
phone_send_data(send_buff, sizeof(send_buff)); //回复设置状态
break;
}
case PHONE_INQ_TIME:
{
uint8_t send_buff[7] = {PHONE_INQ_TIME_ACK, 0};
struct my_tm t;
localtime(time_utc, &t);
send_buff[1] = t.tm_year - 2000;
send_buff[2] = t.tm_mon;
send_buff[3] = t.tm_mday;
send_buff[4] = t.tm_hour;
send_buff[5] = t.tm_min;
send_buff[6] = t.tm_sec;
phone_send_data(send_buff, sizeof(send_buff)); //发送手表当前时间
break;
}
为什么需要查询时间接口呢,主要其实是为了APP连接手表时,自动设置时间,当时间未初始化时,则对时间进行设置,以及手表时间出现误差时对时间的偏移进行校准,这时数据肯定也出现了偏差,知道偏差的时间也可以对数据存储的时间进行校准。
3.APP设计
APP主要是界面的设计,因为通信协议还是比较简单的,对于界面的设计流程我就不过多的说明了,直接来看一下设计的结果吧,如下图2所示:
图2
设置时间时使用了数字滑动控件【NumberPicker】,我个人觉得这样设置时间比较方便,按下【获取手表时间】按钮可以获取手表的当前时间,【设置手表未上方时间】按钮主要是为了调试使用,可以设置手表为任意时间,【设置为手机当前时间】主要是为了方便直接设置手表时间,设置手机当前时间的代码如下:
//设置当前时间
private void SetTime(){
int year1,year2,month,day,hour,minute,second;
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
Date curDate = new Date(System.currentTimeMillis());
String thistime = formatter.format(curDate);
//year1 = Integer.valueOf(thistime.substring(0,2)).intValue();
year2 = Integer.valueOf(thistime.substring(2,4)).intValue();
month = Integer.valueOf(thistime.substring(5,7)).intValue();
day = Integer.valueOf(thistime.substring(8,10)).intValue();
hour = Integer.valueOf(thistime.substring(11,13)).intValue();
minute = Integer.valueOf(thistime.substring(14,16)).intValue();
second = Integer.valueOf(thistime.substring(17)).intValue();
byte[] bbb = new byte[7];
bbb[0]=(byte) 0x05;
bbb[1]=(byte) year2;
bbb[2]=(byte) (month+1);
bbb[3]=(byte) day;
bbb[4]=(byte) hour;
bbb[5]=(byte) minute;
bbb[6]=(byte) second;
Send_Data_Ble(bbb, bbb.length);
//Toast.makeText(mContext, "设置当前时间", Toast.LENGTH_SHORT).show();
}
然后就是协议发送和接收部分,这里没有太难的,我就贴出一部分代码:
case 0x06:
if(ReceiveBuff[1] == 0x00) {
ConfigurationStateTextView.setTextColor(0xff0000ff);
ConfigurationStateTextView.setText("设置时间成功!");
}
else {
ConfigurationStateTextView.setTextColor(0xffff0000);
ConfigurationStateTextView.setText("设置时间失败!");
}
break;
case 0x08:
String TimeString = "20" + ReceiveBuff[1] + "-" + ReceiveBuff[2] + "-" + ReceiveBuff[3] + " " + ReceiveBuff[4] + ":" + ReceiveBuff[5] + ":" + ReceiveBuff[6];
WatchPowerPercentEditText.setText(TimeString);
break;
case 0x0A:
if(ReceiveBuff[1] == 0x00) {
Toast.makeText(mContext, "设置名字成功!", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(mContext, "设置名字失败!", Toast.LENGTH_SHORT).show();
}
break;
设置名字的效果如下GIF所示:
图3
关于时间的操作图下GIF所示:
图4
4.总结
时间其实是手表比较重要的一部分,但是难度不大,只要维护好时间戳就可以了,对于设置名字,其实只要熟悉广播包的数据协议其实也没有什么难度,下一篇就是数据采集和存储同时APP获取并显示。
|