当前位置: 首页 > news >正文

DA14585墨水屏学习(2)

一、user_svc2_wr_ind_handler函数

void user_svc2_wr_ind_handler(ke_msg_id_t const msgid,struct custs1_val_write_ind const *param,ke_task_id_t const dest_id,ke_task_id_t const src_id)
{// sprintf(buf2,"HEX %d :",param->length);arch_printf("cmd HEX %d:", param->length);for (int i = 0; i < param->length; i++){arch_printf("%02X", param->value[i]);}arch_printf("\r\n");if ((param->value[0] == 0xDD) && (param->length >= 5)){current_unix_time = (param->value[1] << 24) + (param->value[2] << 16) + (param->value[3] << 8) + (param->value[4] & 0xff);tm_t tm = {0};transformTime(current_unix_time, &tm);app_easy_timer_cancel(timer_used_min);time_offset = 60 - tm.tm_sec;timer_used_min = app_easy_timer(time_offset * 100, do_min_work);arch_printf("%d-%02d-%02d %02d:%02d:%02d %d\n", tm.tm_year + YEAR0,tm.tm_mon + 1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec,tm.tm_wday);}else if (param->value[0] == 0xAA){platform_reset(RESET_NO_ERROR);}else if (param->value[0] == 0x101){do_rili_show();is_part = 0;step = 1;display();}else if (param->value[0] == 0xE2){do_time_show();is_part = 0;step = 1;display();}
}

这段代码实现了一个蓝牙服务写入指示处理函数 user_svc2_wr_ind_handler,用于解析来自客户端的命令并执行相应操作。以下是对代码的详细解释:

函数概述

该函数是一个事件处理回调,当接收到自定义蓝牙服务(custs1)的写请求时被触发。

它会解析命令数据并执行以下操作:

1. 打印接收到的原始数据(HEX 格式)

2. 根据命令类型(首字节)执行不同逻辑

◦ 0xDD:设置系统时间

◦ 0xAA:重启设备

◦ 0x101:显示日历

◦ 0xE2:显示时间    

核心逻辑解析

1. 数据接收与打印

 arch_printf("cmd HEX %d:", param->length);
for (int i = 0; i < param->length; i++)
{
    arch_printf("%02X", param->value[i]);
}
arch_printf("\r\n");
     • 功能:将接收到的字节流以 HEX 格式打印输出

• 参数:

◦ param->length:数据长度

◦ param->value[]:数据内容    

2. 时间设置命令(0xDD)

 if ((param->value[0] == 0xDD) && (param->length >= 5))
{
    // 从字节流中解析Unix时间戳(大端格式)
    current_unix_time = (param->value[1] << 24) + (param->value[2] << 16) + 
                        (param->value[3] << 8) + (param->value[4] & 0xff);
    
    // 转换为本地时间结构
    tm_t tm = {0};
    transformTime(current_unix_time, &tm);
    
    // 重新同步定时器,确保整分钟触发
    app_easy_timer_cancel(timer_used_min);
    time_offset = 60 - tm.tm_sec;
    timer_used_min = app_easy_timer(time_offset * 100, do_min_work);
    
    // 打印格式化时间
    arch_printf("%d-%02d-%02d %02d:%02d:%02d %d\n", 
                tm.tm_year + YEAR0, tm.tm_mon + 1, tm.tm_mday,
                tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday);
}
     • 功能:通过蓝牙设置系统时间

• 数据格式:

◦ value[0]:命令头(0xDD)

◦ value[1-4]:Unix 时间戳(4 字节大端整数)  

• 时间同步机制:

◦ 取消当前分钟定时器

◦ 计算距离下一个整分钟的剩余秒数(time_offset)

◦ 重新设置定时器,确保 do_min_work 在整分钟触发    

3. 系统重启命令(0xAA)

else if (param->value[0] == 0xAA)
{
    platform_reset(RESET_NO_ERROR);
}
     • 功能:触发系统软复位

• 参数:RESET_NO_ERROR 表示正常重启(无错误)  

4. 日历显示命令(0x101)

else if (param->value[0] == 0x101)
{
    do_rili_show();  // 显示日历内容
    is_part = 0;
    step = 1;
    display();       // 更新屏幕显示
}
     • 功能:切换到日历显示模式

• 状态变量:

◦ is_part:可能表示部分更新标志

◦ step:状态机控制变量    

5. 时间显示命令(0xE2)

else if (param->value[0] == 0xE2)
{
    do_time_show();  // 显示时间内容
    is_part = 0;
    step = 1;
    display();       // 更新屏幕显示
}
     • 功能:切换到时间显示模式

• 与日历命令类似,但调用 do_time_show() 而非 do_rili_show()  

潜在问题与优化建议

1.  命令格式检查:

◦ 对于 0x101 和 0xE2 命令,未检查 param->length 是否足够,可能导致越界访问。  

2.  定时器精度: ◦ time_offset * 100 可能是笔误,应为 time_offset * 1000(毫秒转换)。  

3.  状态管理: ◦ is_part 和 step 作为全局变量,多命令并发时可能引发状态混乱。  

4.  错误处理:

◦ 未处理未知命令(首字节非 0xDD/0xAA/0x101/0xE2)的情况。    

应用场景 该处理函数常见于蓝牙低功耗(BLE)设备中,用于接收手机 APP 发送的控制命令,实现:

• 时间同步(通过 NTP 或手机时间)

• 远程重启设备 • 界面显示切换(时钟 / 日历)  通过蓝牙协议栈的 GATT 服务,客户端可以向设备写入特定命令,触发相应功能。

二、app_easy_timer_cancel函数

void app_easy_timer_cancel(const timer_hnd timer_id)
{if APP_EASY_TIMER_HND_IS_VALID(timer_id){if ((timer_callbacks[APP_EASY_TIMER_HND_TO_IDX(timer_id)] != NULL) &&(timer_callbacks[APP_EASY_TIMER_HND_TO_IDX(timer_id)] != timer_canceled_handler)){// Remove the timer from the timer queueke_timer_clear(APP_EASY_TIMER_HND_TO_MSG_ID(timer_id), TASK_APP);timer_callbacks[APP_EASY_TIMER_HND_TO_IDX(timer_id)] = timer_canceled_handler;/*Send a message to the kernel in order to clear the timer callback function andfree the respective position in the timers callback array.The app_easy_timer_cancel() function cannot guarantee if a timer has enteredthe message queue or not. Therefore a message must be sent to the kernel andinform it about the requested cancel operation.*/struct cancel_timer_struct *req = KE_MSG_ALLOC(APP_CANCEL_TIMER, TASK_APP, TASK_APP,cancel_timer_struct);req->timer_id = timer_id;ke_msg_send(req);}else{ASSERT_WARNING(0);}}else{ASSERT_WARNING(0);}
}

相关文章:

  • 器件(八)—芯片封装中的开尔文源极
  • Java从入门到精通 - 数组
  • RabbitMQ学习(第三天)
  • redis数据结构-08(SINTER、SUNION、SDIFF、SISMEMBER)
  • Python-UV多环境管理
  • 作业...
  • CentOS7离线安装Mysql8
  • 菜鸟之路day31一一MySQL之多表设计
  • idea中的vcs不见了,如何解决
  • 部署Superset BI(五)连接oracle数据库失败
  • LlamaIndex 第七篇 结构化数据提取
  • 进程(沉淀中)
  • ElasticSearch进阶
  • 大数据模型的构建与优化
  • 找银子 题解(c++)
  • C++ 核心基础:数字、数组、字符串、指针与引用详解
  • springboot3+vue3融合项目实战-大事件文章管理系统-更新用户密码
  • TypeScript 装饰器详解
  • Kotlin Multiplatform--03:项目实战
  • 六大设计原则
  • 加拿大新政府宣誓就职
  • “75万买299元路由器”事件进展:重庆市纪委等三部门联合介入调查
  • 科创板年内第3家!健信超导IPO获受理,拟募资8.65亿
  • 黄土是他们的气质:打破宁夏当代油画创作的沉寂
  • 综艺还有怎样的新可能?挖掘小众文化领域
  • 经济日报刊文:品牌经营不能让情怀唱“独角戏”