Сервер Bluetooth LE GATT, работающий на Raspberry Pi с .NET 8C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Сервер Bluetooth LE GATT, работающий на Raspberry Pi с .NET 8

Сообщение Anonymous »

Я собрал это приложение .NET 8, которое должно работать на 64-разрядной версии Raspberry Pi, и делаю следующее:
  • Публикуйте рекламные объявления Bluetooth LE с помощью конкретные данные производителя, чтобы клиенты могли идентифицировать устройство.
  • Предлагайте определенные услуги GATT с характеристиками, чтобы клиенты могли запрашивать данные из Raspi.
Он содержит множество интерфейсов D-Bus которые были в основном созданы ChatGPT, и я частично исправил их в соответствии со спецификацией BlueZ. Я новичок в BlueZ и D-Bus, поэтому могу лишь приблизительно представить, что все это делает. Кроме того, ИИ оказался не так уж полезен, потому что мне приходилось снова и снова исследовать, гадать и запрашивать конкретные API, которые оказались необходимыми, но раньше не учитывались (например, GattManager и GattApplication).
Однако в коде есть несколько проблем, которые мне пока не удалось решить:
  • При отправке рекламных объявлений (проверено с помощью приложения nRF Connect) для Android), они не содержат никаких данных. Нет локального имени, нет мощности передачи, нет данных производителя.
  • Когда используется код сервера GATT (как указано здесь), он выдает исключение Tmds.DBus.DBusException: " org.bluez.Error.Failed: объект не получен"
До сих пор я мог определить ошибки из спецификации, но теперь я потерялся и часть GattApplication больше не описывается. Это вообще правильно?
Так что же я пропустил? Службы и характеристики GATT связаны только через строковое значение ObjectPath с общими префиксами или мне нужно явно установить это соединение где-то в коде? И что означает это сообщение об исключении?
Любая помощь приветствуется, поскольку мне не удалось найти никаких ресурсов по этому поводу в Интернете. Я не уверен, делал ли кто-нибудь это раньше.
Вот код (Program.cs):
using Tmds.DBus;

namespace RadarSender;

public class Program
{
public static async Task Main()
{
// Create a DBus connection with manual connection management
var connection = new Connection(Address.System);
await connection.ConnectAsync();

// Access the LEAdvertisingManager1 interface
const string adapterPath = "/org/bluez/hci0";
var advertisingManager = connection.CreateProxy("org.bluez", adapterPath);

// Advertisement setup
const string advertisementPath = "/com/example/Advertisement";
Dictionary manufacturerData = [];
manufacturerData["0x8001"] = new byte[] { 0x12, 0x34, 0x56 };
var advertisement = new LEAdvertisement(advertisementPath, manufacturerData);
await connection.RegisterObjectAsync(advertisement);

await advertisingManager.RegisterAdvertisementAsync(advertisement.ObjectPath, new Dictionary());
Console.WriteLine("BLE Advertisement started.");

// Create GATT objects
var application = new GattApplication("/com/example/gattapp");
var service = new GattService("/com/example/gattapp/service0", "12345678-1234-5678-1234-56789abcdef0");
var characteristic = new GattCharacteristic("/com/example/gattapp/service0/char0", "12345678-1234-5678-1234-56789abcdef1");

// Register objects with DBus
await connection.RegisterObjectAsync(application);
await connection.RegisterObjectAsync(service);
await connection.RegisterObjectAsync(characteristic);

// Register application with BlueZ
var gattManager = connection.CreateProxy("org.bluez", "/org/bluez/hci0");
await gattManager.RegisterApplicationAsync(application.ObjectPath, new Dictionary());
Console.WriteLine("GATT server started.");

Console.WriteLine("Press Enter to exit...");
Console.ReadLine();

// Cleanup
await advertisingManager.UnregisterAdvertisementAsync(advertisement.ObjectPath);
connection.UnregisterObject(advertisement.ObjectPath);
await gattManager.UnregisterApplicationAsync(application.ObjectPath);
connection.UnregisterObject(service.ObjectPath);
connection.UnregisterObject(characteristic.ObjectPath);
connection.Dispose();
}
}

[DBusInterface("org.bluez.LEAdvertisingManager1")]
public interface ILEAdvertisingManager1 : IDBusObject
{
Task RegisterAdvertisementAsync(ObjectPath advertisement, IDictionary options);
Task UnregisterAdvertisementAsync(ObjectPath advertisement);
}

[DBusInterface("org.bluez.LEAdvertisement1")]
public interface ILEAdvertisement1 : IDBusObject
{
Task GetIncludesAsync();
Task GetTypeAsync();
Task GetServiceUUIDsAsync();
Task GetLocalNameAsync();
Task GetAppearanceAsync();
Task GetTxPowerAsync();
Task GetManufacturerDataAsync();
Task GetServiceDataAsync();
Task ReleaseAsync();
}

public class LEAdvertisement : ILEAdvertisement1
{
private readonly IDictionary manufacturerData;

public LEAdvertisement(string path, IDictionary manufacturerData)
{
ObjectPath = new ObjectPath(path);
this.manufacturerData = manufacturerData;
}

public ObjectPath ObjectPath { get; }

public Task GetIncludesAsync() => Task.FromResult(["local-name", "tx-power"]);

public Task GetTypeAsync() => Task.FromResult("peripheral");

public Task GetServiceUUIDsAsync() => Task.FromResult(["12345678-1234-5678-1234-56789abcdef0"]);

public Task GetLocalNameAsync() => Task.FromResult("RaspberryPiBLE");

public Task GetAppearanceAsync() => Task.FromResult(0);

public Task GetTxPowerAsync() => Task.FromResult(10);

public Task GetManufacturerDataAsync() => Task.FromResult(manufacturerData);

public Task GetServiceDataAsync() => Task.FromResult(new Dictionary());

public Task ReleaseAsync()
{
Console.WriteLine("Advertisement released.");
return Task.CompletedTask;
}
}

[DBusInterface("org.bluez.GattManager1")]
public interface IGattManager1 : IDBusObject
{
Task RegisterApplicationAsync(ObjectPath application, IDictionary options);
Task UnregisterApplicationAsync(ObjectPath application);
}

public class GattApplication : IDBusObject
{
public GattApplication(string path)
{
ObjectPath = new ObjectPath(path);
}

public ObjectPath ObjectPath { get; }
}

[DBusInterface("org.bluez.GattService1")]
public interface IGattService1 : IDBusObject
{
Task GetUUIDAsync();
Task GetPrimaryAsync();
Task GetIncludesAsync();
Task GetCharacteristicsAsync();
}

public class GattService : IGattService1
{
private readonly string uuid;

public GattService(string path, string uuid)
{
ObjectPath = new ObjectPath(path);
this.uuid = uuid;
}

public ObjectPath ObjectPath { get; }

public Task GetUUIDAsync() => Task.FromResult(uuid);

public Task GetPrimaryAsync() => Task.FromResult(true);

public Task GetIncludesAsync() => Task.FromResult([]);

public Task GetCharacteristicsAsync()
{
// TODO: Add future characteristics here
var characteristicPath = new ObjectPath($"{ObjectPath}/char0");
return Task.FromResult(new[] { characteristicPath });
}
}

[DBusInterface("org.bluez.GattCharacteristic1")]
public interface IGattCharacteristic1 : IDBusObject
{
Task ReadValueAsync(IDictionary options);
Task WriteValueAsync(byte[] value, IDictionary options);
Task StartNotifyAsync();
Task StopNotifyAsync();
Task GetUUIDAsync();
Task GetFlagsAsync();
Task GetServiceAsync();
Task GetNotifyingAsync();
Task GetValueAsync();
}

public class GattCharacteristic : IGattCharacteristic1
{
private readonly string uuid;

public GattCharacteristic(string path, string uuid)
{
ObjectPath = new ObjectPath(path);
this.uuid = uuid;
}

public ObjectPath ObjectPath { get; }

public Task GetFlagsAsync() => Task.FromResult(["read", "write", "notify"]);

public Task ReadValueAsync(IDictionary options)
{
Console.WriteLine("Characteristic read requested.");
return Task.FromResult(new byte[] { 0x01, 0x02, 0x03 });
}

public Task WriteValueAsync(byte[] value, IDictionary options)
{
Console.WriteLine($"Characteristic write requested: {BitConverter.ToString(value)}");
return Task.CompletedTask;
}

public Task StartNotifyAsync()
{
Console.WriteLine("Notifications started.");
return Task.CompletedTask;
}

public Task StopNotifyAsync()
{
Console.WriteLine("Notifications stopped.");
return Task.CompletedTask;
}

public Task GetUUIDAsync() => Task.FromResult(uuid);

// TODO: Make configurable
public Task GetServiceAsync() => Task.FromResult(new ObjectPath("/com/example/gattapp/service0"));

public Task GetNotifyingAsync() => Task.FromResult(false);

public Task GetValueAsync() => Task.FromResult(new byte[] { 0x11, 0x22, 0x33, 0x44 });
}

И соответствующий файл проекта (.csproj):



Exe
net8.0
enable
enable









Подробнее здесь: https://stackoverflow.com/questions/792 ... with-net-8
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Сервер Bluetooth LE GATT, работающий на Raspberry Pi с .NET 8
    Anonymous » » в форуме C#
    0 Ответы
    31 Просмотры
    Последнее сообщение Anonymous
  • Может ли устройство Android одновременно действовать как GATT-сервер и GATT-клиент?
    Anonymous » » в форуме Android
    0 Ответы
    17 Просмотры
    Последнее сообщение Anonymous
  • Создайте Bluetooth-сервер BLE GATT с низким энергопотреблением с помощью .NET C#
    Anonymous » » в форуме C#
    0 Ответы
    17 Просмотры
    Последнее сообщение Anonymous
  • Виртуальный принтер сервер GATT физическое устройство Android
    Anonymous » » в форуме Android
    0 Ответы
    32 Просмотры
    Последнее сообщение Anonymous
  • Реализуйте CTS-подобный сервер GATT на iOS
    Anonymous » » в форуме IOS
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»