Xamarin Plugin.BLE 为什么读取的数据没有改变?
Xamarin Plugin.BLE why data read doesn't change?
我无法完成从我的 BLE 设备读取一些数据的任务。
我的目标机器上有一个 HM-19 DSD Tech Bluetooth 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 技术演示应用程序并执行相同的指令(连接、发送和读取),它就可以工作!我发送触发机器响应的数据,演示应用程序显示我从机器发送的预期正确字节。
那么...我如何读取该数据?在开发者网站上,文档几乎没有指导您如何扫描和连接,但在 write/read 上缺少信息。非常令人失望,这个插件是 Nuget 存储库中最好的。
任何人都可以帮助我,我做的不好吗?
这是一个link插件,可能我漏掉了什么https://github.com/xabre/xamarin-bluetooth-le
BLE 通信可能会很痛苦,尤其是使用 Xamarin 时。
在任何情况下,您的应用程序的异步调用可能 return 在数据实际发送到您的终端设备之前。
这是由以下几个因素造成的:
- 操作系统 BLE 驱动程序行为 - 您在应用程序代码中进行的任何调用都由操作系统驱动程序处理。这些可能 return 在 BLE 硬件实际处理任何数据之前。
- BLE 传输层延迟 - BLE 数据传输不是即时的。两个设备之间的数据连接实际上发生在离散的时隙内,其间 BLE 收发器被关闭以节省电力。
- 结束设备响应时间。
使用 BLE 的设备之间的双向通信的大多数实现至少使用两个特征,一个用于发送数据,另一个用于设备接收数据,例如设备 1 接收有关设备 2 发送的特性数据,反之亦然。这避免了双方发送数据发生冲突的可能性。
您可以尝试在轮询特征数据之前在代码中放置一个延迟,看看是否有帮助,但这不是最佳解决方案。
我看到您正在“匿名”使用您的特征,而不是使用它的 uuid select。如果蓝牙服务支持不止一种特性,那么您将需要使用 uuid 来确保您使用的是正确的特性。特征列表,很像服务和设备列表,可能不会在您请求它们时按相同顺序return编辑。
您可以选择通过定时读取特征来轮询特征,或者为特征 notification/indication 事件设置处理程序(如果特征支持它并且您的 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);
}
最后我将方法附加到特性的事件处理程序并启动服务
characteristic.ValueUpdated += UpdatingValue;
await characteristic.StartUpdatesAsync();
现在每次模块向我的应用程序发送数据时,UpdateEvent 都会触发并填充缓冲区,然后打印缓冲区或在某些视图中显示以查看结果。
我无法完成从我的 BLE 设备读取一些数据的任务。
我的目标机器上有一个 HM-19 DSD Tech Bluetooth 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 技术演示应用程序并执行相同的指令(连接、发送和读取),它就可以工作!我发送触发机器响应的数据,演示应用程序显示我从机器发送的预期正确字节。
那么...我如何读取该数据?在开发者网站上,文档几乎没有指导您如何扫描和连接,但在 write/read 上缺少信息。非常令人失望,这个插件是 Nuget 存储库中最好的。
任何人都可以帮助我,我做的不好吗?
这是一个link插件,可能我漏掉了什么https://github.com/xabre/xamarin-bluetooth-le
BLE 通信可能会很痛苦,尤其是使用 Xamarin 时。
在任何情况下,您的应用程序的异步调用可能 return 在数据实际发送到您的终端设备之前。 这是由以下几个因素造成的:
- 操作系统 BLE 驱动程序行为 - 您在应用程序代码中进行的任何调用都由操作系统驱动程序处理。这些可能 return 在 BLE 硬件实际处理任何数据之前。
- BLE 传输层延迟 - BLE 数据传输不是即时的。两个设备之间的数据连接实际上发生在离散的时隙内,其间 BLE 收发器被关闭以节省电力。
- 结束设备响应时间。
使用 BLE 的设备之间的双向通信的大多数实现至少使用两个特征,一个用于发送数据,另一个用于设备接收数据,例如设备 1 接收有关设备 2 发送的特性数据,反之亦然。这避免了双方发送数据发生冲突的可能性。
您可以尝试在轮询特征数据之前在代码中放置一个延迟,看看是否有帮助,但这不是最佳解决方案。
我看到您正在“匿名”使用您的特征,而不是使用它的 uuid select。如果蓝牙服务支持不止一种特性,那么您将需要使用 uuid 来确保您使用的是正确的特性。特征列表,很像服务和设备列表,可能不会在您请求它们时按相同顺序return编辑。
您可以选择通过定时读取特征来轮询特征,或者为特征 notification/indication 事件设置处理程序(如果特征支持它并且您的 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);
}
最后我将方法附加到特性的事件处理程序并启动服务
characteristic.ValueUpdated += UpdatingValue;
await characteristic.StartUpdatesAsync();
现在每次模块向我的应用程序发送数据时,UpdateEvent 都会触发并填充缓冲区,然后打印缓冲区或在某些视图中显示以查看结果。