www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]作者:Sam (甄峰) sam_code@hotmail.com (HCI協(xié)議簡(jiǎn)介,HCI在BlueZ中的實(shí)現(xiàn)以及HCI編程接口) ? 1. HCI層協(xié)議概述: HCI提供一套統(tǒng)一的方法來(lái)訪問(wèn)Blue

作者:Sam (甄峰) sam_code@hotmail.com

(HCI協(xié)議簡(jiǎn)介,HCI在BlueZ中的實(shí)現(xiàn)以及HCI編程接口)

?

1. HCI層協(xié)議概述:

HCI提供一套統(tǒng)一的方法來(lái)訪問(wèn)Bluetooth底層。如圖所示:

?

Bluetooth編程(三)?HCI層編程" title="實(shí)戰(zhàn)Linux?Bluetooth編程(三)?HCI層編程" />

?

從圖上可以看出,Host ControllerInterface(HCI)??就是用來(lái)溝通Host和Module。Host通常就是PC,Module則是以各種物理連接形式(USB,serial,pc-card等)連接到PC上的bluetooth Dongle。

在Host這一端:application,SDP,L2cap等協(xié)議都是軟件形式提出的(Bluez中是以kernel層程序)。在Module這一端:LinkManager, BB, 等協(xié)議都是硬件中firmware提供的。

而HCI則比較特殊,它一部分在軟件中實(shí)現(xiàn),用來(lái)給上層協(xié)議和程序提供訪問(wèn)接口(Bluez中,hci.chci_usb.c,hci_sock.c等).另一部分也是在Firmware中實(shí)現(xiàn),用來(lái)將軟件部分的指令等用底層協(xié)議明白的方式傳遞給底層。

?

居于PC的上層程序與協(xié)議和居于Modules的下層協(xié)議之間通過(guò)HCI溝通,有4種不同形式的傳輸:Commands,Event, ACL Data, SCO/eSCO Data。

?

1.1. HCI Command:

HCI Command是Host向Modules發(fā)送命令的一種方式。HCI Command Packet結(jié)構(gòu)如下:

Bluetooth編程(三)?HCI層編程" title="實(shí)戰(zhàn)Linux?Bluetooth編程(三)?HCI層編程" />

OpCode用來(lái)唯一標(biāo)識(shí)HCI Command.它由2部分組成,10bit的Opcode Command.6bit的Opcode Group。

?

1.1.1: OpCode Group:

Linux Kernel(BlueZ)中,~/include/net/bluetooth/hci.h中定義了OpCodeGroup。

#define OGF_LINK_CTL?0x01

#defineOGF_LINK_POLICY?0x02??

#define OGF_HOST_CTL?0x03

#defineOGF_INFO_PARAM?0x04

#defineOGF_STATUS_PARAM?0x05

它們代表了不同的Command Group:

?

OGF_LINK_CTL: Link control,這個(gè)CommandGroup中的Command允許Host控制與其它bluetooth device 的連接。

OGF_LINK_POLICY?:LinkPolicy。這個(gè)Command Group中的Command允許調(diào)整Link Manager control.

OGF_HOST_CTL: Control and Baseband.

?

1.1.2: Opcode Command:?

用來(lái)在同一個(gè)Group內(nèi)唯一識(shí)別Command。~/include/net/bluetooth/hci.h中定義。

?

?

1.2: HCI Event:

Modules向Host發(fā)送一些信息,使用HCI Event。Event Packet結(jié)構(gòu)如下:

Bluetooth編程(三)?HCI層編程" title="實(shí)戰(zhàn)Linux?Bluetooth編程(三)?HCI層編程" />

HCI Event分3種:Command complete Event, Command StatesEvent,Command Subsequently Completend.

Command complete Event:如果Host發(fā)送的Command可以立刻有結(jié)果,則會(huì)發(fā)送此類Event。也就是說(shuō),如果發(fā)送的Command只與本地Modules有關(guān),不與remote設(shè)備打交道,則使用Commandcomplete Event。例如:HCI_Read_Buffer_Size.

Command StatesEvent:如果Host發(fā)送的Command不能立刻得知結(jié)果,則發(fā)送此類Event。Host發(fā)送的Command執(zhí)行要與Remote設(shè)備打交道,則必然無(wú)法立刻得知結(jié)果,所以會(huì)發(fā)送CommandStates Event.例如:

HCI Connect。

Command SubsequentlyCompletend:Command延后完成Event。例如:連接已建立。

?

下圖是一個(gè)Command-Event例子:

Bluetooth編程(三)?HCI層編程" title="實(shí)戰(zhàn)Linux?Bluetooth編程(三)?HCI層編程" />

從這里可以看出,如果Host發(fā)送的Command是與Remote device有關(guān)的,則會(huì)先發(fā)送CommandStates Event?。等動(dòng)作真正完成了,再發(fā)送Command Subsequently Completend。

?

HCI ACL與SCO數(shù)據(jù),這里就不多講了。只需要明白,l2cap數(shù)據(jù)是通過(guò)ACL數(shù)據(jù)傳輸給remotedevice的。

下圖很明白的展示了l2cap數(shù)據(jù)如何一步一步轉(zhuǎn)化為USB數(shù)據(jù)并傳遞給底層協(xié)議的。

Bluetooth編程(三)?HCI層編程" title="實(shí)戰(zhàn)Linux?Bluetooth編程(三)?HCI層編程" />

很明顯,一個(gè)l2cap包會(huì)按照規(guī)則先切割為多個(gè)HCI數(shù)據(jù)包。HCI數(shù)據(jù)包再通過(guò)HCI-usb這一層傳遞給USB設(shè)備。每個(gè)包又通過(guò)USBdriver發(fā)送到底層。

?

?

2. HCIprotocol的實(shí)現(xiàn):

(稍后添加)

?

?

3. HCI 層的編程:

正如上一節(jié)所說(shuō),HCI是溝通上層協(xié)議以及程序與底層硬件協(xié)議的通道。所以,通過(guò)HCI發(fā)送的Command都是上層協(xié)議或者應(yīng)用程序發(fā)送給BluetoothDongle的。它命令Bluetooth Dongle(或其中的硬件協(xié)議)去做什么何種動(dòng)作。

?

3.0:得到Host上插入Dongle數(shù)目以及Dongle信息:

我們先復(fù)習(xí)一下socket的概念:

使用函數(shù)socket()建立一個(gè)Socket,就如同你有一部電話.bind()則是把這個(gè)電話和某個(gè)電話號(hào)碼(網(wǎng)絡(luò)地址)對(duì)應(yīng)起來(lái)。

類似的,我們可以把Host理解為一個(gè)房間,這個(gè)房間有多部電話(Dongle)。

當(dāng)使用socket() 打開(kāi)一個(gè)HCIprotocol的socket,表明得到這個(gè)房間的句柄。HOST可能會(huì)有多個(gè)Dongle。換句話說(shuō),這個(gè)房間可以有多個(gè)電話號(hào)碼。所以HCI會(huì)提供一套指令去得到這些Dongle。

?

?

//0.?分配一個(gè)空間給?hci_dev_list_req。這里面將放所有Dongle信息。

struct hci_dev_list_req *dl;
struct hci_dev_req *dr;

struct hci_dev_info di;

int i;

?

?if (!(dl = malloc(HCI_MAX_DEV * sizeof(structhci_dev_req) + sizeof(uint16_t)))) {
??perror("Can't allocatememory");
??exit(1);
?}
?dl->dev_num = HCI_MAX_DEV;
?dr = dl->dev_req;

?

?

//1. 打開(kāi)一個(gè)HCI socket.此socket相當(dāng)于一個(gè)房間。

if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI))< 0) {
??perror("Can't open HCIsocket.");
??exit(1);
?}

?

// 2. 使用HCIGETDEVLIST,得到所有dongle的DeviceID。存放在dl中。??

?if (ioctl(ctl, HCIGETDEVLIST, (void *) dl)< 0) {
??perror("Can't get devicelist");
??exit(1);
?}

?

// 3 使用HCIGETDEVINFO,得到對(duì)應(yīng)Device ID的Dongle信息。

di.dev_id = (dr+i)->dev_id;
ioctl(ctl, HCIGETDEVINFO, (void *) &di);

?

這樣就能得到所有Dongle信息。

struct hci_dev_info {
?uint16_tdev_id;?? //dongle DeviceID
?char????name[8];? //Dongle name

?bdaddr_tbdaddr;?? //Dongle bdaddr

?uint32_tflags;???//Dongle Flags:如:UP,RUNING,Down等。
?uint8_t?type;?? //Dongle連接方式:如USB,PCCard,UART,RS232等。

?uint8_t? features[8];

?uint32_t pkt_type;
?uint32_t link_policy;
?uint32_t link_mode;

?uint16_t acl_mtu;
?uint16_t acl_pkts;
?uint16_t sco_mtu;
?uint16_t sco_pkts;

?struct??hci_dev_stats stat;? //此Dongle的數(shù)據(jù)信息,如發(fā)送多少個(gè)ACLPacket,正確多少,錯(cuò)誤多少,等等。
};

?

3.0.1: UP和Down Bluetooth Dongle:

ioctl(ctl, HCIDEVUP, hdev)

ioctl(ctl, HCIDEVDOWN, hdev)

ctl:為使用socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)打開(kāi)的Socket.

hdev: Dongle Device ID.(所以上面的Socket不需要bind,因?yàn)檫@邊指定了)

?

?

?

?

?

3.1BlueZ提供的HCI編程接口一(針對(duì)本地Dongle的API系列):

3.1。1 打開(kāi)一個(gè)HCI Socket---int hci_open_dev(intdev_id):

這個(gè)function用來(lái)打開(kāi)一個(gè)HCI Socket。它首先打開(kāi)一個(gè)HCIprotocol的Socket(房間),并將此Socket與deviceID=參數(shù)dev_id的Dongle綁定起來(lái)。只有bind后,它才將Socket句柄與Dongle對(duì)應(yīng)起來(lái)。

注意,所有的HCI Command發(fā)送之前,都需要使用hci_open_dev打開(kāi)并綁定。

?

3.1.2: 關(guān)閉一個(gè)HCI Socket:

int hci_close_dev(int dd)//簡(jiǎn)單的關(guān)閉使用hci_open_dev打開(kāi)的Socket。

?

3.1.3: 向HCI Socket(對(duì)應(yīng)一個(gè)Dongle)發(fā)送request:

int hci_send_req(int dd, structhci_request *r, int to)

BlueZ提供這個(gè)function非常有用,它可以實(shí)現(xiàn)一切Host向Modules發(fā)送Command的功能。

參數(shù)1:HCI Socket。

參數(shù)2:Command內(nèi)容。

參數(shù)3:以milliseconds為單位的timeout.

下面詳細(xì)解釋此function和用法:

當(dāng)應(yīng)用程序需要向Dongle(對(duì)應(yīng)為一個(gè)bind后的Socket)發(fā)送Command時(shí),調(diào)用此function.

其中,參數(shù)一dd對(duì)應(yīng)一個(gè)使用hci_open_dev()打開(kāi)的Socket(Dongle)。

參數(shù)三to則為等待Dongle執(zhí)行并回復(fù)命令結(jié)果的timeout.以毫秒為單位。

參數(shù)二hci_request * r 最為重要,首先看它的結(jié)構(gòu):

struct hci_request {
?uint16_togf;????//OpcodeGroup
?uint16_tocf;????//OpcodeCommand
?int?????event;? //此Command產(chǎn)生的Event類型。
?void????*cparam; //Command 參數(shù)
?int?????clen;???//Command參數(shù)長(zhǎng)度
?void????*rparam;? //Response參數(shù)
?int?????rlen;???//Response 參數(shù)長(zhǎng)度
};

ogf,ocf不用多說(shuō),對(duì)應(yīng)前面的圖就明白這是Group Code和Command Code。這兩項(xiàng)先確定下來(lái),然后可以查HCISpec。察看輸入?yún)?shù)(cparam)以及輸出參數(shù)(rparam)含義。至于他們的結(jié)構(gòu)以及參數(shù)長(zhǎng)度,則在~/include/net/bluetooth/hci.h中有定義。

至于event.如果設(shè)置,它會(huì)被setsockopt設(shè)置于Socket。

?

例1:得到某個(gè)連接的Policy Setting.

HCISpec以及~/include/net/bluetooth/hci.h中均可看到,OGF=OGF_LINK_POLICY(0x02).OCF=OCF_READ_LINK_POLICY(0x0C).

因?yàn)檫@個(gè)Command用來(lái)讀取某個(gè)ACL連接的Policy Setting。所以輸入?yún)?shù)即為此連接Handle.

返回參數(shù)則包含3部分,status(Command是否順利執(zhí)行), handle(連接Handle)。policy(得到的policy值)

這就又引入了一個(gè)新問(wèn)題,如何得到某個(gè)ACL連接的Handle。

可以使用ioctl HCIGETCONNINFO得到ACL 連接Handle。

ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);

Connect_handle =htobs(cr->conn_info->handle);

?

所以完整的過(guò)程如下:

?

struct hci_request HCI_Request;
?read_link_policy_cp Command_Param;
?read_link_policy_rp Response_Param;

// 1.得到ACL Connect Handle

if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr)< 0)?
?{??
??return?-1;
?}
?Connect_handle =htobs(cr->conn_info->handle);

?

memset(&HCI_Request, 0,sizeof(HCI_Request));
?memset(&Command_Param, 0 ,sizeof(Command_Param));
?memset(&Response_Param, 0 ,sizeof(Response_Param));

?

// 2.填寫Command輸入?yún)?shù)
?Command_Param.handle = Connect_handle;

?

?

HCI_Request.ogf = OGF_LINK_POLICY;?//Command組ID
?HCI_Request.ocf = OCF_READ_LINK_POLICY; //CommandID
?HCI_Request.cparam =&Command_Param;
?HCI_Request.clen =READ_LINK_POLICY_CP_SIZE;
?HCI_Request.rparam =&Response_Param;
?HCI_Request.rlen = READ_LINK_POLICY_RP_SIZE;

?

if (hci_send_req(dd, &HCI_Request, to)< 0)
?{
??perror("nhci_send_req()");
??return -1;
?}

//如果返回值狀態(tài)不對(duì)

?if (Response_Param.status) {
??return?-1;
?}
?

//得到當(dāng)前policy
?*policy = Response_Param.policy;

?

?

3.1.4:幾個(gè)更基礎(chǔ)的function:

static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)//bdaddr copy

static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t*ba2)//bdaddr 比較

?

?

3.1.5: 得到指定Dongle BDAddr:

int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to);

參數(shù)1:HCISocket,使用hci_open_dev()打開(kāi)的Socket(Dongle)。

參數(shù)2:輸出參數(shù),其中會(huì)放置bdaddr.

參數(shù)3:以milliseconds為單位的timeout.

?

?

?

3.1.6: 讀寫Dongle Name:

int hci_read_local_name(int dd, int len, char *name, int to)

int hci_write_local_name(int dd, const char *name, int to)

參數(shù)1:HCISocket,使用hci_open_dev()打開(kāi)的Socket(Dongle)。

參數(shù)2:讀取或設(shè)置Name。

參數(shù)3:以milliseconds為單位的timeout.

注意:這里的Name與IOCTL HCIGETDEVINFO 得到hci_dev_info中的name不同。

?

3.1.7:得到HCI Version:

int hci_read_local_version(int dd, struct hci_version *ver, intto)

?

?

3.1.8:得到已經(jīng)UP的Dongle BDaddr:

int hci_devba(int dev_id, bdaddr_t *bdaddr);

dev_id: Dongle Device ID.

bdaddr:輸出參數(shù),指定Dongle如果UP, 則放置其BDAddr。

?

3.1.9: 得到Dongle Info:

int hci_devinfo(int dev_id, struct hci_dev_info *di)

dev_id: Dongle Device ID.

di: 此Dongle信息。

出錯(cuò)返回 -1。

注意,這個(gè)Function的做法與3.0的方法完全一致。

?

3.1.10:從hciX中得到X:

int hci_devid(const char *str)

str: 類似 hci0這樣的字串。

如果hciX對(duì)應(yīng)的Device ID(X)是現(xiàn)實(shí)存在且UP。則返回此設(shè)備DeviceID。?

?

3.1.11:得到BDADDR不等于參數(shù)bdaddr的DongleDevice ID:

int hci_get_route(bdaddr_t *bdaddr)

查找Dongle,發(fā)現(xiàn)Dongle Bdaddr不等于參數(shù)bdaddr的第一個(gè)Dongle,則返回此Dongle DeviceID。

所以,如果: int hci_get_route(NULL),則得到第一個(gè)可用的Dongle Device ID。

?

?

3.1.12: 將BDADDR轉(zhuǎn)換為字符串:

int ba2str(const bdaddr_t *ba, char *str)

?

3.1.13: 將自串轉(zhuǎn)換為BDADDR:

int str2ba(const char *str, bdaddr_t *ba)

?

?

3.2BlueZ提供的HCI編程接口二(針對(duì)Remote Device的API系列):

3.2.1? inquiry 遠(yuǎn)程BluetoothDevice:

int hci_inquiry(int dev_id, int len, int nrsp, const uint8_t*lap, inquiry_info **ii, long flags)

hci_inquiry()用來(lái)命令指定的Dongle去搜索周圍所有bluetoothdevice.并將搜索到的Bluetooth Device bdaddr 傳遞回來(lái)。

參數(shù)1:dev_id:指定Dongle Device ID。如果此值小于0,則會(huì)使用第一個(gè)可用的Dongle。

參數(shù)2:len: 此次inquiry的時(shí)間長(zhǎng)度(每增加1,則增加1.25秒時(shí)間)

參數(shù)3:nrsp:此次搜索最大搜索數(shù)量,如果給0。則此值會(huì)取255。

參數(shù)4:lap:BDADDR中LAP部分,Inquiry時(shí)這塊值缺省為0X9E8B33.通常使用NULL。則自動(dòng)設(shè)置。

參數(shù)5:ii:存放搜索到BluetoothDevice的地方。給一個(gè)存放inquiry_info指針的地址,它會(huì)自動(dòng)分配空間。并把那個(gè)空間頭地址放到其中。

參數(shù)6:flags:搜索flags.使用IREQ_CACHE_FLUSH,則會(huì)真正重新inquiry。否則可能會(huì)傳回上次的結(jié)果。

?

返回值是這次Inquiry到的Bluetooth Device 數(shù)目。

?

注意:如果*ii不是自己分配的,而是讓hci_inquiry()自己分配的,則需要調(diào)用bt_free()來(lái)幫它釋放空間。

?

?

3.2.2:得到指定BDAddr的reomte device Name:

int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, intlen, char *name, int to)

參數(shù)1:使用hci_open_dev()打開(kāi)的Socket。

參數(shù)2:對(duì)方BDAddr.

參數(shù)3:name 長(zhǎng)度。

參數(shù)4:(out)放置name的位置。

參數(shù)5:等待時(shí)間。

?

3.2.3: 讀取連接的信號(hào)強(qiáng)度:

int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, intto)

注意,所有對(duì)連接的操作,都會(huì)有一個(gè)參數(shù),handle.這個(gè)參數(shù)是連接的Handle。前面講過(guò)如何得到連接Handle的。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉