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 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 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_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.
The Major HCI functions are presented in Table 3-8. All functions accept at least one parameter - HCI descriptor and return an error code, which can has following 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

FunctionDescription
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.

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