3.3. HCI API

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.

3.3.1. Function set

The HCI API function set divided into two subsets: system (Affix specific) function set and HC (Bluetooth device specific) function set. All an Affix function names have low-case style and all a HC function names have mixed-case style and are starting from HCI_ or __HCI_. The HC 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 prototypeDescription
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_listen_event(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 *hd);Receives HCI event from the HCI devices. Event is stored in the buffer pointed by "event" argument and device id from where event came is stored in variable pointed by "hd".
int hci_exec_cmd(int fd, void *cmd, __u64 mask, int flags, void *event);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_recv_msg(int fd, __u8 *param);Receives Affix internal control message from the channel pointed by "fd" and stores data in the buffer pointed by "param" argument.
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*.
hci_get_attr(char *name, struct hci_dev_attr *attr);Reads device attributes:. name, id, flags.
hci_get_attr_id(int hd, struct hci_dev_attr *attr);Reads device attributes:. name, id, flags.
hci_get_attr_fd(int fd, struct hci_dev_attr *attr);Reads device attributes:. name, id, flags.
hci_get_flags(int fd, int *flags);Reads device flags.
hci_set_flags(int fd, int flags);Sets device flags: HCI_FLAGS_UP
int hci_set_secmode(int fd, int mode);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 packet type.
int hci_set_role(int fd, int role);Set connection roles.
char *hcierror(int err);Returns HCI error message.
char *bda2str(BD_ADDR *bda);Converts Bluetooth address to string.
int str2bda(BD_ADDR *p, char *str);Converts string to Bluetooth address.
The Major HC functions are presented in Table 3-8. All functions accept at least one parameter - hci descriptor and return error code, which can has following values: z,.

General HC function format is: int HCI_Xxxx(int hd, param, param, ...);

The rest of parameters of HC 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 HC functions implemented in the Affix. A complete set can be found in hci_cmds.h.

3.3.2. Data structures

Data structures related to the HCI interface are defined in hci_types.h header.

3.3.3. Sample code

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;
}