C application for BLE connection

Hello,

I am developing a C application in a container to establish a connection with a BLE device.

I am using a Verdin IMX8MM Q 2GB WB IT V1.1E module and a Dhalia Carrier Board. The Torizon Core image being used is: ID=torizon NAME=“TorizonCore” VERSION=“6.2.0+build.2 (kirkstone)” VERSION_ID=6.2.0-build.2 PRETTY_NAME=“TorizonCore 6.2.0+build.2 (kirkstone)” DISTRO_CODENAME=“kirkstone” BUILD_ID=“2” ANSI_COLOR=“1;34” VARIANT=“Docker”

I configured the Torizon extension in VSCode with the username set as root, and I installed libbluetooth-dev:arm64 under devpackages, along with its dependencies libbluetooth3 and libc6-dev under extrapackages.

To execute the docker container, I use the command docker run -it --net=host .

To start my application, I followed the guidelines explained in another topic: C/C++ Bluetooth - #7 by rudhi.tx However, it only covers device scanning.

When trying to establish a connection with the BLE device, as shown below:

cCopy code

uint16_t le_config_interval = htobs(0x0004);
uint16_t le_config_window = htobs(0x0004);
uint16_t le_config_initialization_filter = 0;

uint8_t le_config_peer_bdaddr_type = LE_PUBLIC_ADDRESS;
bdaddr_t le_config_bdaddr = info->bdaddr;
uint8_t le_config_own_bdaddr_type = LE_PUBLIC_ADDRESS;

uint16_t le_config_min_interval = htobs(0x000F);
uint16_t le_config_max_interval = htobs(0x000F);
uint16_t le_config_latency = htobs(0x0000);
uint16_t le_config_supervision_timeout = htobs(0xFFFF);
uint16_t le_config_min_ce_length = htobs(0x0000);
uint16_t le_config_max_ce_length = htobs(0x0000);
uint16_t le_config_handle = 0;
int le_config_to = 25000;

ret = hci_le_create_conn(device_desc, le_config_interval, le_config_window, le_config_initialization_filter,
                         le_config_peer_bdaddr_type, le_config_bdaddr, le_config_own_bdaddr_type,
                         le_config_min_interval, le_config_max_interval, le_config_latency,
                         le_config_supervision_timeout, le_config_min_ce_length, le_config_max_ce_length,
                         &le_config_handle, le_config_to);

printf("ret = %d \n", ret);
perror("Could not create connection");

I receive the following return: Could not create connection: Input/output error.

I would like to highlight that I can successfully establish a connection via the Linux terminal using the following commands:

csharpCopy code

bluetoothctl
power on
menu scan
transport le
back
scan on
connect B8:F0:09:8F:7F:B6

Is there anything additional that I should configure in my C application to establish a successful connection?

Hi @AndreiBGLR

Can you try to run the container with the “–priveleged” option? My guess is that this is just a permissions issue that is not handled by the “–net=host” parameter that you have already specified.

Drew

Dear @drew.tx ,

Thank you for getting back to me.

I have already performed this test, but I got the same result.

Is there any other specific configuration that needs to be done?

Thank you very much!

Best regards

Hello @AndreiBGLR,

Is it possible to send your full code, so that I could try to reproduce the issue?

Dear @rudhi.tx

yes, is possible.

My code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
#include <signal.h>
#include <getopt.h>
#include <string.h>

#define LE_SCAN_PASSIVE                 0x00
#define LE_SCAN_ACTIVE                  0x01

/* These LE scan and inquiry parameters were chosen according to LE General
 * Discovery Procedure specification.
 */
#define DISCOV_LE_SCAN_WIN              0x12
#define DISCOV_LE_SCAN_INT              0x12

#define BLE_SCAN_TIMEOUT   4

union U64to8
{
	/* data */
	uint64_t u64data;
	char sdata[8];
	uint8_t u8data[8];
};

union U32to8
{
	/* data */
	uint32_t u32data;
	char sdata[4];
	uint8_t u8data[4];
};

union U16to8
{
	/* data */
	uint16_t u16data;
	char sdata[2];
	uint8_t u8data[2];
};

typedef void (*ble_discovered_device_t)(const char* addr, const char* name);

// We use a mutex to make the BLE connections synchronous
// static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

static int ble_scan_enable(int device_desc);
static int ble_scan_disable(int device_desc);
int address2string(const bdaddr_t *ba, char *str);

int main(int argc, char const *argv[])
{
    inquiry_info *ii = NULL;
    int max_rsp, num_rsp;
    int dev_id, device_desc, len, flags;
    int i;
    char addr[19] = { 0 };  
	char addr_old[19] = { 0 };
	char addr_res[19] = "B8:F0:09:8F:7F:B6"; 
	char addr_conn[19];
    char name[248] = { 0 };
    int r, teste, ret, opt;
	struct hci_filter new_filter;
    socklen_t filter_size;
	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
	u_int8_t len_data, flagIDGateway, rssi;
	union U64to8 xNameDevice;
	union U32to8 xAlarm, xNCycle, xTS;
	union U16to8 xNItem;
	bdaddr_t bdaddr_teste;

	/** Route adapter */
    dev_id = hci_get_route(NULL);
    //dev_id = hci_devid(addr);    
    printf("%d!\n", dev_id);  
    if (dev_id < 0)
    {
        perror("Error: No Bluetooth adapter found.");
        exit(1);
    }
	/** Abertura de socket */                                                                                                                                              
    device_desc = hci_open_dev( dev_id );
    printf("%d\n", device_desc);
    if (dev_id < 0 || device_desc < 0) {
        perror("opening socket");
        exit(1);
    }

	/** Habilita Scan BLE */  
	ret = ble_scan_enable(device_desc);
	if (ret != 0) {
		fprintf(stderr, "ERROR: Scanning fail.\n");
		return 1;
	}

	printf("Filtros ativos \n");
    // new filter to only look for event packets
    hci_filter_clear(&new_filter);
    hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter);
    hci_filter_set_event(EVT_LE_META_EVENT, &new_filter);
    if (setsockopt(device_desc, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0) {
        perror("Error setsockopt");
        exit(1);
    }

	/** Scan BLE */ 
for (size_t i = 0; i < 1; i++){ // Loop
	le_advertising_info *info;
	evt_le_connection_complete *conn;
	le_create_connection_cp *conn_cp;
    evt_le_meta_event *meta;


 	while ((len = read(device_desc, buf, sizeof(buf))) < 0) {
		printf("While: \n");
	}

	ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
	len -= (1 + HCI_EVENT_HDR_SIZE);

	meta = (void *) ptr;
	info = (le_advertising_info *) (meta->data + 1);

	memset(addr, 0, sizeof(addr));

    address2string(&info->bdaddr, addr);

	int xTesteString = (strncmp(addr, addr_res, 17)); // Compara com o MAC buscado

	if(xTesteString == 0){

		/** Printa o advertising*/
		printf("Advertising:");
		for (int k = 0; k < info->length; k++) {
          printf("%x", info->data[k]);
      	}

		//ret   = ble_scan_disable(device_desc);
		// if (ret < 0) {
		// 	printf("ble_scan_disable = %d \n", ret);
		// 	perror("Could not create connection");
		// 	exit(1);
		// }
		printf("Connection ..\n");

		/** Tenta conexão BLE com device */
		uint16_t le_config_interval = htobs(0x08);
		uint16_t le_config_window = htobs(0x08);
		uint16_t le_config_initialization_filter = htobs(0x08);

		uint8_t le_config_peer_bdaddr_type = LE_PUBLIC_ADDRESS;
		bdaddr_t le_config_bdaddr = info->bdaddr;
		uint8_t le_config_own_bdaddr_type = LE_PUBLIC_ADDRESS;

		uint16_t le_config_min_interval = htobs(0x0006);
		uint16_t le_config_max_interval = htobs(0x0010);
		uint16_t le_config_latency = htobs(0x0000);
		uint16_t le_config_supervision_timeout = htobs(0x0FA0);
		uint16_t le_config_min_ce_length = htobs(0x0000);
		uint16_t le_config_max_ce_length = htobs(0x0000);
		uint16_t le_config_handle = 0;
		int le_config_to = 250000;


		ret = hci_le_create_conn(device_desc,le_config_interval,le_config_window,le_config_initialization_filter
								,le_config_peer_bdaddr_type,le_config_bdaddr,le_config_own_bdaddr_type,le_config_min_interval,
								le_config_max_interval,le_config_latency,le_config_supervision_timeout,le_config_min_ce_length,
								le_config_max_ce_length,&le_config_handle,250000);
		//ret = hci_create_connection(device_desc, &info->bdaddr, LE_PUBLIC_ADDRESS, 0, 0x01, &handle, 250000000);
		if (ret < 0) {
			ble_scan_disable(device_desc);
			printf("ret = %d \n", ret);
			perror("Could not create connection");
			exit(1);
		}
		printf("Connection handle %d\n", le_config_handle);

	}else{
		printf("Other\n");
		i--;					// Se for diferente não sai do Loop
	}
}

	/** Scan Off */
	ble_scan_disable(device_desc);

	printf("\n Scan completed \n");

    return 0;
}

static int ble_scan_enable(int device_desc) {
	uint16_t interval = htobs(DISCOV_LE_SCAN_INT);
	uint16_t window = htobs(DISCOV_LE_SCAN_WIN);
	uint8_t own_address_type = 0x00;
	uint8_t filter_policy = 0x00;

	int ret = hci_le_set_scan_parameters(device_desc, LE_SCAN_ACTIVE, interval, window, own_address_type, filter_policy, 10000);
	if (ret < 0) {
		fprintf(stderr, "ERROR: Set scan parameters failed (are you root?).\n");
		return 1;
	}

	ret = hci_le_set_scan_enable(device_desc, 0x01, 1, 10000);
	if (ret < 0) {
		fprintf(stderr, "ERROR: Enable scan failed.\n");
		return 1;
	}

	return 0;
}

static int ble_scan_disable(int device_desc) {
	if (device_desc == -1) {
		fprintf(stderr, "ERROR: Could not disable scan, not enabled yet.\n");
		return 1;
	}

	int result = hci_le_set_scan_enable(device_desc, 0x00, 1, 10000);
	if (result < 0) {
		fprintf(stderr, "ERROR: Disable scan failed.\n");
	}
	return result;
}

int address2string(const bdaddr_t *ba, char *str)
{
  return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
    ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
}

Thank you very much!

I had faced many issues with getting bluetooth to work with this library.

The issue was resolved by @rudhi.tx. C/C++ Bluetooth - #7 by rudhi.tx

Still, in the end, I ended up using d-bus api to setup everything.

Best Regards,
Hassan.

Yeah, generally when there is a DBUS API available it is much more convenient to use that from within a container as you just need to map the DBUS socket into the container and you don’t have to fight too much with permissions. Hopefully @rudhi.tx can get you squared away with the current code though.
Drew

Dear @geopaxpvtltd and @drew.tx, thank you for the suggestions.

@geopaxpvtltd, in the topic described, @rudhi.tx addressed device scanning, and that worked fine. I managed to develop it successfully, including advertising handling. However, I haven’t been successful in establishing connections with devices for data exchange, which is why the new topic emerged.

From what I found in the topic you described, you used the Debian package libsystemd-dev. I have it imported into my application, but I couldn’t find any further details about implementations related to BLE. Do you have any references you relied on or additional tips?

Thank you all for your attention.

@AndreiBGLR You basically need to control the dbus service for org.bluez.

if you google it, you will find many examples on how to setup different bluetooth services using dbus for bluez.

You basically need to define a service, and then advertise it. and implement different methods for handling different bluetooth services.

In order to handle connection and disconnection from inside your app, if you are setting up a server, you will have to define an agent that sets up the credentials for connection.

It is a long topic.