上周帶孩子上課時(shí),有個(gè)網(wǎng)友求助我一個(gè)藍(lán)牙的問題,正巧孩子上課我有大把時(shí)間,于是便聊了起來,他使用的是nordic的平臺(tái),想要鏈接頑鹿和zwift這類的應(yīng)用app來實(shí)現(xiàn)室內(nèi)自行車等運(yùn)動(dòng)設(shè)備。
我曾經(jīng)也想過這個(gè)應(yīng)用,家里有一臺(tái)閑置著,滿是灰塵的橢圓機(jī),只有一個(gè)簡(jiǎn)單的斷碼屏幕可以顯示寫數(shù)字,比較枯燥,一直想改裝一下,無奈不得閑。
今天正巧,遇上了就嘗試著了解一下,順便幫網(wǎng)友也一起調(diào)試一下,不過他用的nordic平臺(tái)我已經(jīng)七八年不使用了,幾乎回憶不起來了,因?yàn)樗{(lán)牙這個(gè)東西,每家的軟件都不甚相同,跨行業(yè)的電控工程師上手還是很難的。為了方面,我先用最近玩的國產(chǎn)芯片,磐啟微的PAN1070來實(shí)現(xiàn)。
之前自己做過模組,還做了一個(gè)底板,專門用來實(shí)現(xiàn)各種小應(yīng)用。
頑鹿和zwift一樣,是一個(gè)健身類的APP,模擬了實(shí)際場(chǎng)景,可以鏈接上我們室內(nèi)的自行車等運(yùn)動(dòng)設(shè)備,通過藍(lán)牙接受到踏頻,功率和速度信息,然后就生成動(dòng)畫來模擬我們戶外騎行。
同時(shí),如果像上圖這樣,我們的室內(nèi)自行車具備阻力調(diào)劑能力,軟件還可以下發(fā)阻力信息,這樣就能夠把真實(shí)的路況信息模擬出來。對(duì)于自行車愛好者來說非常的有價(jià)值,霧霾天呀,大冬天呀都可以在家騎車了。
我不是自行車愛好者,我曾經(jīng)騎摩拜單車十公里,蛋蛋都麻木的沒有知覺了,所以還是把橢圓機(jī)模擬成自行車吧。
首先,藍(lán)牙有個(gè)標(biāo)準(zhǔn)協(xié)議族FTMS,他規(guī)定了絕大部分的健康運(yùn)動(dòng)方面的硬件設(shè)備協(xié)議,這也讓我們的硬件和手機(jī)等上位機(jī)軟件具備了標(biāo)準(zhǔn)的通信能力。至于ANT+,我特別不喜歡,原因在于它不夠開放,也玩不起。
我們先說廣播,我們的藍(lán)牙模塊首先要廣播一些必要信息,讓APP能夠發(fā)現(xiàn)我們的設(shè)備,進(jìn)一步鏈接我們的設(shè)備。
上圖是使用nrf connect掃描出來的一個(gè)廣播包信息,近些年來我一直在幫一些公司招聘技術(shù)人員,面試藍(lán)牙相關(guān)的候選人非常之多,不過,我發(fā)現(xiàn)他們絕大部分弄不懂藍(lán)牙廣播包的數(shù)據(jù)形式,我之前的藍(lán)牙基礎(chǔ)教程中也介紹過,這里不多言,放個(gè)鏈接:
第三篇 藍(lán)牙的廣播是如何做到多樣化的?
這里解釋下,藍(lán)牙的廣播包中,每一個(gè)段數(shù)據(jù)都是從LEN長(zhǎng)度開始,后面跟著LEN個(gè)數(shù)據(jù)。其中緊跟LEN的就是廣播類型,最后面的一坨是數(shù)據(jù)。
比如第二行,他就是說,后面12個(gè)數(shù)是我的,0x09就是說,我是名稱,在后面的一串就是名稱字符串了。
那么對(duì)于FTMS協(xié)議,我們需要再廣播中展示出來,讓頑鹿和zwift來識(shí)別。對(duì)應(yīng)的也就是我上圖中的最后一行,6個(gè)字節(jié),TYPE類型為0x16。它的數(shù)據(jù)部分是FTMS的UUID(0x1826),再后面的指示運(yùn)動(dòng)設(shè)備支持的類型。具體要看藍(lán)牙官方的文檔
FTMS_v1.0.pdf
簡(jiǎn)單說,UUID后面的一個(gè)字節(jié)表示健身設(shè)備是否有效。
最后的16bit表示不同的健身設(shè)備
我上面的廣播包開始弄錯(cuò)了,想要嘗試的朋友可以按照上面的表格啟用第4和5bit即可以模擬出劃船機(jī)和室內(nèi)自行車。
有了廣播數(shù)據(jù)包,啟動(dòng)頑鹿APP就可以在設(shè)備列表中看到我們的設(shè)備了。
當(dāng)APP這邊鏈接好了以后,我們就可以按照APP的操作邏輯來進(jìn)行數(shù)據(jù)上報(bào)了。
數(shù)據(jù)上報(bào)的指令都是Notify的,具體的可以參考官方文檔,這里有個(gè)華為開發(fā)的網(wǎng)戰(zhàn),上面是中文的,看起來會(huì)省很多力氣。
文檔中心
這里面規(guī)定了我們藍(lán)牙設(shè)備需要實(shí)現(xiàn)的服務(wù),基本上包含兩個(gè)服務(wù):
DIS標(biāo)準(zhǔn)特征值支持范圍
FTMS標(biāo)準(zhǔn)特征值支持范圍
他們?cè)敿?xì)的列表可以打開我上面放的鏈接查看,這里不粘貼過來了。我們以Indoor bike為例來說明一下這服務(wù)的協(xié)議內(nèi)容。
這里的UUID就是我們需要在0x1826服務(wù)下面生命的特征值。頑鹿APP在讀取到0x1826下面的0x2AD2特征值時(shí),就會(huì)訂閱我們的Notify特征,此時(shí)我們就可以發(fā)送對(duì)應(yīng)的Notify數(shù)據(jù)了。順著這個(gè)鏈接點(diǎn)進(jìn)去就能夠看到具體協(xié)議內(nèi)容。
藍(lán)牙的很多協(xié)議,為了保證數(shù)據(jù)內(nèi)容的靈活性,都采用了類似的方式,就是先放一個(gè)長(zhǎng)度或者標(biāo)志,來決定后面跟的數(shù)據(jù)是什么,這種架構(gòu)極大的擴(kuò)展了藍(lán)牙協(xié)議的擴(kuò)展性。
你看,indoor bike data中的前兩個(gè)字節(jié)是flags,這里有16個(gè)bit,每一個(gè)bit代表著某一個(gè)數(shù)據(jù)是否上傳。簡(jiǎn)單來說,加入Flags中有兩個(gè)bit被置位了,那么后面我們應(yīng)該跟上兩個(gè)參數(shù),參數(shù)的長(zhǎng)度類型在標(biāo)準(zhǔn)文檔里有定義。
表格中的每一個(gè)bit都做了介紹,尤其要注意第一個(gè),它與眾不同,置0時(shí)表示有對(duì)應(yīng)的數(shù)據(jù)。不知到為了啥,我想肯定是為了提高什么效率之類的。
接下來看具體數(shù)據(jù)的類型。
這里面列出來每種數(shù)據(jù)類型格式和單位,后面的必選和可選忽略它,這只是華為這邊自己要求的,實(shí)際藍(lán)牙協(xié)議里面都是可選的。
讓人不舒服的一點(diǎn)就是第一項(xiàng),不用instantaneous speed,非得用more data,不知到為什么,可能是因?yàn)槠渌慕】翟O(shè)備協(xié)議中,第一個(gè)bit有可能代表多個(gè)數(shù)據(jù),劃船機(jī)就是這樣。
如果你的自行車不支持阻力調(diào)節(jié),其實(shí)到這里,我們就可以在軟件中吃撐天涯了,但是如果想實(shí)現(xiàn)阻力控制,我們還需要實(shí)現(xiàn)一個(gè)特征值Fitness Machine Control Point。這里以后再說。
先來看效果。