Xamarin Plugin.BLE 为什么读取的数据不会改变?



我被这个关于从我的BLE设备读取一些数据的任务卡住了。

我的目标机器上有一个HM-19 DSD Tech蓝牙LE模块,我想用我的智能手机与它通信。

我使用Xamarin插件。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技术演示应用程序并执行相同的指令(连接,发送和读取),它就会工作!我发送触发机器响应的数据,演示应用程序显示我从机器发送的预期正确字节。

所以…我怎么读取这些数据?在开发者网站上,文档几乎没有指导你扫描和连接,但是关于写/读缺乏信息。这是非常令人失望的,这个插件是最好的Nuget库。

谁能帮帮我,我做得不好吗?这是一个插件的链接,也许我错过了什么https://github.com/xabre/xamarin-bluetooth-le

经过多次尝试,我得到了解决方案:

要有效地从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触发并填充缓冲区,然后打印缓冲区或显示在一些视图中查看结果。

BLE通信可能是一种痛苦,尤其是Xamarin。

在任何情况下,应用程序的异步调用可能在数据实际发送到终端设备之前返回。这是由以下几个因素造成的:

  1. 操作系统BLE驱动程序行为-您在应用程序代码中进行的任何调用都由操作系统驱动程序处理。这些可能在BLE硬件实际处理任何数据之前返回。
  2. BLE传输层延迟- BLE传输数据不是即时的。两个设备之间的数据连接实际上发生在离散的时隙中,在此期间关闭BLE收发器以节省电力。
  3. 终端响应时间。

使用BLE的设备之间的双向通信的大多数实现使用至少两个特征,一个用于发送数据,另一个用于设备接收数据,例如设备1接收设备2发送的特征数据,反之亦然。这避免了双方发送的数据发生冲突的可能性。

您可以尝试在轮询特征数据之前在代码中放置延迟,看看是否有帮助,但这不是最佳解决方案。

我看到你正在"匿名"使用你的特征,而不是使用它的uid来选择它。如果蓝牙服务支持多个特性,那么您需要使用uid来确保使用的是正确的特性。特征列表,就像服务和设备列表一样,可能不会在你请求它们时以相同的顺序返回。

您可以选择通过定时读取特征或设置特征通知/指示事件的处理程序来轮询特征,如果特征支持它并且您的BLE设备使用该机制来显示数据已准备好。

程序不能正常工作,所以我查了一下,发现了类似的东西,缺少的不是找到蓝牙设备。很抱歉,如果你可以分享,请把整个程序用电子邮件发送过来。谢谢你!kdg000@empas.com

  1. AndroidManifest.xml
  • MainPage.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>
    
  • MainPage.xaml.cs

  • employeeID名称空间{公共部分类MainPage: ContentPage{IAdapter适配器;IBluetoothLE祝福;ObservableCollection devicelist;设备;i系设备之

    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");
    }
    }
    }
    

    }

    相关内容

    • 没有找到相关文章

    最新更新