问题点5:原生BT中,HID Host如何主动连接HID Device的控制通道和中断通道;
因HID 的控制通道(Control Channel)和中断通道(Interrupt Channel)实际上是两条L2CAP 通道,这两条通道有固定的PSM值(控制通道的PSM 是0x0011, 中断通道的PSM值是0x0013);
原生BT 中,主动发起L2CAP 连接的API 是L2CA_ConnectReq;
PSM的宏定义是:
#define HID_PSM_CONTROL 0x0011
#define HID_PSM_INTERRUPT 0x0013
基于HID Spec,HID 的两条通道,先建立控制通道,再建立中断通道;断开时,先断开中
断通道,再断开控制通道;
Tracing 发现:原生BT 的HID Host主动连接时执行控制通道建立的API是:
hidh_conn_initiate
控制通道建立后,再建立中断通道。当前中断通道是在API hidh_l2cif_config_ind中建立,其是其控制通道建立后,执行L2CAP 配置,然后触发的中断通道建立;
每条通道建立后,将得到对应的CID(Channel ID)值;
表示控制通道的CID是“p_hcon->ctrl_cid”;
表示中断通道的CID是“p_hcon->intr_cid”
问题点6:原生BT中,HID Host通过L2CAP 中断通道发送Data的API;
基于以上找到的CID 表示“p_hcon->intr_cid”, 我们定位到最终通过L2CAP 发送的实现是基于API L2CA_DataWrite;
所以当前中断通道发送中断data的API是:hidh_conn_snd_data
问题点7:原生BT中,HID Host如何接收Data;
在API hidh_l2cif_data_ind(HID Device 的是:hidd_l2cif_data_ind)中接收到L2CAP 数据,并通过CID值来判别收到的是控制通道还是中断通道Data;此API是通过API
L2CA_Register注册的函数指针,作为L2CAP层的callback返回;
在注册位置hidh_conn_reg,我们可以看到原生Android BT中默认支援7个HID Device的连接(宏定义:HID_HOST_MAX_DEVICES),注意:虽然直接连接最多7个HID Device,但其初始化只需一次;
-->如当前收到中断通道Data时,将在API hidh_l2cif_data_ind中执行callback ,对应消息ID 是HID_HDEV_EVT_INTR_DATA(如果是控制通道的DATA指令消息,则evt是
HID_HDEV_EVT_CTRL_DATA);
-->触发Callback对应API bta_hh_cback, 转发发出event BTA_HH_INT_DATA_EVT;
bta_hh_cback in bta_hh_act.cc (system\bt\bta\hh)
通过关联到表示连接上后的“event + action + next state”数组bta_hh_st_connected,得到其对应的Action是“BTA_HH_DATA_ACT”;
/**************************************************************/
延伸问题点:bta_hh_st_connected数组,如何理解并对应到具体API;
当前中断通道收到的data,最终触发event BTA_HH_INT_DATA_EVT,但我们发现event是被包含在数组bta_hh_st_idle、bta_hh_st_w4_conn、bta_hh_st_connected、bta_hh_st_w4_sec当中;
以上数组实际上就是一个状态机,但其不直接对应API,而是通过问询形式得到具体的action, 然后把action值传递给函数数组,如当前的bta_hh_action;
/**************************************************************/
-->通过bta_hh_action 和索引BTA_HH_DATA_ACT,执行到bta_hh_data_act;
-->执行到API bta_hh_data_act,函数内部执行bta_hh_co_data;
从bta_hh_co_data的实现可以看到,在hidh_l2cif_data_ind把data 传给
bta_hh_co_data前,进行了偏移1Byte的动作,原因是:基于HID Spec:所有的HID Message 的第1个Byte都是Header;
-->执行API bta_hh_co_data,此函数的重点是bta_hh_co_write;
-->执行到函数bta_hh_co_write,把收到的中断report data 直接写给了节点"/dev/uhid";
(Note:关于节点"/dev/uhid"部分,后续有更详细的描述);