簡體   English   中英

Xamarin Plugin.BLE 為什么讀取的數據不會改變?

[英]Xamarin Plugin.BLE why data read doesn't change?

我一直堅持從我的 BLE 設備讀取一些數據的任務。

我的目標機器上有一個 HM-19 DSD Tech 藍牙 LE 模塊,我想用我的智能手機與它通信。

我正在使用 Xamarin 和 Plugin.BLE 來嘗試實現這一目標。

有我的BluetoothPage.xaml.cs代碼

  public partial class BluetoothPage : ContentPage
  {
      IAdapter adapter;
      ObservableCollection<IDevice> devicesList;
      ListView pageList;

      public BluetoothPage()
      {
          adapter = CrossBluetoothLE.Current.Adapter;
          deviceList = new ObservableCollection<IDevice>();

          pageList = new ListView();
          pageList.ItemSource = deviceList;
          pageList.ItemSelected += ActionConnect;
          pageStackLayout.Children.Add(pageList); // Layout component declared on BluetoothPage.xaml
      }

      private void ButtonScan(object sender, EventArgs e)
      {
          try
          {
              devicesList.Clear();
              adapter.DeviceDiscovered += (s, a) =>
              {
                  devicesList.Add(a.Device);
              };

              if(!adapter.isScanning)
              {
                  await adapter.StartScanningForDevicesAsync();
              }
          }
          catch(Exception ex)
          {
              Console.WriteLine("ERROR: " + ex.Message);
          }
      }

      private async void ActionConnect(object sender, SelectedItemChangedEventArgs se)
      {
          if(se != null)
          {
              try
              {
                  if(adapter.IsScanning)
                  {
                      await adapter.StopScanningForDevicesAsync();
                  }

                  await adapter.ConnectToDeviceAsync((IDevice)pageList.SelectedItem);
                  IDevice device = adapter.ConnectedDevices[0];

                  // now get the service and characteristics of connected device
                  var services = await device.GetServicesAsync();

                  IService service = services[0];

                  var characteristics = await service.GetCharacteristicsAsync();

                  ICharacteristic characteristic = characteristics[0];

                  // now we can write and hopefully read values
                  byte[] data = { Coderequest.InitRequest, Coderequest.Info }; // My message to sendo to the machine to trigger his functions and his response
                  byte[] response = { 0 };

                  await characteristic.WriteAsync(data); // Send the data

                  response = await characteristic.ReadAsync() // Theorically we reading the response from the machine by BLE

              }
              catch(Exception ex)
              {
                  Console.WriteLine("ERROR: " + ex.Message);
              }
          }
      }
  }

當我啟動我的應用程序時:

  • 我觸發了掃描按鈕,它工作得很好
  • 然后我點擊我想要的 BLE 設備,它可以完美連接
  • 使用目標機器上的調試器,我可以看到數據確實是由應用程序通過 BLE 發送的

但是我沒有得到預期的響應,我總是在讀取相同的字節(可能是默認值),而不是我預期的字節。

奇怪的是,如果我使用 HM-19 模塊的 DSD Tech Demo App 並執行相同的指令(連接、發送和讀取),它就可以工作! 我發送觸發機器響應的數據,演示應用程序顯示我從機器發送的預期正確字節。

那么......我怎樣才能讀取這些數據? 在開發人員網站上,文檔幾乎沒有指導您進行掃描和連接,但在寫入/讀取方面缺乏信息。 這是非常令人失望的,這個插件是 Nuget repos 上最好的。

誰能幫助我,我在哪里做的不好?

這是插件的鏈接,也許我錯過了一些東西https://github.com/xabre/xamarin-bluetooth-le

BLE 通信可能會很痛苦,尤其是使用 Xamarin。

在任何情況下,來自您的應用程序的異步調用可能會在數據實際發送到您的終端設備之前返回。 這是由於幾個因素:

  1. 操作系統 BLE 驅動程序行為 - 您在應用程序代碼中進行的任何調用都由操作系統驅動程序處理。 這些可能會在 BLE 硬件實際處理任何數據之前返回。
  2. BLE 傳輸層延遲 - BLE 數據傳輸不是即時的。 兩個設備之間的數據連接實際上發生在離散的時隙內,在此期間BLE收發器被關閉以節省電力。
  3. 終端設備響應時間。

使用 BLE 的設備之間的雙向通信的大多數實現至少使用兩個特性,一個用於發送數據,另一個用於由設備接收的數據,例如設備 1 接收與設備 2 發送的特性有關的數據,反之亦然。 這避免了雙方發送的數據發生任何沖突的可能性。

您可以嘗試在輪詢特征數據之前在代碼中放置延遲,看看是否有幫助,但這不是最佳解決方案。

我看到您正在“匿名”使用您的特征,而不是使用它的 uuid 來選擇它。 如果藍牙服務支持多個特性,那么您將需要使用 uuid 以確保您使用的是正確的特性。 與服務和設備列表非常相似的特征列表可能不會在您請求它們時以相同的順序返回。

如果特性支持並且您的 BLE 設備使用該機制來顯示數據已准備好,您可以選擇通過定時讀取特性或為特性通知/指示事件設置處理程序來輪詢特性。

經過各種嘗試,我得到了解決方案:

要有效地從 BLE 模塊讀取數據,必須使用 ValueUpdateHandler。

然后我以這種方式更改了我的代碼:

public partial class BluetoothPage : ContentPage
{
      IAdapter adapter;
      ObservableCollection<IDevice> devicesList;
      ListView pageList;
      List<byte> buffer = new List<byte>();

      public BluetoothPage()
      {
          adapter = CrossBluetoothLE.Current.Adapter;
          deviceList = new ObservableCollection<IDevice>();

          pageList = new ListView();
          pageList.ItemSource = deviceList;
          pageList.ItemSelected += ActionConnect;
          pageStackLayout.Children.Add(pageList); // Layout component declared on BluetoothPage.xaml
      }

      private void UpdatingValue(object sender, CharacteristicUpdateEventArgs args)
      {
          buffer.AddRange(args.Characteristic.Value);
      }

      private void ButtonScan(object sender, EventArgs e)
      {
          try
          {
              devicesList.Clear();
              adapter.DeviceDiscovered += (s, a) =>
              {
                  devicesList.Add(a.Device);
              };

              if(!adapter.isScanning)
              {
                  await adapter.StartScanningForDevicesAsync();
              }
          }
          catch(Exception ex)
          {
              Console.WriteLine("ERROR: " + ex.Message);
          }
      }

      private async void ActionConnect(object sender, SelectedItemChangedEventArgs se)
      {
          if(se != null)
          {
              try
              {
                  if(adapter.IsScanning)
                  {
                      await adapter.StopScanningForDevicesAsync();
                  }

                  await adapter.ConnectToDeviceAsync((IDevice)pageList.SelectedItem);
                  IDevice device = adapter.ConnectedDevices[0];

                  // now get the service and characteristics of connected device
                  IService service = device.GetServiceAsync(Guid.Parse("0000ffe0-1000-8000-00805f9b34fb"));

                  ICharacteristic characteristic = service.GetCharacteristicAsync(Guid.Parse("0000ffe1-1000-8000-00805f9b34fb"));
                  // we attach the UpdateVale event to the characteristic
                  // and we start the service
                  characteristic.ValueUpdated += UpdatingValue;
                  await characteristic.StartUpdatesAsync();

                  // now we can write and hopefully read values
                  byte[] data = { Coderequest.InitRequest, Coderequest.Info }; // My message to sendo to the machine to trigger his functions and his response

                  await characteristic.WriteAsync(data); // Send the data

              }
              catch(Exception ex)
              {
                  Console.WriteLine("ERROR: " + ex.Message);
              }
          }
      }
  }

所以首先我創建一個字節緩沖區來存儲數據: List<byte> buffer = new List<byte>() 我為事件創建了一個方法來捕獲讀取的值並填充緩沖區

private void UpdatingValue(object sender, CharacteristicUpdateEventArgs args)
{
    buffer.AddRange(args.Characteristic.Value);
}

最后,我將方法附加到特征的 EventHandler 並啟動服務

characteristic.ValueUpdated += UpdatingValue;
await characteristic.StartUpdatesAsync();

現在,每次模塊向我的應用程序發送數據時,UpdateEvent 都會觸發並填充緩沖區,然后打印緩沖區或在某些視圖中顯示以查看結果。

該程序運行不正常,所以我查了一下,發現類似的東西,缺少的是找不到藍牙設備。 很抱歉,如果您可以分享,請通過電子郵件發送整個程序。 謝謝 kdg000@empas.com

  1. AndroidManifest.xml
  1. 主頁.xaml

     <Button Text="Search" Clicked="searchDevice"/> <ListView x:Name="DevicesList" CachingStrategy="RecycleElement" ItemSelected="DevicesList_OnItemSelected"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="{Binding name}"></Label> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
  2. MainPage.xaml.cs

namespace employeeID { public partial class MainPage : ContentPage { IAdapter 適配器; IBluetoothLE ble; ObservableCollection 設備列表; IDevice設備;

    public MainPage()
    {
        InitializeComponent();
        
        ble = CrossBluetoothLE.Current;
        adapter = CrossBluetoothLE.Current.Adapter;

        devicelist = new ObservableCollection<IDevice>();
        DevicesList.ItemsSource = devicelist;
    }

    private async void searchDevice(object sender, EventArgs e)
    {
        if (ble.State == BluetoothState.Off)
        {
            await DisplayAlert("Message", "Bluetooth is not available.", "OK");
        }
        else
        {
            try
            {
                devicelist.Clear();

                adapter.ScanTimeout = 10000;
                adapter.ScanMode = ScanMode.Balanced;

                adapter.DeviceDiscovered += (s, a) =>
                {
                    //devicelist.Add(new ScanResultViewModel() { Device = a.Device, IsConnect = "Status: " + a.Device.State.ToString(), Uuid = "UUID:" + a.Device.Id.ToString() });
                    devicelist.Add(a.Device);
                };

                //We have to test if the device is scanning 
                if (!ble.Adapter.IsScanning)
                {
                    await adapter.StartScanningForDevicesAsync();
                }
            }
            catch (Exception ex)
            {
                await DisplayAlert("Notice", ex.Message.ToString(), "Error !");
            }
        }
    }

    private async void DevicesList_OnItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        device = DevicesList.SelectedItem as IDevice;

        var result = await DisplayAlert("Message", "Do you want to connect to this device?", "Connect", "Cancel");

        if (!result)
            return;

        //Stop Scanner
        await adapter.StopScanningForDevicesAsync();

        try
        {
            await adapter.ConnectToDeviceAsync(device);

            await DisplayAlert("Message", "Connect Status:" + device.State, "OK");

        }
        catch (DeviceConnectionException ex)
        {
            await DisplayAlert("Error", ex.Message, "OK");
        }

    }
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM