The author's blog address: http://blog.sina.com.cn/samzhen1977
By Sam (zhufeng) sam_code@hotmail.com
(HCI protocol introduction, HCI
Implementation in bluez and HCI Programming Interface)
1. HCI Layer Protocol Overview:
HCI provides a unified method to access the Bluetooth underlying layer. :
As shown in the figure,Host Controller
Interface (HCI)
Is used to communicate with the host and module. Host is usually a PC,
The module is connected to the Bluetooth dongle on the PC in various physical connection forms (such as USB, serial, and PC-card.
At the host end, protocols such as application, SDP, and L2CAP are all proposed in the form of software (bluez uses the kernel layer program ). In the module
End: Link
Manager, BB, and other protocols are provided by firmware in the hardware.
HCI is special. It is implemented in software and is used to provide access interfaces for upper-layer protocols and programs (in bluez, HCI. c
Hci_usb.c, hci_sock.c, etc.). The other part is also implemented in firmware, which is used to transmit software commands to the underlying layer in a way that is understood by the underlying protocol.
The upper-Layer Program and protocol in the PC and the lower-layer protocol in the modulles communicate through HCI, there are four different forms of transmission:Commands,
Event, ACL data, SCO/ESCO data.
1.1. HCI command:
HCI command is a method in which the host sends commands to modules. The structure of HCI command packet is as follows:
Opcode uniquely identifies the HCI command. It consists of two parts, a 10bit opcode command.
6-bit opcode group.
1.1.1: opcode group:
Linux Kernel (bluez ,~ Opcode is defined in/include/NET/Bluetooth/HCI. h.
Group.
# Define ogf_link_ctl 0x01
# Define
Ogf_link_policy 0x02
# Define ogf_host_ctl 0x03
# Define
Ogf_info_param 0x04
# Define
Ogf_status_param 0x05
They represent different command groups:
Ogf_link_ctl:
Link Control, the command
The command in group allows the host to control connections to other Bluetooth devices.
Ogf_link_policy
: Link
Policy. The command in this command group allows you to adjust the link Manager Control.
Ogf_host_ctl:
Control and baseband.
1.1.2: opcode command:
It is used to uniquely identify commands in the same group .~ /Include/NET/Bluetooth/HCI. h.
1.2: HCI event:
Modules sends some information to the host and uses HCI event. The event packet structure is as follows:
There are three types of HCI events:Command complete event, command states
Event, command subsequently completend.
Command Complete Event
:
If the command sent by the host can have immediate results, such events will be sent. That is to say, if the sent command is only related to the local modules, it is not
When dealing with remote devices, use command
Complete Event. Example: hci_read_buffer_size.
Command states
Event:
If the command sent by the host cannot know the result immediately, this type of event is sent. The Command sent by the host must be
When dealing with remote devices, it is inevitable that the results will not be immediately known, so the command will be sent
States event. Example:
HCI connect.
Command subsequently
Completend:
The command is delayed to complete the event. For example, the connection has been established.
Is a command-event example:
It can be seen from this that if the Command sent by the host is related to the remote device, it will first sendCommand
States event
. And then send
Command subsequently completend.
Hci acl and SCO data are not described here. You only need to understand that L2CAP data is transmitted to remote through ACL
Device.
It clearly shows how L2CAP data is converted to USB data and transmitted to the underlying protocol step by step.
Obviously, an L2CAP packet will first cut multiple HCI packets according to the rules. HCI packets are then transmitted to the USB device through the HCI-USB layer. Each package uses USB
The driver is sent to the underlying layer.
2. HCI
Protocol implementation:
(Add later)
3. HCI Layer programming:
As mentioned in the previous section, HCI is a channel for communication between upper-layer protocols and between programs and underlying hardware protocols. Therefore, commands sent through HCI are sent by upper-layer protocols or applications
Bluetooth
Dongle. What action does it perform by running the Bluetooth dongle command (or the hardware protocol.
3.0: obtain the number of dongles inserted on the host and the dongle information:
Let's first review the concept of socket:
Use the function socket () to create a socket, just as if you have a phone number. BIND () is to map the phone number and a phone number (network address.
Similarly, we can regard the host as a room with multiple phone numbers ).
When you use socket () to open an HCI
The socket of Protocol indicates that the handle of the room is obtained. The host may have multiple dongles. In other words, this room can have multiple phone numbers. Therefore, HCI provides
A set of commands to get these dongles.
//
0. Allocate a space to hci_dev_list_req. All the dongle information is provided here.
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 (struct
Hci_dev_req) + sizeof (uint16_t )))){
Perror ("can't allocate
Memory ");
Exit (1 );
}
DL-> dev_num = hci_max_dev;
Dr = DL-> dev_req;
// 1. Open an HCI socket. This socket is equivalent to a room.
If (CTL = socket (af_bluetooth, sock_raw, btproto_hci ))
<0 ){
Perror ("can't open HCI
Socket .");
Exit (1 );
}
// 2. Use hcigetdevlist to obtain all the donggle devices.
Id. Stored in DL.
If (IOCTL (CTL, hcigetdevlist, (void *) dL)
<0 ){
Perror ("can't get Device
List ");
Exit (1 );
}
// 3 Use hcigetdevinfo to obtain the dongle information corresponding to the device ID.
Di. dev_id = (DR + I)-> dev_id;
IOCTL (CTL, hcigetdevinfo, (void *) & di );
In this way, you can obtain all the dongle information.
Struct hci_dev_info {
Uint16_t
Dev_id; // dongle Device
ID
Char
Name [8]; // dongle name
Bdaddr_t
Bdaddr; // dongle bdaddr
Uint32_t
Flags;
// Dongle flags: for example, up, runing, and down.
Uint8_t
Type; // dongle connection mode: such as USB or PC
Card, UART, RS232, etc.
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; // the data information of This dongle, such as how many ACLs are sent
Packet, correct number, error number, and so on.
};
3.0.1: Up and down Bluetooth dongle:
IOCTL (CTL, hcidevup, hdev)
IOCTL (CTL, hcidevdown, hdev)
CTL: the socket opened with socket (af_bluetooth, sock_raw, btproto_hci.
Hdev: dongle device ID. (so the above socket does not need bind, because it is specified here)
3.1
HCI programming interface 1 provided by bluez (for the local dongle API series ):
3.1. 1 open an HCI socket --- int hci_open_dev (int
Dev_id ):
This function is used to open an HCI socket. It first opens an HCI
Protocol socket (room), and the socket and Device
Id = bind the dongle of the dev_id parameter. Only after bind, It maps the socket handle to the dongle.
Note: before sending all HCI commands, you must use
Hci_open_dev
Open and bind.
3.1.2: close an HCI socket:
Int hci_close_dev (INT dd)
// Close the applicationHci_open_dev
Open socket.
3.1.3: Send To HCI socket (corresponding to a Dongle)
Request:
Int hci_send_req (int dd, struct
Hci_request * r, int)
Bluez provides this function, which enables all hosts to send commands to modules.
Parameter 1: HCI socket.
Parameter 2: Command content.
Parameter 3: timeout in milliseconds.
The following describes the function and usage in detail:
This function is called when the application needs to send a command to the dongle (corresponding to the socket after bind.
Here, parameter 1 dd
Corresponds toHci_open_dev ()
Dozen
Open socket (dongle ).
Parameter 3
The timeout that waits for the dongle to execute and replies to the command result. The unit is millisecond.
Parameter 2: hci_request * R
Most
First, let's look at its structure:
Struct hci_request {
Uint16_t
Ogf; // opcode
Group
Uint16_t
OCF; // opcode
Command
Int
Event; // The Event Type generated by this command.
Void
* Cparam; // Command Parameter
Int
Clen;
// Command parameter length
Void
* Rparam; // response
Parameters
Int
Rlen;
// Response parameter length
};
Ogf and OCF are needless to say. The figure above shows that this is group code and command code. Determine the two items first, and then check HCI
Spec. View the meaning of the input parameters (cparam) and output parameters (rparam. As for their structure and parameter length ~ /Include/Net
/Bluetooth/HCI. H is defined.
As for event. If it is set, it will be set to socket by setsockopt.
Example 1: Get the policy setting of a connection.
HCI
Spec and ~ /Include/NET/Bluetooth/HCI. h can be seen, ogf = ogf_link_policy (0x02 ).
OCF = ocf_read_link_policy (0x0c ).
This command is used to read the policy setting of an ACL connection. Therefore, the input parameter is connected to handle.
The returned parameters include status (command execution is successful) and handle (connection handle ).
Policy (obtained policy value)
This introduces a new question about how to obtain the handle of an ACL connection.
You can use IOCTL hcigetconninfo to get the ACL connection handle.
IOCTL (DD, hcigetconninfo, (unsigned long) Cr );
Connect_handle =
Htobs (Cr-> conn_info-> handle );
The complete process is as follows:
Struct hci_request;
Read_link_policy_cp command_param;
Read_link_policy_rp response_param;
// 1. Get 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. Enter the command input parameter
Command_param.handle = connect_handle;
Hci_request.ogf = ogf_link_policy;
// Command Group 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,)
<0)
{
Perror ("/nhci_send_req ()");
Return-1;
}
// If the status of the returned value is incorrect
If (response_param.status ){
Return-1;
}
// Obtain the current policy
* Policy = response_param.policy;
3.1.4: several basic functions:
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 comparison
3.1.5: Get the specified dongle bdaddr:
Int hci_read_bd_addr (int dd, bdaddr_t * bdaddr, int );
Parameter 1: HCI
Socket, useHci_open_dev ()
The opened socket (dongle ).
Parameter 2: output parameter, where bdaddr is placed.
Parameter 3: timeout in milliseconds.
3.1.6: read/write dongle Name:
Int hci_read_local_name (int dd, int Len, char * Name, int)
Int hci_write_local_name (int dd, const char * Name, int)
Parameter 1: HCI
Socket, useHci_open_dev ()
The opened socket (dongle ).
Parameter 2: read or set name.
Parameter 3: timeout in milliseconds.
Note: The name here is different from the name in hci_dev_info obtained by IOCTL hcigetdevinfo.
3.1.7: Obtain HCI version:
Int hci_read_local_version (int dd, struct hci_version * ver, int
To)
3.1.8: Get the up dongle bdaddr:
Int hci_devba (INT dev_id, bdaddr_t * bdaddr );
Dev_id: dongle device ID.
Bdaddr: output parameter. It specifies that the bdaddr is placed if the dongle is up.
3.1.9: Get dongle info:
Int hci_devinfo (INT dev_id, struct hci_dev_info * di)
Dev_id: dongle device ID.
DI: the dongle information.
-1 is returned if an error occurs.
Note that the function method is exactly the same as that of method 3.0.
3.1.10: Obtain X from hcix:
Int hci_devid (const char * Str)
STR: A string similar to hci0.
If the device ID (x) corresponding to hcix exists and is up. Returns the device
Id.
3.1.11: Obtain the parameter bdaddr is not equal
BdaddrDongle
Device ID:
Int hci_get_route (bdaddr_t * bdaddr)
Find the dongle and find that the dongle bdaddr is not equal to the first dongle of the bdaddr parameter.
Id.
Therefore, if: int hci_get_route (null), the first available dongle device ID is obtained.
3.1.12: Convert bdaddr to a string:
Int ba2str (const bdaddr_t * Ba, char * Str)
3.1.13: Convert the string to bdaddr:
Int str2ba (const char * STR, bdaddr_t * Ba)
3.2
HCI programming interface 2 provided by bluez (for the remote device API series ):
3.2.1 inquiry remote Bluetooth
Device:
Int hci_inquiry (INT dev_id, int Len, int nrsp, const uint8_t
* Lap, inquiry_info ** II, long flags)
Hci_inquiry () is used to command the specified dongle to search for all the Bluetooth
Device. And pass the searched bluetooth device bdaddr back.
Parameter 1: dev_id: Specify the dongle device ID. If this value is less than 0, the first available dongle is used.
Parameter 2: Len: the length of the inquiry time (1.25 seconds for each increase)
Parameter 3: nrsp: Maximum number of searches for this query. If this parameter is set to 0. The value is 255.
Parameter 4: lap part in bdaddr. The default value of this part is 0x9e8b33 in inquiry. null is usually used. It is set automatically.
Parameter 5: II: store the searched Bluetooth
Device. To an address that stores the inquiry_info pointer, it will automatically allocate space. Put the space header address in it.
Parameter 6: Flags: Search for flags. If ireq_cache_flush is used, inquiry is actually returned. Otherwise, the last result may be returned.
The returned value is the number of Bluetooth devices from inquiry.
NOTE: If * II is not allocated by itself, but is allocated by hci_inquiry (), you need to call
Bt_free () to help it release space.
3.2.2: Get the reomte device name of the specified bdaddr:
Int hci_read_remote_name (int dd, const bdaddr_t * bdaddr, int
Len, char * Name, int)
Parameter 1: Socket opened with hci_open_dev.
Parameter 2: bdaddr of the other party.
Parameter 3: Name Length.
Parameter 4: (out) place the name.
Parameter 5: wait time.
3.2.3: Read the signal strength of the connection:
Int hci_read_arg (int dd, uint16_t handle, int8_t * Arg, int
To)
Note that all operations on the connection will have a parameter, handle. this parameter is the connected handle. We have discussed how to get the handle connection.