藍(lán)牙車載產(chǎn)品的兼容性設(shè)計(jì)
這是發(fā)表在電子產(chǎn)品世界2009精選實(shí)用電子設(shè)計(jì)100例上的文章,論述了藍(lán)牙技術(shù)的兼容性問(wèn)題出現(xiàn)的原因以及解決方法。
引言
藍(lán)牙技術(shù)問(wèn)世10余年,得到了廣泛應(yīng)用,其中部分原因在于藍(lán)牙SIG組織為各種應(yīng)用以profile的形式定義了應(yīng)用協(xié)議,這樣藍(lán)牙設(shè)備之間的互操作便有章可循,但即使如此,藍(lán)牙設(shè)備之間的互操作性又稱兼容性問(wèn)題仍存在于幾乎所有藍(lán)牙應(yīng)用中。筆者歷時(shí)兩年時(shí)間為某合資汽車廠商開(kāi)發(fā)了一款藍(lán)牙車載產(chǎn)品,實(shí)現(xiàn)了免提通話、雙重呼叫管理、電話本自動(dòng)下載與手動(dòng)下載、流媒體音樂(lè)播放及遠(yuǎn)程控制功能,期間測(cè)試了近100部手機(jī)和音樂(lè)播放器,遇到并解決了各種兼容性問(wèn)題。結(jié)合產(chǎn)品開(kāi)發(fā)過(guò)程中測(cè)試并解決兼容性問(wèn)題的經(jīng)驗(yàn),本文對(duì)兼容性問(wèn)題出現(xiàn)的原因進(jìn)行了分析,大致有以下三個(gè)方面的原因:具體應(yīng)用本身定義不嚴(yán)格、應(yīng)用上下文差異、引入?yún)f(xié)議帶來(lái)的兼容性。以下就這三個(gè)方面進(jìn)行詳細(xì)分析并結(jié)合具體實(shí)例,說(shuō)明其解決方法。
應(yīng)用定義不嚴(yán)格
藍(lán)牙SIG組織定義了Profile,對(duì)各種功能的實(shí)現(xiàn)方式做了規(guī)范,并且定義了必選功能和可選功能,設(shè)備廠商可以對(duì)可選項(xiàng)有選擇得實(shí)現(xiàn),這樣便會(huì)造成一定的差異。而且Profile并沒(méi)有對(duì)應(yīng)用本身做嚴(yán)格定義,只是定義了功能,而應(yīng)用是功能的集合體,Profile并沒(méi)有定義怎么由多個(gè)功能組合實(shí)現(xiàn)某個(gè)應(yīng)用,這樣藍(lán)牙設(shè)備廠商在實(shí)現(xiàn)某一應(yīng)用時(shí)便有了差異性。雙重呼叫是車載設(shè)備免提通話應(yīng)用中兼容性最多的一種應(yīng)用,下面分析下該應(yīng)用出現(xiàn)兼容性問(wèn)題的原因并舉例剖析其解決方法。
對(duì)于免提通話而言,比較重要的幾個(gè)功能是呼叫建立提示CALL_SETUP、呼叫保持CALL_HELD、呼叫結(jié)果CALL、呼叫信息CLCC,手機(jī)在呼叫狀態(tài)產(chǎn)生變化時(shí)實(shí)時(shí)向免提設(shè)備端傳送這些提示消息,免提設(shè)備端便可以與手機(jī)的呼叫狀態(tài)保持一致,在免提設(shè)備端控制呼叫才符合預(yù)期。其中CALL_SETUP和CALL是必選功能,但對(duì)于雙重呼叫而言非常重要的CALL_HELD和CLCC卻是可選功能,雙重呼叫在免提剖面HFP(Hands-Free Profile)中定義為Three way calling,這也是一個(gè)可選功能。這樣在支持雙重呼叫時(shí),各種手機(jī)便以自己的方式來(lái)支持或者部分支持,這樣便來(lái)了雙重呼叫的兼容性問(wèn)題。下面以第二個(gè)呼叫為呼出為例剖析下解決方法。
當(dāng)撥打第二個(gè)電話時(shí),手機(jī)會(huì)發(fā)送CALL_SETUP=2消息,表示正在呼出,結(jié)果有對(duì)方拒接、對(duì)方接聽(tīng)、未撥通這么幾種情況。顯然判斷出呼出結(jié)果是至關(guān)重要的,我們通過(guò)對(duì)手機(jī)進(jìn)行測(cè)試然后根據(jù)其表現(xiàn)特性進(jìn)行分類,將手機(jī)分為如下幾類:A-支持CALL_HELD不支持CLCC、B-支持CALL_HELD和CLCC、C-支持CLCC不支持CALL_HELD而且手機(jī)在Three way calling下不支持CALL、D-支持CLCC不支持CALL_HELD但手機(jī)在Three way calling下支持CALL、E-不支持CALL_HELD也不支持CLCC但手機(jī)在Three way calling下支持CALL、F-不支持CALL_HELD也不支持CLCC而且手機(jī)Three way calling下不支持CALL。
對(duì)于支持CALL_HELD消息的AB類手機(jī)而言,我們可以通過(guò)CALL_HELD來(lái)判斷呼出結(jié)果,CALL_HELD=1表示對(duì)方接聽(tīng),CALL_HELD=0則表示對(duì)方拒接或未撥通;對(duì)于支持CLCC的CD類手機(jī)而言,如果手機(jī)在Three way calling下支持CALL,CALL=1則表示對(duì)方接聽(tīng),如果沒(méi)有CALL消息說(shuō)明對(duì)方拒接或未撥通,這時(shí)需要在CALL_SETUP=0時(shí)讀取手機(jī)當(dāng)前的呼叫信息,然后根據(jù)該呼叫信息更新免提設(shè)備端的呼叫狀態(tài);對(duì)于不支持CLCC和CALL_HELD的EF類手機(jī)而言,如果手機(jī)在Three way calling下支持CALL,CALL=1則表示對(duì)方接聽(tīng),否則在CALL_SETUP=0時(shí)默認(rèn)將呼叫結(jié)果處理為對(duì)方拒接,即這個(gè)時(shí)候無(wú)法判斷呼出結(jié)果。
應(yīng)用上下文差異
藍(lán)牙是個(gè)對(duì)時(shí)間特性要求很嚴(yán)格的應(yīng)用,每種藍(lán)牙行為及其每個(gè)階段必須在相應(yīng)時(shí)間內(nèi)完成,否則可能造成失敗或者長(zhǎng)時(shí)間無(wú)法響應(yīng)。應(yīng)用的上下文是指在某個(gè)藍(lán)牙行為完成后,下面將要進(jìn)行什么樣的藍(lán)牙行為,它是由藍(lán)牙設(shè)備的應(yīng)用決定的,同類產(chǎn)品在應(yīng)用上的差異便會(huì)帶來(lái)應(yīng)用上下文上的差異,這樣便可能會(huì)帶來(lái)兼容性問(wèn)題。比如在藍(lán)牙車載設(shè)備與藍(lán)牙手機(jī)互操作完成配對(duì)后,當(dāng)車載設(shè)備實(shí)現(xiàn)配對(duì)后的自動(dòng)連接時(shí),便由于手機(jī)在配對(duì)完成后的處理有所不同而遇到了兼容性問(wèn)題。車載設(shè)備實(shí)現(xiàn)了配對(duì)后的自動(dòng)連接功能,在配對(duì)完成后車載設(shè)備讀取外部設(shè)備的SDP進(jìn)行服務(wù)查詢以判斷外部設(shè)備類型(包括免提、音頻流、免提+音頻流三種類型)然后自動(dòng)連接其免提或音頻流服務(wù),結(jié)果造成部分手機(jī)讀取SDP失敗、部分手機(jī)自動(dòng)連接失敗、部分手機(jī)處于長(zhǎng)時(shí)間無(wú)法響應(yīng)的狀態(tài)。
對(duì)于這種兼容性問(wèn)題,需要對(duì)手機(jī)在不同應(yīng)用上下文的表現(xiàn)特性進(jìn)行分析,并根據(jù)其差異進(jìn)行分類。通過(guò)對(duì)手機(jī)在配對(duì)完成后的處理進(jìn)行分析,有的手機(jī)配對(duì)完成后馬上自動(dòng)連接,有的需要用戶確認(rèn)再手動(dòng)連接,有的會(huì)通過(guò)SDP讀取車載設(shè)備的服務(wù)列表然后針對(duì)車載設(shè)備提供的服務(wù)自動(dòng)連接(車載設(shè)備提供免提服務(wù)、SPP服務(wù)、SyncML服務(wù)、流媒體音樂(lè)播放服務(wù)),而有的不會(huì)自動(dòng)連接,這樣分類后,根據(jù)手機(jī)特性的不同設(shè)計(jì)實(shí)現(xiàn)配對(duì)后的自動(dòng)連接如下:
藍(lán)牙車載設(shè)備在配對(duì)完成后的4秒內(nèi)無(wú)操作,配對(duì)后馬上自動(dòng)連接的手機(jī)(如nokia 6500c)和大部分讀取SDP后自動(dòng)連接的手機(jī)(如三星SGH-U608、SGH-E208),可以迅速連接上車載設(shè)備。配對(duì)完成四秒后藍(lán)牙車載設(shè)備通過(guò)SDP判斷配對(duì)設(shè)備的類型(包括免提、音頻流、免提+音頻流三種類型),如果類型為免提+音頻流,則在連接免提成功后等待10秒再去連接音頻流,之所以10秒后再去連接音頻流是因?yàn)槊馓徇B接成功后,需要連接PBAP或SyncML或SPP去下載電話本,如果同時(shí)進(jìn)行A2DP的連接去連接配對(duì)設(shè)備的流媒體服務(wù),會(huì)造成鏈路丟失,免提連接及音頻流連接斷開(kāi)。如果連接免提失敗,則不再連接其音頻流服務(wù),因?yàn)橛械氖謾C(jī)如多普達(dá)D600的PDA手機(jī),配對(duì)完成后讀取SDP然后自動(dòng)連接,有時(shí)會(huì)造成免提連接不成功,如果去連接其音頻流,連接成功,但之后從車載設(shè)備端連接手機(jī)無(wú)法連接成功。斷開(kāi)流媒體后,連接免提一直失敗,必須重新配對(duì)才行。
對(duì)于用戶確認(rèn)手動(dòng)連接的手機(jī)和部分讀取SDP然后自動(dòng)連接車載設(shè)備的手機(jī),在車載設(shè)備自動(dòng)連接手機(jī)期間,可能會(huì)收到手機(jī)的連接請(qǐng)求,如果連接請(qǐng)求的手機(jī)與自動(dòng)連接的手機(jī)為同一設(shè)備(藍(lán)牙地址相同),則接收該連接請(qǐng)求,否則會(huì)造成自動(dòng)連接失敗。同時(shí)由于車載設(shè)備支持SPP的dev A,PDA手機(jī)的dev A可能會(huì)在配對(duì)后自動(dòng)連接車載設(shè)備的SPP dev A,這時(shí)要拒絕該連接,如果不對(duì)該連接請(qǐng)求進(jìn)行處理,會(huì)造成PDA手機(jī)處于長(zhǎng)時(shí)間無(wú)法響應(yīng)的狀態(tài)。
引入?yún)f(xié)議帶來(lái)的兼容性
藍(lán)牙技術(shù)是個(gè)開(kāi)放性的協(xié)議,它借鑒了很多成熟的已經(jīng)得到廣泛應(yīng)用的協(xié)議,比如Syncml,封裝在藍(lán)牙OBEX協(xié)議上可以實(shí)現(xiàn)個(gè)人信息的同步更新,比如vCard,它和PBAP、OPP協(xié)議結(jié)合,用來(lái)進(jìn)行電話本條目和呼叫日志的封裝、下載和解析,這些協(xié)議本身便存在一定的兼容性問(wèn)題,需要深入研究引入的協(xié)議,并盡量多得測(cè)試更多手機(jī)以盡量完善應(yīng)用程序。下面以vCard的解析為例來(lái)說(shuō)明該兼容性問(wèn)題的解決方法。
vCard是電子名片規(guī)范,定義了個(gè)人信息數(shù)據(jù)的存儲(chǔ)格式及訪問(wèn)接口的規(guī)范,現(xiàn)在廣泛應(yīng)用的是v2.1版本和3.0版本,對(duì)于電話本條目和呼叫日志而言,關(guān)鍵信息為姓名、電話號(hào)碼及呼叫時(shí)間。含有多個(gè)電話號(hào)碼的電話本條目,我們將之定義為VCARD,其電話號(hào)碼包含家庭電話、工作電話、手機(jī)、車載電話四種屬性。
vCard樣例如下:
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE;:=9A=6C=5E=FA=8F=89
TEL;CELL:13475909642
TEL;WORK:053182605413
END:VCARD
以上的vCard樣例中,人名字段提取為“馬建輝”的UTF-8字符0x9A6C 0x5EFA 0x8F89,這部分的兼容性在于不同手機(jī)在封裝電話本條目的人名字段時(shí)所使用的字符集和編碼方式不一致,字符集有ASCII和UTF-8,編碼方式有8BIT、QUOTED-PRINTABLEPRINTABLE、BASE64這么幾種方式,需要對(duì)這幾種方式分別處理,比如以上vCard人名字段的處理需要把=9A=6C=5E=FA=8F=89轉(zhuǎn)換為0x9A6C 0x5EFA 0x8F89,處理代碼如下所示,temp_name數(shù)組為未處理的人名字符串,處理好的人名放在NAME數(shù)組中:
if(temp_name[i]=='=')
{
if((temp_name[i+1]>=0x41)&&(temp_name[i+1]<=0x46))
temp1=temp_name[i+1]-0x37;
else if((temp_name[i+1]>=0x30)&&(temp_name[i+1]<=0x39))
temp1=temp_name[i+1]-0x30;
if((temp_name[i+2]>=0x41)&&(temp_name[i+2]<=0x46))
temp2=temp_name[i+2]-0x37;
else if((temp_name[i+2]>=0x30)&&(temp_name[i+2]<=0x39))
temp2=temp_name[i+2]-0x30;
NAME[name_len]=(temp1<<4)+temp2;
name_len++;
i+=3;
}
另外還需要考慮一些特殊情況,如Sony Erricson 手機(jī)電話本條目的人名字段有時(shí)會(huì)把空格處理為0xE38080,所以如果提取出0xE38080,需要把該特殊字符以空格0x20代替,否則會(huì)處理為亂碼。
對(duì)于號(hào)碼字段的提取,關(guān)鍵字不僅是HOME、WORK、CELL、CAR,還要把PREF、VOICE作為可以被識(shí)別的關(guān)鍵字,而且有手機(jī)不帶關(guān)鍵字,把不帶關(guān)鍵字的處理為CELL即手機(jī)屬性即可。
呼叫時(shí)間,其字段以X-IRMC-CALL-DATETIME表示,其標(biāo)準(zhǔn)格式舉例如下:20080112T1212,年四個(gè)字節(jié),月和日分別兩個(gè)字節(jié),但對(duì)于部分手機(jī),其月和日沒(méi)有嚴(yán)格遵循該規(guī)范,月+日字段共兩個(gè)字節(jié)或共三個(gè)字節(jié),這就需要根據(jù)月和日的特性進(jìn)行特殊處理了。處理代碼如下,月日字節(jié)數(shù)為temp_month_date_length,存放在temp_month_date數(shù)組中,
if(temp_month_date_length==2)
{
temp_month=temp_month_date[0]-0x30;
temp_date=temp_month_date[1]-0x30;
}
else if(temp_month_date_length==3)
{
if(temp_month_date[0]>0x31)//then the character must be month
{
//214-2 14
temp_month=temp_month_date[0]-0x30;
temp_date=(unsigned char)((temp_month_date[1]-0x30)*10+(temp_month_date[2]-0x30));
}
else if(temp_month_date[1]>0x32)
{
//130-1 30
temp_month=temp_month_date[0]-0x30;
temp_date=(unsigned char)((temp_month_date[1]-0x30)*10+(temp_month_date[2]-0x30));
}
else
{
//114 to month=11 date=4
temp_month=(unsigned char)((temp_month_date[0]-0x30)*10+(temp_month_date[1]-0x30));
temp_date=temp_month_date[2]-0x30;
if(temp_month>=11)
{
temp_month=0;
temp_date=0;
}
}
}
結(jié)語(yǔ)
兼容性是藍(lán)牙產(chǎn)品開(kāi)發(fā)中的難點(diǎn)問(wèn)題,本文分析了兼容性問(wèn)題出現(xiàn)的原因,并結(jié)合具體實(shí)例分析其解決方法,有很好的借鑒意義。