第一篇:藍(lán)牙知識(shí)小結(jié)
藍(lán)牙協(xié)議知識(shí)總結(jié)
藍(lán)牙設(shè)備 和 主機(jī)進(jìn)行連接和數(shù)據(jù)通信的 流程如下:外部設(shè)備發(fā)出廣告(帶有UUID信息等其他信息); 主機(jī)(集中器設(shè)備)收到廣告信息,進(jìn)而發(fā)送掃描請(qǐng)求;表示我掃描到你的信息; 3 外部設(shè)備收到掃描請(qǐng)求后,返回掃描回應(yīng),表示我知道你掃描到我的信息; 4 主機(jī)進(jìn)而發(fā)送連接請(qǐng)求信息,表示主機(jī)要跟設(shè)備建立無(wú)線(xiàn)連接; 5 設(shè)備收到連接請(qǐng)求后,發(fā)送相應(yīng)請(qǐng)求回應(yīng);表示已經(jīng)建立連接;
數(shù)據(jù)讀寫(xiě)流程如下進(jìn)一步(在建立連接的基礎(chǔ)上): 主機(jī)發(fā)送主服務(wù)UUID(設(shè)備的廣告UUID)給設(shè)備;
服務(wù)發(fā)現(xiàn) 7 設(shè)備收到后回應(yīng)服務(wù)信息; 主機(jī)發(fā)送特性UUID;
特性發(fā)現(xiàn) 9 設(shè)備收到后回應(yīng)特性值句柄;(類(lèi)似于存儲(chǔ)設(shè)備的地址)主機(jī)發(fā)送特性值句柄;
讀信息 11 設(shè)備收到后回應(yīng)特性值; 主機(jī)發(fā)送特性值句柄和要寫(xiě)入值;
寫(xiě)信息 13 設(shè)備回應(yīng)寫(xiě)入成功響應(yīng);
在睡眠狀態(tài),耗電只有1微安(uA),而在連接事件中最高的是10幾個(gè)毫安
連接建立之后,再進(jìn)行安全密鑰的交換配對(duì),進(jìn)而進(jìn)行數(shù)據(jù)的讀寫(xiě);
主機(jī)和從機(jī)綁定之后,斷開(kāi)連接后,可以快速的建立連接并進(jìn)行加密讀寫(xiě),而不需要再次配對(duì); 特點(diǎn) 低功耗藍(lán)牙速度只有100bps,傳統(tǒng)藍(lán)牙有3Mbps 2 低功耗藍(lán)牙不需要IOS 的MFI 認(rèn)證,傳統(tǒng)藍(lán)牙必須; 3 低功耗藍(lán)牙能紐扣電池能用1年多,傳統(tǒng)藍(lán)牙不行;
頻道:
2.4G – 2.48G 總共40個(gè)頻段,每2M 一個(gè)頻段;
其中 37(2.40G),38(2.426G),39(2.48G)為 3個(gè)廣播頻道;這3個(gè)頻道避開(kāi)了wifi 常用的頻道,與wifi可以共存; 其他37個(gè)為連接頻道;
1、BLE中主從機(jī)建立連接,到配對(duì)和綁定的過(guò)程如下圖。
正如上圖所示,最簡(jiǎn)單一次藍(lán)牙通信需要以上相關(guān)步驟,包括discovery device,connect,pairing,bond等4個(gè)主要部分。
1)廣播:廣播包可以包含廣播數(shù)據(jù),廣播包可以無(wú)指定或者對(duì)指定的設(shè)備發(fā)送??梢月暶髟撈骷强蛇B接的還是不可連接的。在一次廣播中,廣播包可以在三個(gè)廣播通道中同時(shí)發(fā)送。
廣播類(lèi)型 :1 未指定可連接 2 指定可連接 3 未指定 不可見(jiàn) 4 未指定不可連接 #define GAP_ADTYPE_ADV_IND
0x00 //!< Connectable undirected advertisement #define GAP_ADTYPE_ADV_DIRECT_IND 0x01 //!< Connectable directed advertisement #define GAP_ADTYPE_ADV_DISCOVER_IND
0x02 //!< Discoverable undirected advertisement #define GAP_ADTYPE_ADV_NONCONN_IND
0x03 //!< Non-Connectable undirected advertisement #define GAP_ADTYPE_SCAN_RSP_IND
0x04 //!< Only used in gapDeviceInfoEvent_t 在peripheral.c中
GAPRole_Init(taskID++);進(jìn)行了初始化設(shè)置
還有有以下函數(shù)bStatus_t GAPRole_SetParameter(uint16 param, uint8 len, void *pValue)GAPRole_GetParameter(…..)可以調(diào)用進(jìn)行設(shè)置。2)scanning 1)被動(dòng)掃描: 掃描者監(jiān)聽(tīng)廣播頻道的廣播包,收到后將其上傳到host層
2)主動(dòng)掃描:掃描者監(jiān)聽(tīng)廣播頻道的廣播包,當(dāng)收到廣播包后掃描者發(fā)送一個(gè)scan Request包,廣播設(shè)備回應(yīng)一個(gè)scan reponse包
3)Connection 在掃描設(shè)備掃描到一個(gè)可連接的廣播消息后,掃描設(shè)備可以通過(guò)發(fā)送 connection reequst 包給廣播設(shè)備從而成為連接的發(fā)起者
Connection resqust 包含從機(jī)鏈路層一系列的參數(shù),這些參數(shù)聲明連接時(shí)的通道及時(shí)序要求。建立連接
GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,DEFAULT_LINK_WHITE_LIST,addrType, peerAddr);廣播設(shè)備接收了連接請(qǐng)求,就進(jìn)入了連接狀態(tài),發(fā)起者成了主機(jī),廣播設(shè)備成了從機(jī)。兩個(gè)已連接的設(shè)備的所有通信發(fā)生在連接事件中,連接事件周期性的發(fā)生,周期由連接間隔參數(shù)決定。
連接間隔:使用調(diào)頻的間隔;兩個(gè)連接事件之間的時(shí)間間隔,藍(lán)牙傳數(shù)據(jù)是在一個(gè)頻段發(fā)送數(shù)據(jù)后,然后跳到另一個(gè)頻段再傳數(shù)據(jù),從一個(gè)頻道另一個(gè)頻段的時(shí)間間隔就是連接間隔;即使沒(méi)有數(shù)據(jù)發(fā)送,也要調(diào)頻切換測(cè)試包是否連接斷開(kāi);所以,連接間隔是定時(shí)的存在;可以認(rèn)為是一個(gè)固定的時(shí)序;每隔一段時(shí)間就自動(dòng)調(diào)到另一個(gè)頻道的去建立連接;這個(gè)時(shí)間中,是很少功耗的,基本沒(méi)有;
單位是1.25毫秒;范圍是 6----3200個(gè)單位;也就是1.25ms到4s的范圍 不同的應(yīng)用 時(shí)間間隔不一樣,時(shí)間間隔長(zhǎng),功耗就低,傳輸數(shù)據(jù)慢; 時(shí)間間隔短,功耗就高,傳輸數(shù)據(jù)就快。
從機(jī)延時(shí): 從機(jī)如果沒(méi)有數(shù)據(jù)發(fā)送,可以跳過(guò)連接間隔,不用頻繁的定時(shí)去建立連接,從而過(guò)一段較長(zhǎng)時(shí)間再去建立連接;這個(gè)時(shí)間就是從機(jī)延時(shí)時(shí)間;從而功耗降低很多;單位是和連接間隔一樣;范圍是 0---499
管理超時(shí)
超過(guò)這個(gè)時(shí)間,還沒(méi)有建立連接,則認(rèn)為是連接丟失,斷開(kāi)?;氐轿催B接狀態(tài);
單位是10ms,范圍是 10(100ms)-----3200(32s)。超時(shí)值必須比有效連接間隔大;有效連接間隔= 連接間隔×(1+從機(jī)延時(shí))
如果從機(jī)不想使用當(dāng)前的連接參數(shù),可以向主機(jī)發(fā)送連接更新請(qǐng)求,從機(jī)設(shè)備可以在任何時(shí)候發(fā)送連接更新請(qǐng)求,使得從機(jī)可以動(dòng)態(tài)的調(diào)整連接參數(shù)。
GAPCentralRole_UpdateLink(simpleBLEConnHandle,DEFAULT_UPDATE_MIN_CONN_INTERVAL,DEFAULT_UPDATE_MAX_CONN_INTERVAL,DEFAULT_UPDATE_SLAVE_LATENCY,DEFAULT_UPDATE_CONN_TIMEOUT);無(wú)論主機(jī)還是從機(jī),都可以無(wú)條件的終止當(dāng)前連接,一方請(qǐng)求終止,另一方必須在斷開(kāi)連接狀態(tài)之前響應(yīng)。
連接還可以由超時(shí)而終止。超時(shí)時(shí)間小于32s,大于有效連接間隔(連接間隔×(1+從機(jī)延時(shí)))
終止連接函數(shù):
GAPCentralRole_TerminateLink(simpleBLEConnHandle);主機(jī)和從機(jī)保存各自的超時(shí)計(jì)時(shí)器,每次收到數(shù)據(jù)包就清零,一旦達(dá)到超時(shí)數(shù)值,就認(rèn)為連接已經(jīng)丟失就會(huì)斷開(kāi)連接。
連接超時(shí)判斷,終止連接在程序中還沒(méi)找到。
2.BLE中的GAP和GATT GAP個(gè)人認(rèn)為就是監(jiān)控上圖中的交互狀態(tài),比如從廣播變成連接,到配對(duì)等。
GATT通俗理解為用于主從機(jī)之間的客戶(hù)端和服務(wù)器端的數(shù)據(jù)交互,以Attribute Table來(lái)體現(xiàn)。
GAP Role Profile:在GAP所處的4個(gè)角色:廣播Advertise,主機(jī)central,從機(jī)Peripheral,觀察者Observer。GATT Attribute:通用屬性配置文件。
GAP作為Peripheral Role需要設(shè)置的核心參數(shù)如下 GAPROLE_ADVERT_ENABLED:廣播使能。GAPROLE_ADVERT_DATA:廣播時(shí)的參數(shù),GAPROLE_SCAN_RSP_DATA:從機(jī)掃描響應(yīng),返回的數(shù)據(jù)包
GAPROLE_MIN_CONN_INTERVAL:處于連接狀態(tài)后的設(shè)備,都會(huì)有個(gè)hop,一段時(shí)間內(nèi)進(jìn)行數(shù)據(jù)交互,以保證兩者是連接的。當(dāng)前后兩次交互時(shí),需要等待的最小間隔時(shí)間 GAPROLE_MAX_CONN_INTERVAL:...需要等待的最大間隔時(shí)間
GAPROLE_SLAVE_LATENCY:處于連接后,從機(jī)可以做出不響應(yīng)連接請(qǐng)求的間隔數(shù)目,即跳過(guò)n個(gè)交互的連接。
GAPROLE_TIMEOUT_MULTIPLIER:從上次成功連接到這次連接成功的最大允許延時(shí)。如果規(guī)定時(shí)間內(nèi)未成功則認(rèn)為本次連接失敗,丟棄。該值必須比有效連接的間隔大。GAPROLE_PARAM_UPDATE_ENABLE:請(qǐng)求主機(jī)更新參數(shù),主機(jī)可以接受也可以拒絕。.GATT Server的相關(guān)設(shè)置函數(shù)。
// Initialize GATT attributes GGS_AddService(GATT_ALL_SERVICES);// GAP Service GATTServApp_AddService(GATT_ALL_SERVICES);// GATT attributes DevInfo_AddService();// Device Information Service SimpleProfile_AddService(GATT_ALL_SERVICES);// Simple GATT Profile 通常一個(gè)GATT中GAP server和GATT server是必須強(qiáng)制存在的,還有設(shè)備信息服務(wù)以及自己設(shè)計(jì)的profile server.SimpleProfile_AddService就是添加自己設(shè)計(jì)的profile server 在SimpleProfile_AddService函數(shù)中調(diào)用了如下函數(shù)
GATTServApp_RegisterService(simpleProfileAttrTbl, GATT_NUM_ATTRS(simpleProfileAttrTbl),&simpleProfileCBs);
} simpleProfileCBs 的函數(shù)定義如下:
CONST gattServiceCBs_t simpleProfileCBs = { simpleProfile_ReadAttrCB,// Read callback function pointer
simpleProfile_WriteAttrCB, // Write callback function pointer
NULL
// Authorization callback function pointer };實(shí)際上就是底層讀寫(xiě)數(shù)據(jù)的函數(shù),主機(jī)讀數(shù)據(jù)時(shí)從機(jī)會(huì)調(diào)用simpleProfile_ReadAttrCB函數(shù),寫(xiě)數(shù)據(jù)時(shí)從機(jī)會(huì)調(diào)用simpleProfile_WriteAttrCB函數(shù)。這兩個(gè)函數(shù)在simpleGaatprofile.c 中實(shí)現(xiàn)。
注意在simpleProfile_WriteAttrCB,函數(shù)中有如下語(yǔ)句 if((notifyApp!= 0xFF)&& simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange)
{
simpleProfile_AppCBs->pfnSimpleProfileChange(notifyApp);
} 注意函數(shù)指針的用法,實(shí)際是在接收到主機(jī)數(shù)據(jù)發(fā)過(guò)來(lái)的數(shù)據(jù)后調(diào)用simpleProfileChangeCB函數(shù)來(lái)處理接收到的數(shù)據(jù)。這個(gè)函數(shù)在初始化時(shí)注冊(cè),下面會(huì)講到。作為GATT的server和client,主要通過(guò)Attribute來(lái)進(jìn)行交互,當(dāng)client請(qǐng)求server讀取數(shù)據(jù)時(shí),通過(guò)如下注冊(cè)的回調(diào)函數(shù)來(lái)進(jìn)行訪(fǎng)問(wèn)。
// Register callback with SimpleGATTprofile
VOID SimpleProfile_RegisterAppCBs(&simpleBLEPeripheral_SimpleProfileCBs);//給應(yīng)用注冊(cè)回調(diào)函數(shù),這個(gè)函數(shù)非常重要 在回調(diào)函數(shù)中對(duì)數(shù)據(jù)做出處理。
static simpleProfileCBs_t simpleBLEPeripheral_SimpleProfileCBs = {
simpleProfileChangeCB
// Charactersitic value change callback };
在SimpleProfile_RegisterAppCBs 函數(shù)中賦值。simpleProfile_AppCBs = simpleProfileChangeCB
在simpleProfileChangeCB函數(shù)中可以啟動(dòng)定時(shí)器來(lái)給主機(jī)發(fā)送Notification數(shù)據(jù)
發(fā)送數(shù)據(jù)函數(shù)為GATT_Notification(noti_cHandle,&pReport,FALSE);
如下:
{ static attHandleValueNoti_t pReport;//聲明attHandleValueNoti_t這個(gè)結(jié)構(gòu)體
uint16 noti_cHandle;//存放handle
pReport.handle = simpleProfileAttrTbl[11].handle;//讀取notification對(duì)應(yīng)的handle
GAPRole_GetParameter(0x30E, ¬i_cHandle);//獲取Connection Handle
pReport.len = 1;//數(shù)據(jù)長(zhǎng)度
pReport.value[0] = 0x03;//賦值
GATT_Notification(noti_cHandle,&pReport,FALSE);}
主機(jī)使能Notification:
這個(gè)handle應(yīng)該是相應(yīng)的characteristic value的handle的后面一個(gè), 就是characteristic value的handle加 1.例子: { attWriteReq_t writeReq;writeReq.handle =;writeReq.len = 2;writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
這里是 0x01 writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
這里是 0x00 writeReq.sig = 0;writeReq.cmd = 0;GATT_WriteCharValue(simpleBLEConnHandle, &writeReq, simpleBLETaskId);}
這兩個(gè)值目的是打開(kāi)Notification功能.CCC的參數(shù)有兩個(gè), 一個(gè)Notification, 一個(gè)indication.value[0]就是打開(kāi)關(guān)閉notification, value[1]是打開(kāi)關(guān)閉indication.主機(jī)數(shù)據(jù)處理:
simpleBLECentral.c 這個(gè)文件, 里面有個(gè)函數(shù):simpleBLECentralProcessGATTMsg()這個(gè)函數(shù)就是處理各種從peripheral過(guò)來(lái)的數(shù)據(jù).但是在示例代碼中并沒(méi)有加入通知, 就是notification的接收, 所以你得自己添加代碼.很簡(jiǎn)單, 類(lèi)似 if((pMsg->method == ATT_READ_RSP)||........), 添加 else if((pMsg->method == ATT_HANDLE_VALUE_NOTI)||......)就可以處理從機(jī)Notification的數(shù)據(jù)。
value 被寫(xiě)的時(shí)候首先 simpleProfile_WriteAttrCB()會(huì)被調(diào)到.最后才會(huì)調(diào)用 simpleProfileChangeCB()
GAP通過(guò)在啟動(dòng)設(shè)備事件的任務(wù)處理中啟動(dòng)設(shè)備,其實(shí)主要是向GAP中注冊(cè)回調(diào)函數(shù),讓系統(tǒng)在發(fā)現(xiàn)自身運(yùn)行狀態(tài)變化時(shí),調(diào)用該函數(shù),方便應(yīng)用層進(jìn)行相關(guān)操作。if(events & SBP_START_DEVICE_EVT)
{
// Start the Device VOID GAPRole_StartDevice(&simpleBLEPeripheral_PeripheralCBs);//啟動(dòng)設(shè)備,注冊(cè)回調(diào)函數(shù),用于監(jiān)督設(shè)備的狀態(tài)變化:廣播、連接、配對(duì)、綁定等。
// Start Bond Manager VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);} simpleBLEPeripheral_PeripheralCBs函數(shù)定義如下
static gapRolesCBs_t simpleBLEPeripheral_PeripheralCBs = {
peripheralStateNotificationCB, // Profile State Change Callbacks
NULL
// When a valid RSSI is read from controller(not used by application)};static void peripheralStateNotificationCB(gaprole_States_t newState)//傳入?yún)?shù)由GPA自己輸入,內(nèi)部調(diào)用回調(diào)函數(shù)給用戶(hù),處理連接狀態(tài)的改變 simpleBLEPeripheral_BondMgrCBs函數(shù)定義如下: static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs = {
ProcessPasscodeCB,// 生成配對(duì)密碼,發(fā)送給主機(jī)
ProcessPairStateCB
//主機(jī)密碼的校驗(yàn)處理。配對(duì)狀態(tài)管理 };
一、修改廣播功率 { #define LL_EXT_TX_POWER_MINUS_23_DBM
0 //-23dbm 功率 最小 #define LL_EXT_TX_POWER_MINUS_6_DBM
//-6dbm
#define LL_EXT_TX_POWER_0_DBM
// 0dbm
#define LL_EXT_TX_POWER_4_DBM // +dbm 功率 最大
HCI_EXT_SetTxPowerCmd(gTxPower);
更新廣播內(nèi)容
GAP_UpdateAdvertisingData(simpleBLEPeripheral_TaskID, TRUE, sizeof(advertData_Ex), advertData_Ex);}
二、數(shù)據(jù)加密解密 { uint8 key[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
// 需要加密的數(shù)據(jù)
uint8 plaintextData[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
// 加密后數(shù)據(jù)存放區(qū)
uint8 encryptedData[16];
// 解密后數(shù)據(jù)存放區(qū)
uint8 deccryptedData[16];
// 開(kāi)始加密
LL_Encrypt(key, plaintextData, encryptedData);
// 開(kāi)始解密
LL_EXT_Decrypt(key, encryptedData, deccryptedData);}
三、設(shè)置從機(jī)廣播時(shí)間 1)、廣播模式必須是Limited Discoverable mode 在advertData 中加入此AD string: 0x02, GAP_ADTYPE_FLAGS, GAP_ADTYPE_FLAGS_LIMITED| GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED 2)、設(shè)置時(shí)間
//Maximum time to remain advertising, when in Limited Discoverable mode.unit is seconds #define USER_DEF_ADV_TIMEOUT
GAP_SetParamValue(TGAP_LIM_ADV_TIMEOUT, USER_DEF_ADV_TIMEOUT);
第二篇:Android藍(lán)牙開(kāi)發(fā)小結(jié)
學(xué)習(xí)之前先了解兩個(gè)基本概念:
一、RFCOMM協(xié)議:
一個(gè)基于歐洲電信標(biāo)準(zhǔn)協(xié)會(huì)ETSI07.10規(guī)程的串行線(xiàn)性仿真協(xié)議。此協(xié)議提供RS232控制和狀態(tài)信號(hào),如基帶上的損壞,CTS以及數(shù)據(jù)信號(hào)等,為上層業(yè)務(wù)(如傳統(tǒng)的串行線(xiàn)纜應(yīng)用)提供了傳送能力。
RFCOMM是一個(gè)簡(jiǎn)單傳輸協(xié)議,其目的是針對(duì)如何在兩個(gè)不同設(shè)備上的應(yīng)用之間保證一條完整的通信路徑,并在它們之間保持一通信段。
RFCOMM是為了兼容傳統(tǒng)的串口應(yīng)用,同時(shí)取代有線(xiàn)的通信方式,藍(lán)牙協(xié)議棧需要提供與有線(xiàn)串口一致的通信接口而開(kāi)發(fā)出的協(xié)議。RFCOMM協(xié)議提供對(duì)基于L2CAP協(xié)議的串口仿真,基于ETSI07.10??芍С衷趦蓚€(gè)BT設(shè)備之間同時(shí)保持高達(dá)60路的通信連接。
RFCOMM只針對(duì)直接互連設(shè)備之間的連接,或者是設(shè)備與網(wǎng)絡(luò)接入設(shè)備之間的互連。通信兩端設(shè)備必須兼容于RFCOMM協(xié)議,有兩類(lèi)設(shè)備:DTE(Data Terminal Endpoint,通信終端,如PC,PRINTER)和DCE(Data Circuit Endpoint,通信段的一部分,如Modem)。此兩類(lèi)設(shè)備不作區(qū)分。
二、MAC硬件地址
MAC(Medium/MediaAccess Control, 介質(zhì)訪(fǎng)問(wèn)控制)MAC地址是燒錄在NetworkInterfaceCard(網(wǎng)卡,NIC)里的.MAC地址,也叫硬件地址,是由48比特長(zhǎng)(6字節(jié)),16進(jìn)制的數(shù)字組成.0-23位叫做組織唯一標(biāo)志符(organizationally unique,是識(shí)別LAN(局域網(wǎng))節(jié)點(diǎn)的標(biāo)識(shí).24-47位是由廠家自己分配。其中第40位是組播地址標(biāo)志位。網(wǎng)卡的物理地址通常是由網(wǎng)卡生產(chǎn)廠家燒入網(wǎng)卡的EPROM(一種閃存芯片,通??梢酝ㄟ^(guò)程序擦寫(xiě)),它存儲(chǔ)的是傳輸數(shù)據(jù)時(shí)真正賴(lài)以標(biāo)識(shí)發(fā)出數(shù)據(jù)的電腦和接收數(shù)據(jù)的主機(jī)的地址。
Android平臺(tái)提供的藍(lán)牙API去實(shí)現(xiàn)藍(lán)牙設(shè)備之間的通信,藍(lán)牙設(shè)備之間的通信主要包括了四個(gè)步驟:設(shè)置藍(lán)牙設(shè)備、尋找局域網(wǎng)內(nèi)可能或者匹配的設(shè)備、連接設(shè)備和設(shè)備之間的數(shù)據(jù)傳輸。以下是建立藍(lán)牙連接的所需要的一些基本類(lèi):
BluetoothAdapter類(lèi):代表了一個(gè)本地的藍(lán)牙適配器。它是所有藍(lán)牙交互的的入口點(diǎn)。利用它你可以發(fā)現(xiàn)其他藍(lán)牙設(shè)備,查詢(xún)綁定了的設(shè)備,使用已知的MAC地址實(shí)例化一個(gè)藍(lán)牙設(shè)備和建立一個(gè)BluetoothServerSocket(作為服務(wù)器端)來(lái)監(jiān)聽(tīng)來(lái)自其他設(shè)備的連接。
BluetoothDevice類(lèi):代表了一個(gè)遠(yuǎn)端的藍(lán)牙設(shè)備,使用它請(qǐng)求遠(yuǎn)端藍(lán)牙設(shè)備連接或者獲取遠(yuǎn)端藍(lán)牙設(shè)備的名稱(chēng)、地址、種類(lèi)和綁定狀態(tài)。(其信息是封裝在bluetoothsocket中)。
Bluetoothsocket類(lèi):代表了一個(gè)藍(lán)牙套接字的接口(類(lèi)似于tcp中的套接字),它是應(yīng)用程序通過(guò)輸入、輸出流與其他藍(lán)牙設(shè)備通信的連接點(diǎn)。
Blueboothserversocket類(lèi):代表打開(kāi)服務(wù)連接來(lái)監(jiān)聽(tīng)可能到來(lái)的連接請(qǐng)求(屬于server端),為了連接兩個(gè)藍(lán)牙設(shè)備必須有一個(gè)設(shè)備作為服務(wù)器打開(kāi)一個(gè)服務(wù)套接字。當(dāng)遠(yuǎn)端設(shè)備發(fā)起連接連接請(qǐng)求的時(shí)候,并且已經(jīng)連接到了的時(shí)候,Blueboothserversocket類(lèi)將會(huì)返回一個(gè)bluetoothsocket。
Bluetoothclass類(lèi):描述了一個(gè)藍(lán)牙設(shè)備的一般特點(diǎn)和能力。它的只讀屬性集定義了設(shè)備的主、次設(shè)備類(lèi)和一些相關(guān)服務(wù)。然而,它并沒(méi)有準(zhǔn)確地描述所有該設(shè)備所支持的藍(lán)牙文件和服務(wù),而是作為對(duì)設(shè)備種類(lèi)來(lái)說(shuō)的一個(gè)小小暗示。下面說(shuō)說(shuō)具體的編程實(shí)現(xiàn) 1.啟動(dòng)藍(lán)牙功能:
首先通過(guò)調(diào)用靜態(tài)方法getDefaultAdapter()獲取藍(lán)牙適配器BluetoothAdapter,以后你就可以使用該對(duì)象了。如果返回為空,the story is over。例如:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if(mBluetoothAdapter == null){ // Device does not support Bluetooth } 其次,調(diào)用isEnabled()來(lái)查詢(xún)當(dāng)前藍(lán)牙設(shè)備的狀態(tài),如果返回為false,則表示藍(lán)牙設(shè)備沒(méi)有開(kāi)啟,接下來(lái)你需要封裝一個(gè)ACTION_REQUEST_ENABLE請(qǐng)求到intent里面,調(diào)用startActivityForResult()方法使能藍(lán)牙設(shè)備,例如:
if(!mBluetoothAdapter.isEnabled()){ Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}
2.查找設(shè)備:
使用BluetoothAdapter類(lèi)里的方法,你可以查找遠(yuǎn)端設(shè)備(大概十米以?xún)?nèi))或者查詢(xún)?cè)谀闶謾C(jī)上已經(jīng)匹配(或者說(shuō)綁定)的其他手機(jī)了。當(dāng)然需要確定對(duì)方藍(lán)牙設(shè)備已經(jīng)開(kāi)啟或者已經(jīng)開(kāi)啟了“被發(fā)現(xiàn)使能”功能(對(duì)方設(shè)備是可以被發(fā)現(xiàn)的是你能夠發(fā)起連接的前提條件)。如果該設(shè)備是可以被發(fā)現(xiàn)的,會(huì)反饋回來(lái)一些對(duì)方的設(shè)備信息,比如名字、MAC地址等,利用這些信息,你的設(shè)備就可以選擇去向?qū)Ψ匠跏蓟粋€(gè)連接。
如果你是第一次與該設(shè)備連接,那么一個(gè)配對(duì)的請(qǐng)求就會(huì)自動(dòng)的顯示給用戶(hù)。當(dāng)設(shè)備配對(duì)好之后,他的一些基本信息(主要是名字和MAC)被保存下來(lái)并可以使用藍(lán)牙的API來(lái)讀取。使用已知的MAC地址就可以對(duì)遠(yuǎn)端的藍(lán)牙設(shè)備發(fā)起連接請(qǐng)求。
匹配好的設(shè)備和連接上的設(shè)備的不同點(diǎn):匹配好只是說(shuō)明對(duì)方設(shè)備發(fā)現(xiàn)了你的存在,并擁有一個(gè)共同的識(shí)別碼,并且可以連接。連接上:表示當(dāng)前設(shè)備共享一個(gè)RFCOMM信道并且兩者之間可以交換數(shù)據(jù)。也就是是說(shuō)藍(lán)牙設(shè)備在建立RFCOMM信道之前,必須是已經(jīng)配對(duì)好了的。
3.查詢(xún)匹配好的設(shè)備:
在建立連接之前你必須先查詢(xún)配對(duì)好了的藍(lán)牙設(shè)備集(你周?chē)乃{(lán)牙設(shè)備可能不止一個(gè)),以便你選取哪一個(gè)設(shè)備進(jìn)行通信,例如你可以你可以查詢(xún)所有配對(duì)的藍(lán)牙設(shè)備,并使用一個(gè)數(shù)組適配器將其打印顯示出來(lái):
Set
4.掃描設(shè)備:
掃描設(shè)備,只需要簡(jiǎn)單的調(diào)用startDiscovery()方法,這個(gè)掃描的過(guò)程大概持續(xù)是12秒,應(yīng)用程序?yàn)榱薃CTION_FOUND動(dòng)作需要注冊(cè)一個(gè)BroadcastReceiver來(lái)接受設(shè)備掃描到的信息。對(duì)于每一個(gè)設(shè)備,系統(tǒng)都會(huì)廣播ACTION_FOUND動(dòng)作。例如: // Create a BroadcastReceiver for ACTION_FOUND private final BroadcastReceiver mReceiver = new BroadcastReceiver(){ public void onReceive(Context context, Intent intent){ String action = intent.getAction();// When discovery finds a device if(BluetoothDevice.ACTION_FOUND.equals(action)){ // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName()+ “n” + device.getAddress());} } };// Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(mReceiver, filter);// Don't forget to unregister during onDestroy 注意:掃描的過(guò)程是一個(gè)很耗費(fèi)資源的過(guò)程,一旦你找到你需要的設(shè)備之后,在發(fā)起連接請(qǐng)求之前,確保你的程序調(diào)用cancelDiscovery()方法停止掃描。顯然,如果你已經(jīng)連接上一個(gè)設(shè)備,啟動(dòng)掃描會(huì)減少你的通信帶寬。
5.使能被發(fā)現(xiàn):Enabling discoverability 如果你想使你的設(shè)備能夠被其他設(shè)備發(fā)現(xiàn),將ACTION_REQUEST_DISCOVERABLE動(dòng)作封裝在intent中并調(diào)用startActivityForResult(Intent, int)方法就可以了。他將在不使你應(yīng)用程序退出的情況下使你的設(shè)備能夠被發(fā)現(xiàn)。缺省情況下的使能時(shí)間是120秒,當(dāng)然你可以可以通過(guò)添加EXTRA_DISCOVERABLE_DURATION字段來(lái)改變使能時(shí)間(最大不超過(guò)300秒,這是出于對(duì)你設(shè)備上的信息安全考慮)。例如: Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);startActivity(discoverableIntent);運(yùn)行該段代碼之后,系統(tǒng)會(huì)彈出一個(gè)對(duì)話(huà)框來(lái)提示你啟動(dòng)設(shè)備使能被發(fā)現(xiàn)(此過(guò)程中如果你的藍(lán)牙功能沒(méi)有開(kāi)啟,系統(tǒng)會(huì)幫你開(kāi)啟),并且如果你準(zhǔn)備對(duì)該遠(yuǎn)端設(shè)備發(fā)現(xiàn)一個(gè)連接,你不需要開(kāi)啟使能設(shè)備被發(fā)現(xiàn)功能,因?yàn)樵摴δ苤皇窃谀愕膽?yīng)用程序作為服務(wù)器端的時(shí)候才需要。
6.連接設(shè)備:
在應(yīng)用程序中,想建立兩個(gè)藍(lán)牙設(shè)備之間的連接,必須實(shí)現(xiàn)客戶(hù)端和服務(wù)器端的代碼(因?yàn)槿魏我粋€(gè)設(shè)備都必須可以作為服務(wù)端或者客戶(hù)端)。一個(gè)開(kāi)啟服務(wù)來(lái)監(jiān)聽(tīng),一個(gè)發(fā)起連接請(qǐng)求(使用服務(wù)器端設(shè)備的MAC地址)。當(dāng)他們都擁有一個(gè)藍(lán)牙套接字在同一RFECOMM信道上的時(shí)候,可以認(rèn)為他們之間已經(jīng)連接上了。服務(wù)端和客戶(hù)端通過(guò)不同的方式或其他們的藍(lán)牙套接字。當(dāng)一個(gè)連接監(jiān)聽(tīng)到的時(shí)候,服務(wù)端獲取到藍(lán)牙套接字。當(dāng)客戶(hù)可打開(kāi)一個(gè)FRCOMM信道給服務(wù)器端的時(shí)候,客戶(hù)端獲取到藍(lán)牙套接字。
注意:在此過(guò)程中,如果兩個(gè)藍(lán)牙設(shè)備還沒(méi)有配對(duì)好的,android系統(tǒng)會(huì)通過(guò)一個(gè)通知或者對(duì)話(huà)框的形式來(lái)通知用戶(hù)。RFCOMM連接請(qǐng)求會(huì)在用戶(hù)選擇之前阻塞。如下圖:
7.服務(wù)端的連接:
當(dāng)你想要連接兩臺(tái)設(shè)備時(shí),一個(gè)必須作為服務(wù)端(通過(guò)持有一個(gè)打開(kāi)的BluetoothServerSocket),目的是監(jiān)聽(tīng)外來(lái)連接請(qǐng)求,當(dāng)監(jiān)聽(tīng)到以后提供一個(gè)連接上的BluetoothSocket給客戶(hù)端,當(dāng)客戶(hù)端從BluetoothServerSocket得到BluetoothSocket以后就可以銷(xiāo)毀BluetoothServerSocket,除非你還想監(jiān)聽(tīng)更多的連接請(qǐng)求。
建立服務(wù)套接字和監(jiān)聽(tīng)連接的基本步驟:
首先通過(guò)調(diào)用listenUsingRfcommWithServiceRecord(String, UUID)方法來(lái)獲取BluetoothServerSocket對(duì)象,參數(shù)String代表了該服務(wù)的名稱(chēng),UUID代表了和客戶(hù)端連接的一個(gè)標(biāo)識(shí)(128位格式的字符串ID,相當(dāng)于PIN碼),UUID必須雙方匹配才可以建立連接。其次調(diào)用accept()方法來(lái)監(jiān)聽(tīng)可能到來(lái)的連接請(qǐng)求,當(dāng)監(jiān)聽(tīng)到以后,返回一個(gè)連接上的藍(lán)牙套接字BluetoothSocket。最后,在監(jiān)聽(tīng)到一個(gè)連接以后,需要調(diào)用close()方法來(lái)關(guān)閉監(jiān)聽(tīng)程序。(一般藍(lán)牙設(shè)備之間是點(diǎn)對(duì)點(diǎn)的傳輸)
注意:accept()方法不應(yīng)該放在主Acitvity里面,因?yàn)樗且环N阻塞調(diào)用(在沒(méi)有監(jiān)聽(tīng)到連接請(qǐng)求之前程序就一直停在那里)。解決方法是新建一個(gè)線(xiàn)程來(lái)管理。例如: private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket;public AcceptThread(){ // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null;try { // MY_UUID is the app's UUID string, also used by theclient code tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch(IOException e){ } mmServerSocket = tmp;} public void run(){ BluetoothSocket socket = null;// Keep listening until exception occurs or a socket is returned while(true){ try { socket = mmServerSocket.accept();} catch(IOException e){ break;} // If a connection was accepted if(socket!= null){ // Do work to manage the connection(in a separate thread)manageConnectedSocket(socket);mmServerSocket.close();break;} } } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel(){ try { mmServerSocket.close();} catch(IOException e){ } } }
8.客戶(hù)端的連接:
為了初始化一個(gè)與遠(yuǎn)端設(shè)備的連接,需要先獲取代表該設(shè)備的一個(gè)BluetoothDevice對(duì)象。通過(guò)BluetoothDevice對(duì)象來(lái)獲取BluetoothSocket并初始化連接,具體步驟:
使用BluetoothDevice對(duì)象里的方法createRfcommSocketToServiceRecord(UUID)來(lái)獲取BluetoothSocket。UUID就是匹配碼。然后,調(diào)用connect()方法來(lái)。如果遠(yuǎn)端設(shè)備接收了該連接,他們將在通信過(guò)程中共享RFFCOMM信道,并且connect()方法返回。例如: private class ConnectThread extends Thread { private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device){ // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null;mmDevice = device;// Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch(IOException e){ } mmSocket = tmp;}
public void run(){ // Cancel discovery because it will slow down the connection mAdapter.cancelDiscovery();try { // Connect the device through the socket.This will block // until it succeeds or throws an exception mmSocket.connect();} catch(IOException connectException){ // Unable to connect;close the socket and get out try { mmSocket.close();} catch(IOException closeException){ } return;} // Do work to manage the connection(in a separate thread)manageConnectedSocket(mmSocket);}
注意:conncet()方法也是阻塞調(diào)用,一般建立一個(gè)獨(dú)立的線(xiàn)程中來(lái)調(diào)用該方法。在設(shè)備discover過(guò)程中不應(yīng)該發(fā)起連接connect(),這樣會(huì)明顯減慢速度以至于連接失敗。且數(shù)據(jù)傳輸完成只有調(diào)用close()方法來(lái)關(guān)閉連接,這樣可以節(jié)省系統(tǒng)內(nèi)部資源。
9.管理連接(主要涉及數(shù)據(jù)的傳輸):
當(dāng)設(shè)備連接上以后,每個(gè)設(shè)備都擁有各自的BluetoothSocket?,F(xiàn)在你就可以實(shí)現(xiàn)設(shè)備之間數(shù)據(jù)的共享了。
1> 首先通過(guò)調(diào)用getInputStream()和getOutputStream()方法來(lái)獲取輸入輸出流。然后通過(guò)調(diào)用read(byte[])和write(byte[]).方法來(lái)讀取或者寫(xiě)數(shù)據(jù)。
2> 實(shí)現(xiàn)細(xì)節(jié):以為讀取和寫(xiě)操作都是阻塞調(diào)用,需要建立一個(gè)專(zhuān)用現(xiàn)成來(lái)管理。3>
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket;private final InputStream mmInStream;private final OutputStream mmOutStream;public ConnectedThread(BluetoothSocket socket){ mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut = null;// Get the input and output streams, using temp objects because // member streams are final try { tmpIn = socket.getInputStream();tmpOut = socket.getOutputStream();} catch(IOException e){ } mmInStream = tmpIn;mmOutStream = tmpOut;} public void run(){ byte[] buffer = new byte[1024];// buffer store for the stream int bytes;// bytes returned from read()// Keep listening to the InputStream until an exception occurs while(true){ try { // Read from the InputStream bytes = mmInStream.read(buffer);// Send the obtained bytes to the UI Activity mHandler.obtainMessage(MESSAGE_READ, bytes,-1, buffer).sendToTarget();} catch(IOException e){ break;} } } /* Call this from the main Activity to send data to the remote device */ public void write(byte[] bytes){ try { mmOutStream.write(bytes);} catch(IOException e){ } } /* Call this from the main Activity to shutdown the connection */ public void cancel(){ try { mmSocket.close();} catch(IOException e){ } } }
第三篇:iOS 藍(lán)牙使用小結(jié) bluetooth
iOS 藍(lán)牙使用小結(jié) bluetooth
現(xiàn)將創(chuàng)建藍(lán)牙工程的要點(diǎn)總結(jié)一下,由于工程主要涉及中心模式,所以只總結(jié)中心模式的用法 1,引入CoreBluetooth.framework 2,實(shí)現(xiàn)藍(lán)牙協(xié)議,如:.h文件如下
@protocol CBCentralManagerDelegate;
@protocol CBPeripheralDelegate;@interface ViewController : UIViewController.m文件如下
#import “CoreBluetooth/CoreBluetooth.h”
另外還有代理部分請(qǐng)自行添加3,下面是使藍(lán)牙動(dòng)起來(lái)的過(guò)程
3.1創(chuàng)建CBCentralManager實(shí)例
self.cbCentralMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
設(shè)置代理,比如:
self.cbCentralMgr.delegate = self;創(chuàng)建數(shù)組管理外設(shè)
self.peripheralArray = [NSMutableArray array];3.2掃描周?chē)乃{(lán)牙
實(shí)際上周?chē)乃{(lán)牙如果可被發(fā)現(xiàn),則會(huì)一直往外發(fā)送廣告消息,中心設(shè)備就是通過(guò)接收這些消息來(lái)發(fā)現(xiàn)周?chē)乃{(lán)牙的
NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false],CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.cbCentralMgr scanForPeripheralsWithServices:nil options:dic];3.3發(fā)現(xiàn)一個(gè)藍(lán)牙設(shè)備
也就是收到了一個(gè)周?chē)乃{(lán)牙發(fā)來(lái)的廣告信息,這是CBCentralManager會(huì)通知代理來(lái)處理
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
}
如果周?chē)乃{(lán)牙有多個(gè),則這個(gè)方法會(huì)被調(diào)用多次,你可以通過(guò)tableView或其他的控件把這些周?chē)乃{(lán)牙的信息打印出來(lái)
3.4連接一個(gè)藍(lán)牙
[self.cbCentralMgr connectPeripheral:peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
一個(gè)中心設(shè)備可以同時(shí)連接多個(gè)周?chē)乃{(lán)牙設(shè)備
當(dāng)連接上某個(gè)藍(lán)牙之后,CBCentralManager會(huì)通知代理處理-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { }因?yàn)樵诤竺嫖覀円獜耐庠O(shè)藍(lán)牙那邊再獲取一些信息,并與之通訊,這些過(guò)程會(huì)有一些事件可能要處理,所以要給這個(gè)外設(shè)設(shè)置代理,比如: peripheral.delegate = self;
3.5查詢(xún)藍(lán)牙服務(wù)
[peripheral discoverServices:nil];返回的藍(lán)牙服務(wù)通知通過(guò)代理實(shí)現(xiàn)
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {for(CBService* service in peripheral.services){
} }
3.6查詢(xún)服務(wù)所帶的特征值
[peripheral discoverCharacteristics:nil forService:service];
返回的藍(lán)牙特征值通知通過(guò)代理實(shí)現(xiàn)-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {for(CBCharacteristic * characteristic in service.characteristics){ } }
3.7給藍(lán)牙發(fā)數(shù)據(jù)
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
這時(shí)還會(huì)觸發(fā)一個(gè)代理事件
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { }
3.8處理藍(lán)牙發(fā)過(guò)來(lái)的數(shù)據(jù)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { }3.9 retrievePeripheralsWithIdentifiers 使用例子
-(IBAction)Retrieve:(id)Sender { [self.tvLog setText:@“"];
NSMutableArray * Identifiers = [NSMutableArray array];
for(CBPeripheral * peripheral in self.peripheralArray){ [Identifiers addObject:peripheral.identifier];}[self addLog:@”[self.cbCentralMgr retrievePeripheralsWithIdentifiers:self.PeripheralIdentifiers]“];
self.retrievePeripherals = [self.cbCentralMgr retrievePeripheralsWithIdentifiers:Identifiers];
for(CBPeripheral* peripheral in self.retrievePeripherals){ [self addLog:[NSString stringWithFormat: @”%@ name:%@“,peripheral,peripheral.name]];}
[self.tableViewPeripheral reloadData];}3.10 retrieveConnectedPeripheralsWithServices 使用例子-(IBAction)Retrieve:(id)Sender { [self.tvLog setText:@”“];
NSMutableArray * services = [NSMutableArray array];
for(CBPeripheral * peripheral in self.peripheralArray){
if(peripheral.isConnected){
for(CBService *service in peripheral.services){ [services addObject:service.UUID];} } }[self addLog:@”[self.cbCentralMgr retrieveConnectedPeripheralsWithServices:peripheral.services]“];
self.retrievePeripherals = [self.cbCentralMgr retrieveConnectedPeripheralsWithServices:services];
for(CBPeripheral* peripheral in self.retrievePeripherals){ [self addLog:[NSString stringWithFormat: @”%@ name:%@",peripheral,peripheral.name]];}
[self.tableViewPeripheral reloadData];}
第四篇:藍(lán)牙通信原理
藍(lán)牙耳機(jī)的工作原理:
關(guān)于音頻流的藍(lán)牙傳輸可以通過(guò)兩個(gè)方式:
1)通過(guò)PCM接口來(lái)傳送
2)通過(guò)模擬UART來(lái)傳送
下面分別來(lái)講述:
1)通過(guò)PCM接口來(lái)傳送
通過(guò)音頻播放器(eg: Media Player)來(lái)打開(kāi)音頻文件,調(diào)用Audio驅(qū)動(dòng),音頻文件通過(guò)解碼后,由PCM輸出到Host端藍(lán)牙模塊的PCM輸入端,接著,經(jīng)過(guò)藍(lán)牙模塊的處理后,由RF無(wú)線(xiàn)模塊發(fā)送給Client 端藍(lán)牙設(shè)備。
Client 端藍(lán)牙設(shè)備經(jīng)由無(wú)線(xiàn)接收模塊后,濾波,穩(wěn)壓,經(jīng)微處理芯片處理后,直接由Speaker播放。
2)通過(guò)模擬UART來(lái)傳送
通過(guò)設(shè)置注冊(cè)表【HKEY_LOCAL_MACHINEServicesBTAGSVC】IsEnabled =1 使得系統(tǒng)引導(dǎo)時(shí)自動(dòng)加載語(yǔ)音網(wǎng)關(guān)(AG)服務(wù)。
首先,通過(guò)手動(dòng)配置建立Host端藍(lán)牙設(shè)備與Client端藍(lán)牙設(shè)備ACL鏈接(面向無(wú)連接的異步鏈路),接著在Applicaiton或Audio Driver中調(diào)用
IOCTL_AG_OPEN_AUDIO,重新建立Host端藍(lán)牙設(shè)備與Client端藍(lán)牙設(shè)備SCO鏈接(面向連接的同步鏈路),接著AG自動(dòng)發(fā)送
waveOutMessage((HWAVEOUT)i, WODM_BT_SCO_AUDIO_CONTROL, 0, TRUE);從而建立了Audio至藍(lán)牙芯片之間的通道,也即,實(shí)現(xiàn)了音頻流到藍(lán)牙模塊的傳送。
然后,經(jīng)由主機(jī)端藍(lán)牙模塊將音頻流打包經(jīng)由RF模塊發(fā)送出去。
客戶(hù)端藍(lán)牙耳機(jī)接收到無(wú)線(xiàn)音頻包后,濾波,穩(wěn)壓,經(jīng)微處理芯片處理后,由PCM傳送給音頻編解碼器芯片,最后,由Speaker播放。
第五篇:藍(lán)牙工程師崗位職責(zé)
1.藍(lán)牙產(chǎn)品原理圖,PCB圖設(shè)計(jì)(新產(chǎn)品設(shè)計(jì))。
2.樣機(jī)調(diào)試。
3.工程文件的擬定。
4.產(chǎn)品試產(chǎn)、量產(chǎn)的跟進(jìn)及問(wèn)題分析處理。