最近在使用芯海的蓝牙芯片开发一个小项目,功能其实很简单,类似于防丢器,只不过这个项目中的主机也是蓝牙芯片,而不是手机。这就不得不去学习更多的协议栈相关的东西。然而,最让人头疼的并不是蓝牙协议本身的学习,毕竟这是SIG发布的通行的一套协议栈,无论谁家的蓝牙都应遵守。最让人头疼的是,每一家做蓝牙芯片的厂家,都有一套自己实现SIG BLE协议栈的源代码,这时候可是真的看出条条大路通罗马了。
用硬件来比喻的话,就相当于SIG 出了一个原理图,各家厂家按照原理图画了各自的线路板,学蓝牙开发就像是看那个乱七八糟PCB gerber图纸,各家都不一样。
我最早接触蓝牙用的是nordic,天天缠着FAE折腾了一个月才熟悉了它的那套代码,后来还直接把它的DFU重构了一下,适应了自己公司的OTA协议。后来开发泰凌微,又是一套新东西,不但整套源代码框架不同,就连IDE也是换了,用起来就像从现代文明一下进入刀耕火种一样。以至于从那以后,但凡有人给我推荐蓝牙,我都先问问能不能在MDK上开发,工具还是用顺手的好,已经不是调戏各种工具的年纪了。
还有一个点,就是这些蓝牙的协议栈都需要跑在一个小型的操作系统上,严格意义上来说,这只是一个稍微复杂的调度系统,这又是一个非标的东西,所以各家系统层的接口又不一样,比如磐启微的蓝牙是基于一个开源的Zephyr系统,我刚一拿到厂家的SDK都不知道从哪入手,第一个函数去哪里找都费劲,所以说为啥MDK用的人多,即便是企业用盗版的都不愿用那些开源的五花八门的东西,简单意味着综合成本低。
昂瑞微的蓝牙和nordic有点类似,杰里的开发起来工具就又得费点劲儿了,现在我弄得这个芯海的蓝牙,不确定是借鉴的哪一家的协议栈,log信息虽然很多,也是绕了一个星期才将将绕明白从开机启动到广播,再从发起Connect到向从机发数据,真的是绕来绕去,一会处理osal的message,一会有处理某一个应用的message,都是从底层一个消息队里取出来的,不同的地方都有相同的事件,再在回调函数里面处理一遍,真的晕。所以,蓝牙这东西,选择两三个平台就足够折腾了。去年我在推广方案的时候,销售的同事三天能给整俩蓝牙进来,根本学不过来,关键在于学习这些不重样的个性协议栈没啥意义,我本身更想关注的是应用怎么写。
这么看来,当年GD把寄存器地址设计成和ST一模一样真的是有远见,从推广上来说,这起到了决定性作用。但是蓝牙没办法,这个行业没有一家独大的的情况,即便是Nordic,TI,赛普拉斯,NXP等在市场上也只能算是平分秋色吧。回到应用开发上,协议栈真的是折腾的我眼花缭乱,整得我整个人都不好了,基本没心情好好写应用。这不,RSSI数据又出问题了,本来都在-30dbm左右,中间总是突然窜出一个-90来,这必须得加一个滤波才行。思来想去选择了滑动窗口滤波器,在窗口内把最大最小值去掉。原来写过,根本不想去翻了(我必须自己写一个算法库,可以随手拖到工程就能用的那种),正着急的时候,想起来GPT,现在还是不太习惯身边有这么个大神啊。我便向他请教:
#include <stdio.h> #include <limits.h> #define WINDOW_SIZE 10 int window[WINDOW_SIZE]; int num_elements = 0; void update_window(int new_value) { if (num_elements < WINDOW_SIZE) { window[num_elements++] = new_value; } else { // 窗口已满,滑动窗口,丢弃最旧的值 for (int i = 1; i < WINDOW_SIZE; i++) { window[i-1] = window[i]; } window[WINDOW_SIZE-1] = new_value; } } double compute_filtered_output() { if (num_elements == 0) return 0.0; // 没有数据 int max = INT_MIN; int min = INT_MAX; int sum = 0; for (int i = 0; i < num_elements; i++) { if (window[i] > max) max = window[i]; if (window[i] < min) min = window[i]; sum += window[i]; } // 减去最大值和最小值,再计算平均 sum -= (max + min); return (double)sum / (num_elements - 2); } int main() { // 模拟输入数据 int data[] = {5, 10, 8, 12, 20, 1, 30, 25, 15, 50, 45, 20, 25, 10, 5}; int n = sizeof(data) / sizeof(data[0]); for (int i = 0; i < n; i++) { update_window(data[i]); if (num_elements > 2) { printf("Filtered output: %.2fn", compute_filtered_output()); } } return 0; }
它还贴心的给了个说明:
真是暖心极了!