Skip to content
Advertisement

How to connect BLE devices using Linux bluetooth C library

  1. Description of the problem

I am trying to connect my Bluetooth devices with BLE to a Linux system using the Bluetooth C libraries (I am programming using C++), so here is the code I am currently using:

#include <string>
#include <iostream>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

#define CONNECT_TIMEOUT     60 /* sec */
#define BLE_ERROR(e) std::cout << "Error: " << e << ": " << strerror(errno) << std::endl;

void connect(std::string addr){
    uint16_t handle = 0;
    uint8_t initiator_filter = 0;
    uint8_t peer_type = LE_PUBLIC_ADDRESS;
    uint8_t own_type = LE_PUBLIC_ADDRESS;
    uint16_t interval = htobs(0x0005);
    uint16_t window = htobs(0x0005);

    uint16_t min_interval = 15;
    uint16_t max_interval = 15;

    uint16_t latency = 0;
    uint16_t timeout = 0;

    uint16_t min_ce_length = 1;
    uint16_t max_ce_length = 1;

    bdaddr_t bdaddr;

    int r, dev_id, dd = -1;

    dev_id = hci_get_route(NULL);
    if (dev_id < 0)
    {
        BLE_ERROR("No local device");
        goto finish;
    }
    dd = hci_open_dev(dev_id);
    if (dd < 0)
    {
        BLE_ERROR("Cannot open socket");
        goto finish;
    }

    r = str2ba(addr.c_str(), &bdaddr);
    if(r < 0){
        BLE_ERROR("Getting baddr");
        goto finish;
    }   

    r = hci_le_create_conn(dd,interval,window,initiator_filter,peer_type,
            bdaddr,own_type,min_interval,max_interval,latency,timeout,min_ce_length,max_ce_length,
            &handle,CONNECT_TIMEOUT * 1000000);
    if(r < 0){
        BLE_ERROR("Connecting device");
        goto finish;
    }

    printf("tHandle: %d (0x%04x)n", handle, handle);

finish:
    hci_close_dev(dd);
}

int main(){

    connect(""); //TODO Complete with a functional MAC Address

    return 0;
}

NOTE: You need to set a specific MAC in connect function parameter. I am also compiling with g++ using the following command:

/usr/bin/g++ -g /home/maria/projects/TestStackOverBLE/main.cpp -o /home/maria/projects/TestStackOverBLE/main -lbluetooth

Here are more information about my hci0 device using hciconfig -a command:

hci0:   Type: Primary  Bus: USB
    BD Address: 24:4B:FE:3A:1A:B6  ACL MTU: 1021:6  SCO MTU: 255:12
    UP RUNNING PSCAN 
    RX bytes:141559 acl:0 sco:0 events:5409 errors:0
    TX bytes:59986 acl:0 sco:0 commands:2084 errors:0
    Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
    Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
    Link policy: RSWITCH HOLD SNIFF PARK 
    Link mode: SLAVE ACCEPT 
    Name: 'maria'
    Class: 0x3c010c
    Service Classes: Rendering, Capturing, Object Transfer, Audio
    Device Class: Computer, Laptop
    HCI Version:  (0xa)  Revision: 0x999
    LMP Version:  (0xa)  Subversion: 0x646b
    Manufacturer: Realtek Semiconductor Corporation (93)

I am also using Ubuntu 18.04 with:

bluetoothctl v5.64

dbus v1.12.2-1ubuntu1

bluez v5.48-0ubuntu3.

And the result I am getting when I run the application is the following:

Error: Connecting device: Input/output error
  1. Solution attempts

I first tried to document myself about how the bluetooth C libraries for Linux works (itis difficult to find any documentation and less for BLE), I need to connect using BLE since my device does not allow communication using Bluetooth classic and I cannot find the reason for the problem I am having. I also have tried to restart both the bluetooth service (using sudo service bluetooth restart) and the hci0 device (using sudo hciconfig hci0 reset) several times but none worked, I also tried restarting the PC and neither, I even tried the steps mentioned here that are quite similar to my case since previously the “Connection timeout” error has also happened to me but it didn’t work either, it just returned the following code in case it was useful: Executing this command: hcitool cmd 0x08 0x000EI received the following output:

< HCI Command: ogf 0x08, ocf 0x000e, plen 0
> HCI Event: 0x0e plen 4
  02 0E 20 0C

What can I do about this problem?

EDIT: I was researching and found that making dbus calls to the bluetooth service using C/C++ could work for me but it is quite difficult to find good documentation or concrete connection examples despite having reviewed lots of github projects as most of the code is too convoluted, included in many files and/or consecutive calls for what I am trying to find/understand

Advertisement

Answer

This is what the old hci_xxx bluetooth C functions are doing at the lowest level. They probably don’t work now because bluez/dbus is getting in the way. The following code works on a Raspberry Pi because it disables bluez first, and could be the basis of a C program – but it would be much easier to use one of the github libraries mentioned in the comments.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

struct sockaddr_hci
  {
  unsigned short hci_family;
  unsigned short hci_dev;      
  unsigned short hci_channel;
  };

  
struct hci_filter
  {
  unsigned long type_mask;
  unsigned long event_mask[2];
  unsigned short opcode;
  };

#define BTPROTO_HCI 1
#define SOL_HCI 0
#define HCI_FILTER 2
#define HCIDEVDOWN 0x400448CA

unsigned char eventmask[16] =  { 1,1,0x0C,8,0xFF,0xFF,0xFB,0xFF,0x07,0xF8,0xBF,0x3D }; 
unsigned char lemask[16] = { 0x01,0x01,0x20,0x08,0xBF,0x05,0,0,0,0,0,0 };
unsigned char leopen[30] = {1,0x0D,0x20,0x19,0x60,0,0x60,0,0,0,0x66,0x55,0x44,0x33,0x22,0x11,0,0x18,0,0x28,0,0,0,0x11,0x01,0,0,0,0}; 


int main()
  {
  int n,len,dd;
  struct sockaddr_hci sa;
  struct hci_filter flt;
  char buf[256];
  
  // set board address 00:1E:C0:2D:17:7C
  leopen[15] = 0x00;
  leopen[14] = 0x1E;
  leopen[13] = 0xC0;
  leopen[12] = 0x2D;
  leopen[11] = 0x17;
  leopen[10] = 0x7C;
  
  dd = socket(31, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);

  if(dd < 0)
    {
    printf("Socket open errorn");
    return(0);
    }
        
  ioctl(dd,HCIDEVDOWN,0);  // hci0
  close(dd); 
 
     
   // AF_BLUETOOTH=31
  dd = socket(31, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);

  if(dd < 0)
    {
    printf("Socket open errorn");
    return(0);
    }


  sa.hci_family = 31;   // AF_BLUETOOTH;
  sa.hci_dev = 0;       // hci0/1/2...
  sa.hci_channel = 1;   // HCI_CHANNEL_USER    
  
  if(bind(dd,(struct sockaddr *)&sa,sizeof(sa)) < 0)
    {
    printf("Bind failedn");
    close(dd);
    return(0);
    }



  write(dd,eventmask,12);
  write(dd,lemask,12);  

  printf("Send hci LE connectn"); 
  write(dd,leopen,29);
  
  printf("If get reply = 04 3E 13 01 00.. then has connected OKn");  
  printf("REPLY =");
  for(n = 0 ; n < 10 ; ++ n)
    {
    len = read(dd,buf,sizeof(buf));
    for(n = 0 ; n < len ; ++n)
      printf(" %02X",buf[n]);
    printf("n");
    sleep(1);
    }
  printf("nExit and disconnectn");
  }



User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement