- 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
- 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 0x000E
I 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"); }