Skip to content
Shiny.NET
GitHubTwitter
Blog

GATT Service

Peripheral Manager (GATT Server)

This allows you to accept client connections

Each OS has different limitations and functions

On iOS - you need to advertise as well as create a gatt server

Services

Services are nothing more than categories in the overall perspective of BluetoothLE. You should be aware that you must setup all characters & descriptors that belong to a service BEFORE starting advertising or adding a service to a running server!

You should always know your service UUID for future client consumption!

From a functionality perspective, there is not a lot you do with services

General Setup

After creating your server instance and a service, you can do the following:

You should always assign a known GUID ID to your characteristic in order for your GATT service to be consumed by a client.

Below are examples of a basic read/write characteristic and a notification characteristic setup

var service = CrossBleAdapter.Current.AddService(new Guid(...));

var characteristic = service.AddCharacteristic(
    Guid.NewGuid(),
    CharacteristicProperties.Read | CharacteristicProperties.Write | CharacteristicProperties.WriteWithoutResponse,
    GattPermissions.Read | GattPermissions.Write
);

var notifyCharacteristic = service.AddCharacteristic
(
    Guid.NewGuid(),
    CharacteristicProperties.Indicate | CharacteristicProperties.Notify,
    GattPermissions.Read | GattPermissions.Write
);

Setup a Service

These are the heart and soul of BLE. This is where data is exchanged between client & server

 await hostingManager.AddService(
    "Your Service UUID",
    true,
    sb =>
    {
        byte[]? currentData = null;

        var notifier = sb.AddCharacteristic("Your NotifyCharacteristicUuid" , x => x.SetNotification(sub =>
        {
            var smsg = sub.IsSubscribing ? "Subscribed" : "UnSubscribed";
            this.Log($"{sub.Peripheral.Uuid} {smsg} to Characteristic");

            return Task.CompletedTask;
        }));

        sb.AddCharacteristic(BleConfiguration.ReadCharacteristicUuid, x => x.SetRead(request =>
        {
            var data = currentData ?? new byte[] { 0x0 };
            this.Log($"{request.Peripheral.Uuid} Read Characteristic", data);

            return Task.FromResult(GattResult.Success(data));
        }));

        sb.AddCharacteristic(BleConfiguration.WriteCharacteristicUuid, cb => cb.SetWrite(async request =>
        {
            currentData = request.Data;
            this.Log($"{request.Peripheral.Uuid} Wrote to Characteristic", request.Data);

            if (notifier.SubscribedCentrals.Count > 0)
            {
                await notifier.Notify(request.Data);
                this.Log("Notification Broadcasted to subscribers");
            }
        }, WriteOptions.Write | WriteOptions.WriteWithoutResponse));
    }
);

Managed Characteristic

A managed characteristic as shown below, respresents a single characteristic but multiple operations

[BleGattCharacteristic("Your Service UUID", "Your Characteristic UUID")]
public class MyManagedCharacteristics : BleGattCharacteristic
{
    readonly SampleSqliteConnection conn;

    public MyManagedCharacteristics(SampleSqliteConnection conn)
        => this.conn = conn;

    // setup any initial wiring before the characteristic is started
    public override Task OnStart()
    {
        return Task.Completed;
    }

    // cleanup any resources/timers/etc you may have had running
    public override void OnStop() => base.OnStop();

    // override this to make your characteristic readable
    public override Task<GattResult> OnRead(ReadRequest request) => base.OnRead(request);

    // override this to make your characteristic writeable
    public override Task OnWrite(WriteRequest request) => base.OnWrite(request);

    // override this to make your characteristic notify based
    public override Task OnSubscriptionChanged(IPeripheral peripheral, bool subscribed) => base.OnSubscriptionChanged(peripheral, subscribed);
}

To register your managed characteristic, during your host building operation (ie. MauiProgram.cs), add the following:

builder.Services.AddBleHostedCharacteristic<MyManagedCharacteristics>();

And lastly to start/stop your managed characteristic

// now inject/resolve the Shiny.BluetoothLE.Hosting.IBleHostingManager and now you can toggle on/off
Shiny.BluetoothLE.Hosting.IBleHostingManager hostingManager;
if (hostingManager.IsRegisteredServicesAttached)
{
    hostingManager.DetachRegisteredServices();
}
else
{
    await hostingManager.AttachRegisteredServices();
}