Closed markat1 closed 5 months ago
maybe zebra zd621
is a ble device so you should use InTheHand.BluetoothLE instead?
thank you so much for your reply @SydneyOwl !
hmm, I will definately try with BluetoothLE!
If I look in the documentation for zebra zd621 it says that it can both handle bluetooth classic and bluetooth LE
In the setup I can choose between classic and bluetooth or use both (classic + bluetooth LE)
@SydneyOwl do you have a sample on howto use BluetoothLE? I'm not sure if the following is using Bluetooth LE.
public IAsyncEnumerable<BluetoothDeviceInfo> GetNearbyDevicesViaBluetoothAsync()
{
using var client = new BluetoothClient();
return client.DiscoverDevicesAsync();
}
Hello @markat1
Seems like you're not using ble since you're using BluetoothDevice
instead of BluetoothLEDevice
.
Here's my example:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using InTheHand.Bluetooth;
using SenhaixFreqWriter.Constants.BLE;
using SenhaixFreqWriter.Utils.BLE.Interfaces;
using SenhaixFreqWriter.Utils.Serial;
namespace SenhaixFreqWriter.Utils.BLE.Platforms.Generic;
public class GenerticShxble : IBluetooth
{
................
public async Task<bool> ScanForShxAsync()
{
var filter = new BluetoothLEScanFilter
{
Name = BleConst.BtnameShx8800
};
try
{
// this will call a native windows ble search window
_shxDevice = await Bluetooth.RequestDeviceAsync(new RequestDeviceOptions { Filters = { filter } });
}
catch
{
// a fallback for linux
var cts = new CancellationTokenSource();
cts.CancelAfter(5000);
var discoveredDevices = await Bluetooth.ScanForDevicesAsync(new RequestDeviceOptions
{
Filters = { filter }
}, cts.Token);
foreach (var discoveredDevice in discoveredDevices)
if (discoveredDevice.Name.Equals(BleConst.BtnameShx8800))
{
_shxDevice = discoveredDevice;
break;
}
}
return _shxDevice != null;
}
.......
}
by the way, make sure you're using <TargetFramework>netx.0-windows10.0.19041.0</TargetFramework>
when building on windows. see #341 for more!
You are absolutely right @SydneyOwl ! I also tried your example and it worked! Thank you!
will definately check out https://github.com/inthehand/32feet/issues/341 !
Glad to be of help to you!😃
just one last thing @SydneyOwl - do you also have a sample of writing to a BluetoothLEDevice ? (seems like I have to do it via a GATT server? - https://software-dl.ti.com/lprf/sdg-latest/html/ble-stack-3.x/gatt.html)
@markat1 here's my sample code:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using InTheHand.Bluetooth;
using SenhaixFreqWriter.Constants.BLE;
using SenhaixFreqWriter.Utils.BLE.Interfaces;
using SenhaixFreqWriter.Utils.Serial;
namespace SenhaixFreqWriter.Utils.BLE.Platforms.Generic;
public class GenerticShxble : IBluetooth
{
private GattCharacteristic _shxCharacteristic;
private BluetoothDevice _shxDevice;
private GattService _shxService;
public Task<bool> GetBleAvailabilityAsync()
{
...
}
public async Task<bool> ScanForShxAsync()
{
....
}
public Task ConnectShxDeviceAsync()
{
return _shxDevice.Gatt.ConnectAsync();
}
public async Task<bool> ConnectShxRwServiceAsync()
{
_shxService = await _shxDevice.Gatt.GetPrimaryServiceAsync(
BluetoothUuid.FromShortId(Convert.ToUInt16(BleConst.RwServiceUuid.ToUpper(), 16)));
return _shxService != null;
}
public async Task<bool> ConnectShxRwCharacteristicAsync()
{
_shxCharacteristic = await _shxService.GetCharacteristicAsync(
BluetoothUuid.FromShortId(Convert.ToUInt16(BleConst.RwCharacteristicUuid.ToUpper(), 16)));
return _shxCharacteristic != null;
}
public async void RegisterSerial()
{
_shxCharacteristic.CharacteristicValueChanged += Characteristic_CharacteristicValueChanged;
MySerialPort.GetInstance().BtDeviceMtu = _shxDevice.Gatt.Mtu;
await _shxCharacteristic.StartNotificationsAsync();
MySerialPort.GetInstance().WriteBle = _shxCharacteristic.WriteValueWithoutResponseAsync;
}
private void Characteristic_CharacteristicValueChanged(object sender, GattCharacteristicValueChangedEventArgs e)
{
foreach (var b in e.Value) MySerialPort.GetInstance().RxData.Enqueue(b);
}
public void Dispose()
{
...
}
}
For a BLE (Bluetooth Low Energy) device, there may be multiple services and characteristics. You need to find the service UUID (in my code, RwServiceUuid) and characteristic UUID(in my code, RwCharacteristicUuid) corresponding to the characteristic used for data interaction. You may be able to find this information in the device's development documentation.
then you should connect to the target characteristic of the ble device at first(in my sample, ConnectShxDeviceAsync->ConnectShxRwServiceAsync->ConnectShxRwCharacteristicAsync), after that bind a callback function CharacteristicValueChanged
( in my code i put all data received into a queue) then call StartNotificationsAsync, finally you can call WriteValueWithoutResponseAsync or WriteValueAsync ( depends on your device)to write data to the device!
I‘m not sure whether proper characteristic is connected or not.. Here’s an example of the zebra iOS sdk: https://github.com/ZebraDevs/LinkOS-iOS-Samples/tree/ZebraPrinterBLEDemo/ZebraPrinterBLEDemo
And here’re the uuids which may possible works: ZPRINTER_DIS_SERVICE_UUID = "0000180A-0000-1000-8000-00805F9B34FB" // Or "180A". ZPRINTER_SERVICE_UUID="38EB4A80-C570-11E3-9507-0002A5D5C51B" / / TARGET SERVICE READ_FROM_ZPRINTER_CHARACTERISTIC_UUID = "38EB4A81-C570-11E3-9507-0002A5D5C51B" //USE THIS TO READ WRITE_TO_ZPRINTER_CHARACTERISTIC_UUID = "38EB4A82-C570-11E3-9507-0002A5D5C51B" //USE THIS TO WRITE
maybe you should try to connect to services and characteristics directly from the uuids? If it doesn’t work, try using writewithresponse instead of writewithoutresponse?
@SydneyOwl Ups sorry I might have deleted my question - but here is where I am right now.
This is really confusing... Have you consulted the SDK mentioned above? It seems like the Zebra printer uses two different characterics for reading and writing respectively, but it appears you're using the same one.
READ_FROM_ZPRINTER_CHARACTERISTIC_UUID = "38EB4A81-C570-11E3-9507-0002A5D5C51B" //USE THIS TO READ
WRITE_TO_ZPRINTER_CHARACTERISTIC_UUID = "38EB4A82-C570-11E3-9507-0002A5D5C51B" //USE THIS TO WRITE
one start with 38EB4A81 and the otherstart with 38EB4A82
@SydneyOwl Hmm okay - so I guess It's better to show you what I can choose from of characteristics - properties confuses me - and if I try not to use indicate it would throw an exception
Due to the following
I don't quite understand what you mean; in fact, as indicated by the red circle in the diagram, the characteristic 38EB4A81 can only be used for indication, and you should bind the callback function for received data to this characteristic and call startnotifyasync on this characteristic; whereas the characteristic 38EB4A82 can be used for read and write, and you should just write data to this characteristic and shouldn't use it for indication.
@SydneyOwl Sorry for being a bit rookie here :) - what confuses me is the following expression marked with a red circle - should I comment it out? If I only want to do writes, then I can't really use indication right?
then do:
In fact, it's not like that... Could you paste function ConnectToZd621 at here?
private void Characteristic_CharacteristicValueChanged(object? sender, GattCharacteristicValueChangedEventArgs e)
{
var t = sender;
var p = e;
}
private static string GetMessageByItemNumber()
{
return @"^XA:^PR2:^LRY:^LH30,30:^FO0,0^GB400,300,300^FS:^FO20,10^AF^FDZEBRA^FS:^FO20,60^B3,,40^FDAAA001^FS:^PF50:^FO20,160^AF^FDSLEW EXAMPLE^FS:^XZ";
}
public async Task ConnectToZd621()
{
try
{
BluetoothDevice? labelDevice = (await _bluetoothService.GetNearbyDevicesViaBluetoothAsync()).FirstOrDefault(device => device.Name == "ZD621");
IEnumerable<BluetoothDevice>? labelDevices = await _bluetoothService.GetNearbyDevicesViaBluetoothAsync();
var service = (await labelDevice!.Gatt.GetPrimaryServicesAsync()).LastOrDefault(s => s.Device.Name == "ZD621");
var services = await labelDevice!.Gatt.GetPrimaryServicesAsync();
await labelDevice!.Gatt.ConnectAsync();
var isConnnected = labelDevice!.Gatt.IsConnected;
var characterics = (await service!.GetCharacteristicsAsync()).Where(s => s.Properties.ToString() == "Read | Write");
var characteric = characterics.FirstOrDefault();
characteric!.CharacteristicValueChanged += Characteristic_CharacteristicValueChanged;
await characteric.StartNotificationsAsync();
byte[] message = Encoding.ASCII.GetBytes(GetMessageByItemNumber());
var mtu = labelDevice.Gatt.Mtu;
await characteric.WriteValueWithResponseAsync(message);
}
catch (Exception ex)
{
var t = ex;
throw;
}
}
maybe this works
public async Task ConnectToZd621()
{
try
{
BluetoothDevice? labelDevice =
(await _bluetoothService.GetNearbyDevicesViaBluetoothAsync()).FirstOrDefault(device =>
device.Name == "ZD621");
IEnumerable<BluetoothDevice>? labelDevices = await _bluetoothService.GetNearbyDevicesViaBluetoothAsync();
await labelDevice!.Gatt.ConnectAsync();
var service = await labelDevice!.Gatt.GetPrimaryServiceAsync(BluetoothUuid.FromGuid(Guid.Parse("38EB4A80-C570-11E3-9507-0002A5D5C51B")));
var isConnnected = labelDevice!.Gatt.IsConnected;
var read_characteric = await service
.GetCharacteristicAsync(BluetoothUuid.FromGuid(Guid.Parse("38EB4A81-C570-11E3-9507-0002A5D5C51B")));
var write_characteric = await service
.GetCharacteristicAsync(BluetoothUuid.FromGuid(Guid.Parse("38EB4A82-C570-11E3-9507-0002A5D5C51B")));
read_characteric!.CharacteristicValueChanged += Characteristic_CharacteristicValueChanged;
await read_characteric.StartNotificationsAsync();
byte[] message = Encoding.ASCII.GetBytes(GetMessageByItemNumber());
var mtu = labelDevice.Gatt.Mtu;
await write_characteric.WriteValueWithResponseAsync(message);
}
catch (Exception ex)
{
var t = ex;
throw;
}
}
Yes that worked! thank you so much @SydneyOwl !
Okay one final question ! @SydneyOwl
mtu is not something that I can make bigger? 247 bytes is all I got?
congratulations! My English is not very good, so you may not fully understand what I mean.. yes mtu is negotiated by the operation system and the device so you can't modify it if the data you want to send is larger than mtu-2 (maybe, data header counts in mtu) you have to split it and send multiple times
your english are great @SydneyOwl ! Thank you so much for your help - I couldn't have done it without you!
you're welcome! actually zebra printer has their own sdk here:https://techdocs.zebra.com/link-os/ maybe you can directly use them
oh you're using wpf...they only have maui one so maybe incompatible
tried that :) - doesn't work - much better using 32feet, because it seperates me from the zebra product :)
I'm using
library: InTheHand.Net.Bluetooth version 4.1.43. framework: .net 6 (also possible to use .net 8) target version: 10.0.22621.0 target os: windows application: WPF application framework: prism
I tried discovering my label machine (zebra zd621), but I'm unable to show it via:
this is what it finds via debugging - it finds some phones, but not the zd621:
I can find zebra zd621 device on my phone and microsoft bluetooth.
I tried setting inqueryLength, but I get an error back saying
System.PlatformNotSupportedException: 'Operation is not supported on this platform.'
:Error:
TimeSpan IBluetoothClient.InquiryLength { get => TimeSpan.Zero; set => throw new PlatformNotSupportedException(); }