GSoC 2024 Qaul: Qaul BLE module for Linux: Part-II

This post is a continuation of my last one, which discussed the theory behind Qaul BLE support for Linux where I explained the theoretical concepts and jargon and high-level system design for Bluetooth low energy flow using GATT. Please refer to that blog before proceeding.

In this blog, we will explore the implementation and low-level design of the BLE support in greater depth.

Introduction

We will begin with creating a GATT server serving two Bluetooth services “main_service” and “msg_service” with their respective UUIDs and characteristics for our qaul device. Then we will use the adapter to advertise the “main_service_uuid” for another qaul device to connect to the GATT server. Afterward, we will create a GATT client by starting a scanning service to discover nearby advertisements. The last thing to do is to set a few functionalities and callbacks like read and write characteristic data methods and request_read and request_write callbacks for characteristics to set a basic GATT prototype with message transfer support.

GATT Server

If you remember the GATT data hierarchy diagram from the last blog shows the GATT server is made up of services and each service is made up of characteristics and each characteristic of descriptors. Here, we will dive into details of how to implement it using BlueR.

GATT Service: GATT services are a set of similar attributes in one common section of the GATT server. For Qaul GATT Server implementation, we have two services – mainService, and msgService and their UUIDs (99xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx23). Below is a struct for Service where you specify uuid, characteristics and whether the service is primary or secondary.

GATT Characteristics: Characteristics are the containers for user data. For the Qaul Gatt Server, we have one characteristic for each service ➖ mainChar, msgChar, and their UUIDs with respective configurations. You can specify the uuid, descriptors(if any), read permission, and callbacks under the read attribute, and write permissions and conditions under the write attribute.

Now, you can create a new session to get an instance of your Bluetooth adapter and start the service GATT application using the above configurations. Below is a sample example of a GATT server with read characteristics functionality enabled.

Advertisements and Device discovery

We will use the above instance of the adapter to start advertising the main_service_uuid to be discovered by other devices. (Refer to sample code).

We can start scanning for nearby devices advertising the same UUID for the presence of qaul. For this, BlueR gives us adapter.set_discovery_filter(get_filter()).await; a feature for filter-based UUID scanning. and stream the discovered device adapter.discover_devices().await.

Till now we have created a Ble GATT server and client, the next thing we will implement is confirming the discovered devices for a qaul node, maintaining a list of discovered devices to save the throughput of scanning devices again and again, and keeping track of devices out of range.

For Qaul ble architecture, we have stored the qaul_id in the main_service’s characteristics, Now, whenever any device discovers this node, it will connect to it, check for the presence of both services along with their characteristics, and mark that qaul_id as discoverable. If the conditions are satisfied, it adds the node and its properties to a lookup map. To keep track of the device’s availability after discovery, Qaul spawns a new task out_of_range_checker to ping recently discovered devices at regular intervals to confirm their presence.

Any message to be sent can be written into msg_service’s characteristics using CharacteristicWriteMethod::Io and receive any write request using CharacteristicControlEvent::Write(write). The message read and write process is a bit more complex than function calls. We will discuss it in more depth in the next blog.

So, in the current blog, we are able to create a GATT server and a GATT client, advertise our UUIDs, and scan for nearby BLE devices. We also learned to identify the correct device and maintain the lookup table for better connectivity and more stability.

Concluding Thoughts

The first half of the GSoC coding period had more code implementation for ble connectivity. The major part was into integrating the prototype to work with async rust on multiple threads. The next half will be implementing loss-less transmission of data and experimenting with bluer for better stability. If you want to know more about my project, please feel free to reach out. Thanks for reading!

GSoC 2024 Qaul: Qaul BLE module for Linux

Abstract

The project aims to create a qaul Ble(Bluetooth low energy) module in Rust for Linux which is compatible with Ble modules for Android and iOS. The module should provide the following functionalities :

  1. BLE discovery and connections: The project should be able to scan other discoverable devices and send BLE advertisements to nearby nodes at regular intervals.
  2. Establish data communication: The connection should be able to exchange messages between qaul nodes.

Plan Of Action

This project aims to establish a BLE connection between Linux and other compatible devices.

BLE GATT Service ➖

  • GATT Server: A GATT server corresponds to an ATT server. It receives requests from clients and sends responses back.
  • GATT Client: A GATT client corresponds to an ATT client. It sends requests to the server and receives responses. After the discovery of the server’s service attributes, it can start reading/writing about attributes found on the server based on permissions provided by the server.

GATT data hierarchy.

Implementation

  • Initiate BLE GATT server  :
    • Initialize the Bluetooth session and activate the Bluetooth adapter.
    • Initiate local Ble GATT server using the bluer crate and set up Bluetooth GATT Services and Characteristics, which become available for remote servers.
  • Initiate BLE GATT client :
    • Initiate advertisement to look for nearby qaul nodes with specified service UUID and characteristic UUID.
    • Connect to discovered devices and send RPC messages to libqaul.
  • Establish communication between devices :
    • On receiving the message.DirectSend request from the libqaul. Write the data into the characteristic.value if the service.UUID() and characteristic.UUID() is compatible with other qaul devices.
    • Create a message listener and forward the characteristic value passed in the event to libqaul to be serialized as protobufs and displayed to the user.
Qaul BLE communication architecture

Deliverables :

  • Creating a stable working ble_module for Linux including fixing, and testing the current prototype.
  • Establish communication of the ble_module with libqaul.
  • Make sure the Linux Bluetooth code is interoperable with Android and iOS Bluetooth modules.
  • Try to optimize the Bluetooth module for better stability and connection.

Concluding Thoughts:

I have always been inspired by the idea of a world built on free and decentralized architecture. When I read the project’s description, I felt motivated to join a community dedicated to achieving borderless, decentralized communication that rivals established centralized applications.

I would like to thank my mentors, Mathias Jud and Brenodt, for guiding me through the project and helping me understand the internal workings of the applications. I am eager to contribute to the project with great enthusiasm.