1. HCI Layer Protocol Overview:
Host Controller Interface (HCI) is used to communicate the host and module. Host is usually pc,module is connected to a Bluetooth Dongle on the PC in various physical connection forms (Usb,serial,pc-card, etc.). At the end of the host: Application,sdp,l2cap and other protocols are presented in the form of software (BlueZ in the kernel layer program). At this end of the module: Link Manager, BB, and so on, are all available in hardware firmware. And HCI is very special, it is part of the software implementation, to provide access to the upper layer protocol and Program Interface (BlueZ, hci.chci_usb.c,hci_ SOCK.C, etc.). The other part is also implemented in firmware, which is used to pass the instructions of the software part to the bottom layer in a way that is understood by the underlying protocol. There are 4 different forms of transmission between the upper-level programs and protocols of the PC and the lower-level protocols residing in modules through HCI: commands,event, ACL data, Sco/esco data.
1.1. HCI Command:
The HCI command is a way for host to send commands to modules. The opcode is used to uniquely identify the HCI command. It consists of 2 parts, 10bit opcode command. OpCode Group of 6bit.
1.1.1:opcode Group:
In Linux Kernel (BlueZ), opcode Group is defined in ~/include/net/bluetooth/hci.h.
#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 Group:
Ogf_link_ctl:link control, the command in this command group allows host to control connections to other Bluetooth device. 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:
Used to uniquely identify the command within the same group. Defined in ~/include/net/bluetooth/hci.h.
1.2:HCI Event:
HCI event is divided into 3 types: Command Complete event, command states Event,command subsequently Completend.command complete event: If host sends Sent command can have the result immediately, it will send this kind of event. That is, if the command sent is only relevant to the local modules and does not deal with the remote device, the command complete Event is used. For example: Hci_read_buffer_size.command states event: If the Command sent by the host does not immediately know the result, send such an event. The command execution sent by host is bound to deal with the remote device, and the result is not immediately known, so the command states Event is sent. For example: HCI Connect. Command subsequently Completend:command postponed completion of the event. For example, the connection is established. As can be seen here, if the command sent by host is related to remote device, the command states Event will be sent first. And so the action is really finished, and then send Command subsequently completend. HCI ACL with SCO data, here is not much to say. Just understand that L2CAP data is transmitted to remote device via ACL. It is clear that a L2CAP package will be cut into several HCI packets first according to the rules. The HCI packet is then passed to the USB device through the HCI-USB layer. Each package is then sent to the bottom through a USB driver.
2. The implementation of HCI protocol:
(Add later)
3. Programming of the HCI layer:
As mentioned in the previous section, HCI is a channel for communicating upper-level protocols and programs to the underlying hardware protocol. Therefore, the command sent through HCI is the upper layer protocol or the application is sent to the Bluetooth dongle. It commands what action the Bluetooth Dongle (or hardware protocol) does.
The concept of socket:
Use the function socket () to create a socket, just as you have a phone. bind () corresponds to a phone number (network address). Similarly, we can interpret host as a room with multiple telephones (Dongle). When using the socket () to open an HCI protocol socket, it indicates that the handle to the room is obtained. Host may have more than one dongle. In other words, this room can have multiple phone numbers. So HCI will provide a set of instructions to get these dongle.
1. Allocate a space to hci_dev_list_req. This will put all the dongle information.
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;
2. 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);
}
3. Use Hcigetdevlist to get all the dongle device IDs. stored in the DL.
if (IOCTL (CTL, hcigetdevlist, (void *) DL) < 0) {
Perror ("Can ' t get device List");
Exit (1);
}
3 use Hcigetdevinfo to get dongle information for the corresponding device ID.
di.dev_id = (dr+i)->dev_id;
IOCTL (CTL, Hcigetdevinfo, (void *) &di);
This will give you 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: such as: Up,runing,down.
uint8_t type; Dongle connection method: such as usb,pc card,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; This dongle data information, such as how many ACL Packet to send, how much correct, how many errors, and so on.
};
3.0.1:up and down Bluetooth Dongle:
IOCTL (CTL, Hcidevup, Hdev)
IOCTL (CTL, Hcidevdown, Hdev)
CTL: The Socket.hdev:Dongle Device ID that is opened for use with sockets (Af_bluetooth, Sock_raw, BTPROTO_HCI). (so the socket above does not need bind, because it is specified here)
3.1 BlueZ provides HCI programming interface one (for 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 binds the socket to the dongle of the device id= parameter dev_id. Only bind, it corresponds to the socket handle to dongle. Note that all HCI command needs to be opened and bound using Hci_open_dev before it is sent.
3.1.2: Close an HCI Socket:
int Hci_close_dev (int dd)//simply close the socket opened with Hci_open_dev.
3.1.3: Send request to the HCI Socket (corresponding to a dongle):
int hci_send_req (int dd, struct hci_request *r, int to)
BlueZ provides this function is very useful, it can achieve all the host to modules to send command functions.
PARAM1:HCI Socket.
Param2:command content.
PARAM3: Timeout in milliseconds.
This function and usage are explained in detail below:
This function is called when the application needs to send a command to Dongle (which corresponds to a socket after bind). Wherein, the parameter one DD corresponds to a socket (Dongle) opened with Hci_open_dev (). The parameter three to is a timeout waiting for dongle to execute and reply to the command result. in milliseconds. Parameter Two Hci_request * R is the most important, first look at its structure:
struct Hci_request {
uint16_t OGF; Opcode Group
uint16_t OCF; Opcode Command
int event; The type of event generated by this command.
void *cparam; Command parameter
int Clen; Command parameter length
void *rparam; Response parameters
int Rlen; Response parameter length
};
OGF,OCF do not need to say more, corresponding to the previous diagram to understand that this is group code and Command code. These two items are determined first, and then the HCI Spec can be checked. Look at the input parameters (Cparam) and the meaning of the output parameters (Rparam). As for their structure and parameter lengths, they are defined in ~/include/net/bluetooth/hci.h. As for the event. If set, it will be setsockopt set to the socket.
Example 1: Get the policy Setting for a connection.
Both HCI spec and ~/include/net/bluetooth/hci.h can be seen in Ogf=ogf_link_policy (0x02).
Ocf=ocf_read_link_policy (0x0C).
Because this command is used to read the policy Setting for an ACL connection. So the input parameter is handle for this connection. The return parameter contains 3 parts, status (command is executed successfully), handle (connection handle). Policy (the resulting policy value), which introduces a new problem, how to get the handle of an ACL connection. You can use the IOCTL hcigetconninfo to get an ACL connection handle.
IOCTL (DD, Hcigetconninfo, (unsigned long) CR);
Connect_handle = Htobs (Cr->conn_info->handle);
So the complete process is as follows:
struct Hci_request 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. Fill in the command input parameters
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, to) < 0)
{
Perror ("\nhci_send_req ()");
return-1;
}
If the return value is not in the correct state
if (response_param.status) {
return-1;
}
Get current policy
*policy = Response_param.policy;
3.1.4: Several more basic 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 comparison
3.1.5: Gets the specified dongle bdaddr:
int hci_read_bd_addr (int dd, bdaddr_t *bdaddr, int to);
PARAM1:HCI socket, use Hci_open_dev () to open the socket (Dongle).
PARAM2: Output parameter, where bdaddr is placed.
PARAM3: Timeout in milliseconds.
3.1.6: Read-write 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)
PARAM1:HCI socket, use Hci_open_dev () to open the socket (Dongle).
PARAM2: Reads or sets the name.
PARAM3: Timeout in milliseconds.
Note: This name differs from the IOCTL hcigetdevinfo in Hci_dev_info.
3.1.7: Get 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, specify dongle if up, then place its bdaddr.
3.1.9: Get dongle Info:
int hci_devinfo (int dev_id, struct hci_dev_info *di)
Dev_id:dongle Device ID.
DI: This dongle information.
Error returns-1.
Note that this function is exactly the same as the 3.0 approach.
3.1.10: Get x from Hcix:
int Hci_devid (const char *STR)
STR: A string similar to Hci0.
If the HCIX corresponding device ID (X) is present and up. This device ID is returned.
3.1.11: Get dongle Device ID bdaddr not equal to parameter bdaddr:
int Hci_get_route (bdaddr_t *bdaddr)
Find dongle, dongle bdaddr is not equal to the first dongle of the parameter bdaddr, this dongle Device ID is returned. 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: Converts the self-string to bdaddr:
int str2ba (const char *STR, bdaddr_t *ba)
HCI programming Interface II provided by 3.2 BlueZ (API series for remote device):
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 all surrounding Bluetooth device. and pass the search to the Bluetooth device bdaddr back.
Parameter 1:dev_id: Specifies the dongle Device ID. If this value is less than 0, the first available dongle is used.
Parameter 2:len: The length of time of this inquiry (increase by 1.25 seconds for each additional 1)
Parameter 3:NRSP: The maximum number of searches for this search, if given 0. This value will take 255.
Parameter 4:lap:bdaddr in the Lap section, inquiry when this value defaults to 0x9e8b33. Null is usually used. is set automatically.
Parameter 5:ii: Place to search for Bluetooth device. To an address that holds the Inquiry_info pointer, it automatically allocates space. And put that space head address in it.
Parameter 6:flags: Search flags. Using Ireq_cache_flush, you will really inquiry again. Otherwise, the last result may be passed back. The return value is the number of Bluetooth Device inquiry to this time.
Note: If the *II is not assigned by itself, but instead lets Hci_inquiry () assign it yourself, you need to call Bt_free () to help it free up space.
3.2.2: Gets the Reomte device Name for the specified bdaddr:
int hci_read_remote_name (int dd, const bdaddr_t *BDADDR, int len, char *name, int to)
Parameter 1: Use Hci_open_dev () to open the socket.
Parameter 2: The other side bdaddr.
Parameter 3:name length.
Parameter 4: (out) place name.
Parameter 5: Wait time.
3.2.3: The signal strength of the Read connection:
int Hci_read_rssi (int dd, uint16_t handle, int8_t *rssi, int to)
Note that all operations on the connection will have a parameter, handle. This parameter is the handle of the connection. I've talked about how to get the connection handle.
BLUETOOTH:HCI Layer Programming