通过Bluez提供的Interface发送HCI Command

作者: Sam(甄峰) [email protected]


背景:
Sam在做Bluetooth USB Dongle与Bluetooth RemoteControl连接的程序时。因为Bluetooth Remote Control会在连接后发送 sniffrequest.约定双方的数据频率为5ms. 但因为Linux程序这端没有处理Sniff(缺省为disable).所以这个request没有成功。造成双方的数据传输并不是定时传输,而是当channel忙时发数据少,channel不忙时发数据多。于是空中鼠标非常不稳定。Ray要求添加1.EnableSniff. 2. set Sniff mode.

Sam于是创建了三个接口:
1. Read_LINK_POLICY() //read Link policy. sniff包含在其中
2. Wiret_LINK_POLICY() //write Link policy.
3. Set_Sniff_Mode() //设置sniff

如前面Blog中所说:可以使用BlueZ提供的Interface发送HCI Command。
int hci_send_req(int dd,struct hci_request *r, int to)



1.Command知识学习:

Sam首先查看:Host Controller InterfaceFunctional Specification文档中HCI Commands andEvents.->Link PolicyCommands->ReadLink Policy Settings Command.
Command:HCI_Read_Link_Policy_Settings
OCF: 0x000C
Command Parameters:Connection_Handle
Return Parameters: Status,Connection_Handle Link_Policy_Settings
说明:这个Command 从指定的Connection Handle读取Link Policy 设置。这个ConnectionHandle必须是ACL连接的。
CommandParameters:
1. Connection_Handle(Size:2 Octets):一个连接的句柄。
Retrun Parameters:返回参数
返回参数1. Status: 0x00: 读取成功
0x01-0xFF: 可以从Error Code表中找到错误含义。
返回参数2. Connection_Handle: 一个连接的句柄。
返回参数3. Link_Policy_Settings:
0x0000: Disable All LM Modes Default.
0x0001: Enable Role Switch
0x0002: Enable Hold Mode.
0x0004: Enable Sniff Mode.
0x0008: Enable Park State.
EventGenerate:
当 Read_link_Policy_Settings命令执行完毕时,会发送一个 Command CompleteEvent.

2.具体编程
Sam发现BlueZ提供的用户层Interface中(也就是BlueZ-lib中)并没有直接提供发送命令--Read LinkPolicy Settings 的接口。但提供了发送Read Remote VersionInformation的接口。这就很简单了,直接仿照这个接口写一个function即可。
BlueZ-lib中的Read Remote Version Information function:
int hci_read_remote_version(int dd, uint16_t handle, structhci_version *ver, int to)
这个function的用法可以参考BlueZ-uitil。
参数描述:
int dd: 由hci_open_dev()返回的HCI Socket 句柄。
uint16_t handle: 一个连接的句柄。
struct hci_version *ver: 返回的版本结构体。
int to: 等待的时间。

这个function 的核心就是前文介绍的: hci_send_req(dd, &rq,to)
只需要读懂它的参数配置,我们的仿造function就算成功了。
其中,dd就是hci_open_dev() 返回的HCI Socket Handle。 to 就是等待时间。
重点是 hci_request * rq
这个结构体如下:
struct hci_request
{
uint16_t ogf; //Command组编号
uint16_t ocf; // Command编号 。由这两个ID号组合,唯一确定Command.
int event; // Command 成功后将自动发送这个Event。
void *cparam; //CommandParam.命令参数。
int clen; //命令参数长度
void *rparam; //response Param。返回参数
int rlen; //返回参数长度
};
其中
ogf, ocf很明显,填上OGF_LINK_POLICY,OCF_READ_LINK_POLICY就可以了。
event:因为文档中讲此Command成功的话,就会发送Command Complete Event. 所以不用指定了。
clen: 文档中讲了:2个字节。 BlueZ中hci.h中也指定了:
#define READ_LINK_POLICY_CP_SIZE 2

rparam: response 参数:文档中有讲,包括三项:BlueZ 中hci.h也定义了:
typedef struct
{
uint8_t status;
uint16_t handle;
uint16_t policy;
} __attribute__ ((packed)) read_link_policy_rp;

rlen: response 参数长度:#define READ_LINK_POLICY_RP_SIZE 5
cparam:Command参数:如文档中所讲,结构体如下:
typedef struct
{
uint16_t handle;
} __attribute__ ((packed)) read_link_policy_cp;

综上所述,可以如下设置:

BTX_Rel hci_Read_Link_Policy(int dd, uint16_t handle, uint16_t*policy, int to)
{
struct hci_request HCI_Request;
read_link_policy_cp Command_Param;
read_link_policy_rp Response_Param;

memset(&HCI_Request, 0, sizeof(HCI_Request));
memset(&Command_Param, 0 ,sizeof(Command_Param));
memset(&Response_Param, 0 ,sizeof(Response_Param));
// 1.
set Command Param Command_Param.handle = handle;
// 2.
set hci_request HCI_Request.ogf = OGF_LINK_POLICY;//Command组ID
HCI_Request.ocf = OCF_READ_LINK_POLICY; //Command ID
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)
{
perror("\nhci_send_req()");
return BTX_SEND_CMD_TO_REMOTE_ERR;
}
if (Response_Param.status)
{ return BTX_SEND_CMD_TO_REMOTE_ERR; }

*policy = Response_Param.policy;
return BTX_SUCCESS;
}


3. 用法:
1. hci socket的得到:
dd = hci_open_dev(dev_id);

if (dd < cr ="malloc(sizeof(*cr)">bdaddr,&des_bdaddr);
cr->type = ACL_LINK;
}
if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) <connect_handle ="htobs(cr-">conn_info->handle);

3.调用
Rel_get_policy = hci_Read_Link_Policy(dd, Connect_handle,&polidy, 1000);
if(Rel_get_policy != BTX_SUCCESS)
{
printf("\nRead Link Policy Error[%d]", Rel_get_policy);
}
else
{
printf("\nPolicy is:[0x%x]", polidy);
}

4.关闭HCI Socket(这一步一定要做)
hci_close_dev(dd);

你可能感兴趣的:(通过Bluez提供的Interface发送HCI Command)