Affix - Technical Documentation: Affix - Open Source Bluetooth Protocol Stack for Linux | ||
---|---|---|
Prev | Chapter 3. Application Programming Interface | Next |
The HCI API allows user to perform low level control of Bluetooth devices, to set it up into different modes of operation, to discover other Bluetooth devices in the radio range, and so forth. There are almost no cases when HCI functions are unused. The most common task is to make a discovery to find what devices are around.
The main notion in the HCI API is a HCI descriptor, which in fact is a Unix file descriptor. The HCI descriptor is used in many functions to specify device used with a calling function.
The HCI API function set divided into two subsets: system (Affix specific) function set and HCI (Bluetooth device specific) function set. All Affix function names have low-case style and all a HCI function names have mixed-case style and are starting from HCI_ or __HCI_. The HCI functions are implemented according to the Bluetooth System Specification [BTSPEC].
The Affix system function set is presented in Table 3-7.
Table 3-7. HCI API function set
function prototype | Description |
---|---|
int hci_open(char *name); | Opens device "by name" and returns HCI descriptor. |
int hci_open_id(int hd); | Opens device "by id" and returns HCI descriptor. |
int hci_get_devs(int *devs); | Stores HCI descriptors of registered Bluetooth devices in the system in the *devs* and returns its number. |
int hci_open_event(void); | Opens a channel used to receive HCI events from any device and returns HCI descriptor. |
int hci_event_mask(int fd, __u64 mask); | Sets event mask for specified device and enable event receiving of matched type. Mask value zero disable events receiving. |
int hci_recv_event(int fd, void *event, int size, long timeout); | Receives HCI event from the HCI devices. Event is stored in the buffer pointed by "event" argument. |
int hci_exec_cmd(int fd, __u16 opcode, void *cmd, int len, __u64 mask, int flags, void *event, int elen); | Sends HCI commands pointed by "cmd" to the device pointed by "fd", waits for the COMMAND_STATUS or COMMAND_COMPLETE event and stores it in the buffer pointed by "event". "mask" argument defines events (mask) to receive. |
int hci_open_mgr(void); | Opens Affix internal control channel an returns descriptor. |
int hci_add_pin(BD_ADDR *bda, int Length, __u8 *Code); | Stores a pin code in the Affix control block. It is used in the case of it will be required. It's used by non-interactive applications. This pin code is used to authenticate device *bda*. |
int hci_remove_pin(BD_ADDR *bda); | Removes pin code from the Affix control block. |
int hci_add_key(BD_ADDR *bda, __u8 key_type, __u8 *key); | Stores a link key in the Affix control block. It's used if application stores link key for later use. Link key is used to authenticate device *bda*. |
int hci_remove_key(BD_ADDR *bda); | Removes link key from Affix control block. |
int hci_set_mode(int fd, int mode); | Sets functional mode of Affix kernel core (mode: AFFIX_MODE_PIN - caller handles PIN, AFFIX_MODE_KEY - caller handles key). |
int hci_get_conn(int fd, BD_ADDR *bda); | Retrieves handle of HCI ACL/SCO connection to device *bda*. |
int hci_get_attr(char *name, struct hci_dev_attr *attr); | Reads device attributes: name, id, flags. |
int hci_get_attr_id(int hd, struct hci_dev_attr *attr); | Reads device attributes: name, id, flags. |
int hci_get_attr_fd(int fd, struct hci_dev_attr *attr); | Reads device attributes: name, id, flags. |
int hci_set_attr(int fd, struct hci_dev_attr *attr) | Set device attributes for opened device which handle is *fd*. |
int hci_get_flags_id(int devnum, int *flags); | Reads device flags. Argument devnum identifies the device. |
int hci_set_secmode(int fd, int secmode); | Sets security mode: HCI_SECURITY_OPEN, HCI_SECURITY_LINK, HCI_SECURITY_AUTH, HCI_SECURITY_AUTHOR). This modes can bitwise-or'd. |
int hci_set_pkttype(int fd, int pkt_type); | Sets the accepted packet types. |
int hci_get_pkttype(int fd, int *pkt_type); | Get the accepted packet types. |
int hci_set_role(int fd, int role); | Set connection roles. |
char *hcierror(int err); | Returns HCI error message. |
int hci_ioctl(int cmd, void *arg); | Control the Bluetooth device. See BTIOC_ command in bluetooth.h |
int hci_open_uart(char *name, int type, int proto, int speed, int flags); | Attach a serial Bluetooth device of type "type". |
int hci_close_uart(char *name); | Detach a serial bluetooth device. |
int hci_setup_uart(char *name, int proto, int speed, int flags); | Sets a serial Bluetooth device up. |
int hci_devnum(char *name); | Get the device number for Bluetooth device in the given interface. Argument "name" is the interface. E.g. "bt0". |
int hci_get_bda_id(int devnum, BD_ADDR *bda); | Get the Bluetooth address for a device number *devnum* |
int hci_start_dev(int fd); | Starts the Bluetooth device wiht handle *fd*. |
int hci_stop_dev(int fd); | Stop the bluetooth device with handle *fd*. |
int hci_set_dbmask(__u32 dbmask); | Set the debug mask. See the possible values in btcore.c file. Defines which debug messagas are printed. |
int hci_get_dbmask(__u32 *dbmask); | Get the current debug mask. |
int hci_get_version(int fd, struct affix_version *ver) | Not implemented |
int hci_disconnect(struct sockaddr_affix *sa) | Disconnect from a device. |
int hci_getmtu(int fd) | Get the socket's maximum transfer unit |
char *bda2str(BD_ADDR *bda); | Converts Bluetooth address to string. |
int str2bda(BD_ADDR *p, char *str); | Converts string to Bluetooth address. |
Zero (0) if no error occurred
-1 in a case of system error, and errno is set appropriately. (like any Linux system call does)
Above zero (>0) in a case of HCI error (see Bluetooth Specification for values)
General HCI function format is: int HCI_Xxxx(int hd, param, param, ...);
The rest of parameters of HCI functions depend on actual function and is defined according to Bluetooth Specification. Its description can be carefully read from there.
The following table presents only partial set of HCI functions implemented in the Affix. A complete set can be found in hci_cmds.h.
Table 3-8. HCI function set
Function | Description |
---|---|
int HCI_Inquiry(int fd, __u8 Inquiry_Length, __u8 Max_Num_Responses, INQUIRY_ITEM *Items, __u8 *Num_Responses) | Performs INQUIRY during (1.28 * Inquiry_Length) sec. and stores found Bluetooth devices info in *Items* array and number of found devices in *Num_Responses*. |
int HCI_WriteScanEnable(int fd, __u8 Scan_Enable); | Sets SCAN mode (SCAN_OFF, SCAN_INQUIRY, SCAN_PAGE, SCAN_BOTH). |
int HCI_WriteClassOfDevice(int fd, __u32 Class_of_Device); | Sets a Class of Device. |
int HCI_ChangeLocalName(int fd, char *Name); | Sets a device name. All remote devices will see this name. |
int HCI_WriteAuthenticationEnable(int fd, __u8 Authentication_Enable); | Enables authentication. |
int HCI_WriteEncryptionMode(int fd, __u8 Encryption_Mode); | Sets encryption mode for ACL connections: EM_NO, EM_PP (point-to-point), EM_ALL (pp and broadcast). |
int HCI_ReadBDAddr(int fd, BD_ADDR *bda); | Reads address from device. |
int HCI_WritePageTimeout(int fd, __u16 Page_Timeout); | Sets page timeout. |
int HCI_WriteLinkPolicy(int fd, CHANDLE Connection_Handle, __u8 Link_Policy_Settings); | Sets Link Policy. |
Data structures related to the HCI interface are defined in hci_types.h header.
struct sockaddr_affix. See definition in chapter Section 3.2.1.
INQUIRY_ITEM
typedef struct { BD_ADDR bda; __u8 PS_Repetition_Mode; __u8 PS_Period_Mode; __u8 PS_Mode; __u32 Class_of_Device:24; __u16 Clock_Offset; }__PACK__ INQUIRY_ITEM;
struct hci_dev_attr.
/* flags mask */ #define HCI_FLAGS_UP 0x00000002 #define HCI_FLAGS_ROLE 0x000000F0 #define HCI_ROLE_ALLOW_SWITCH 0x00000000 #define HCI_ROLE_DENY_SWITCH 0x00000010 #define HCI_ROLE_REMAIN_SLAVE 0x00000000 #define HCI_ROLE_BECOME_MASTER 0x00000020 /* Security mode flags */ #define HCI_FLAGS_SECURITY 0x0000FF00 #define HCI_SECURITY_OPEN 0x00000100 #define HCI_SECURITY_SERVICE 0x00000200 #define HCI_SECURITY_LINK 0x00000400 #define HCI_SECURITY_PAIRABLE 0x00000800 /* Security levels */ #define HCI_SECURITY_AUTH 0x00001000 #define HCI_SECURITY_ENCRYPT 0x00002000 #define HCI_SECURITY_AUTHOR 0x00004000 #define HCI_SECURITY_OUT_AUTH 0x00100000 #define HCI_SECURITY_OUT_ENCRYPT 0x00200000 #define HCI_SECURITY_OUT_AUTHOR 0x00400000 #define HCI_SECURITY_CL 0x00800000 /* connection less traffic */ struct hci_dev_attr { int devnum; char name[IFNAMSIZ]; BD_ADDR bda; int flags; int pkt_type; struct hcidev_stats stats; };
struct hci_msg_hdr.
#define MGR_STATE_CHANGE 0x01 struct hci_msg_hdr { int opcode; int length; };
struct hci_state_change.
/* hci device events */ #define HCIDEV_UP 0x0001 #define HCIDEV_DOWN 0x0002 #define HCIDEV_CHANGE 0x0004 #define HCIDEV_REGISTER 0x0005 #define HCIDEV_UNREGISTER 0x0006 #define HCIDEV_ATTACH 0x0100 #define HCIDEV_DETACH 0x0200 struct hci_state_change { struct hci_msg_hdr hdr; int devnum; int event; };
Here is an example of the HCI API usage.
int main(int argc, char *argv[]) { int devs[16], num, i, err; num = hci_get_devs(devs); if (num < 0) { printf("unable to get device list\n"); return -1; } if (num == 0) { printf("No Bluetooth Adapters found\n"); return 0; } for (i = 0; i < num; i++) { fd = _hci_open_id(devs[i]); if (fd < 0) { printf("Unable to open Bluetooth device: %d\n\n", devs[i]); return -1; } err = hci_get_attr(fd, &da); if (err < 0) { printf("Unable to get attribute for: %d\n", devs[i]); return -1; } printf("%s\t%s\n", da.name, bda2str(&da.bda)); if (!(da.state & HCI_STATE_UP)) { printf("\tDevice is down"); continue; } err = HCI_WriteScanEnable(fd, 0x02); if (err) { printf("unable to set scan mode\n"); return -1; } }
Next example illustrates how to discover surrounding devices.
int main(int argc, char *argv[]) { int fd, i, argind = 1; __u32 length; int err; INQUIRY_ITEM devs[20]; char *devnames[20]; char namebuf[248]; __u8 num; if (argv[argind]) { sscanf(argv[argind], "%x", &length); } else length = 8; fd = hci_open("bt0"); if (fd < 0) { printf("Unable to open device %s: %s\n", btdev, sys_errlist[errno]); return -1; } printf("Searching %d sec ...\n", length); err = HCI_Inquiry(fd, length, 20, devs, &num); print_hci_error(err); if (num == 0) { printf("done.\nNo devices found.\n"); return 0; } printf("Searching done. Resolving names ...\n"); for (i = 0; i < num; i++) { err = HCI_RemoteNameRequest(fd, &devs[i], namebuf); if (!err) devnames[i] = strdup(namebuf); else devnames[i] = NULL; } printf("done.\n"); for (i = 0; i < num; i++) { printf("%d, bda: %s, name: %s\n", i, bda2str(&devs[i].bda), devnames[i]); if (devnames[i]) free(devnames[i]); } return 0; }