Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microbit Bluetooth UART service data reading problem #64

Open
nmitrak opened this issue Apr 3, 2024 · 7 comments
Open

Microbit Bluetooth UART service data reading problem #64

nmitrak opened this issue Apr 3, 2024 · 7 comments

Comments

@nmitrak
Copy link

nmitrak commented Apr 3, 2024

Hi @adabru, as i wrote in a previous post i managed to connect unity and then hololens 2 with a microbit and read its internal temperature sensor value by subscribing to the respective ServiceId and CharacteristicId. But now i have a second temperature sensor that i have connected to a microbit's pin and wrote a program for the microbit in order for the temperature value of the sensor (a simple number) to be transmitted though the Bluetooth Uart service which i enabled on the microbit.
Although i managed to send a set of characters from Unity to the microbit , through your BlewinrtDll project , by using the Demo's Write function , which uses BleApi.SendData, i cannot read any data coming from the microbit. It seems to me that when unity polls data from the CharacteristicId {6e400002-b5a3-f393-e0a9-e50e24dcca9e} of the Bluetooth UART Service nothing comes out. Subscribing to this service doesnt seem to detect value changes when using your demo(?)
The funny thing is that i can read the values coming from microbit through this bluetooth Uart service when using an android phone ,with a custom made application with appinventor and that the Microsoft 's Sample BluetoothLE app from Hololens 2 can subscribe to this CharacteristicId and seems to be detecting value changes but cannot recognize the data format.
I would appreciate any ideas . Again thank you very much.

@nmitrak
Copy link
Author

nmitrak commented Apr 4, 2024

After some research it seems that for that particular bluetooth uart service microbit sends raw binary data. Maybe unity polls for incoming data that are not in raw binary format

@adabru
Copy link
Owner

adabru commented Apr 5, 2024

Hi nmitrak, binary format should be fine for BleWinrtDll. In the Microsoft sample, you can try setting a breakpoint or a log output at https://github.com/microsoft/Windows-universal-samples/blob/main/Samples/BluetoothLE/cs/Scenario2_Client.xaml.cs#L447

@nmitrak
Copy link
Author

nmitrak commented Sep 22, 2024

Thank you again for your answer. Just coming back again to the same problem after a long period of time. I read somewhere that in order to receive messages from the bluetooth uart service of Micro:bit you have to enable notification, writing "0200" on the Client Characteristic Configuration Descriptor (CCCD) of the UART Service Characteristic.(The CCCD is 2902). Is this possible with BleWinrtDLL you compiled?
I would like to thank you once more for your contribution in solving this problem.

@nmitrak
Copy link
Author

nmitrak commented Sep 24, 2024

Dear @adabru
After searching the issues section i found tufeixp's code that might do the job. Coding in C++ is not my strong point but could you tell me please if i add this code to Bluewirtdll.cpp in order to reuse the function PollData without modification, after scanning the characteristics , should I ignore the SubscribeCharacteristic function, call ReadData function and then the PollData? Or call ReadData and directly get the data coming from BLE device?

Thank you so much for your support!

fire_and_forget ReadDataAsync(BLEData data) {
	{
		lock_guard lock(dataQueueLock);
	}
	auto characteristic = co_await retrieveCharacteristic(data.deviceId, data.serviceUuid, data.characteristicUuid);
	GattReadResult result = co_await characteristic.ReadValueAsync();
	if (result.Status() == GattCommunicationStatus::Success) {
		auto dataReader = DataReader::FromBuffer(result.Value());
		auto output = dataReader.ReadString(dataReader.UnconsumedBufferLength());

		BLEData data;
		wcscpy_s(data.characteristicUuid, sizeof(data.characteristicUuid) / sizeof(wchar_t), to_hstring(characteristic.Uuid()).c_str());
		wcscpy_s(data.serviceUuid, sizeof(data.serviceUuid) / sizeof(wchar_t), to_hstring(characteristic.Service().Uuid()).c_str());
		wcscpy_s(data.deviceId, sizeof(data.deviceId) / sizeof(wchar_t), characteristic.Service().Device().DeviceId().c_str());

		data.size = output.size();
		memcpy(data.buf, output.data(), data.size);
		{
			lock_guard queueGuard(dataQueueLock);
			dataQueue.push(data);
			dataQueueSignal.notify_one();
		}
		//saveError(L"%s:%d read done: %s", __WFILE__, __LINE__, output.c_str());
	}
}
void ReadData(BLEData* data)
{
ReadDataAsync(*data);
}

@adabru
Copy link
Owner

adabru commented Sep 24, 2024

Subscribing to a characteristic writes to the CCCD:

fire_and_forget SubscribeCharacteristicAsync(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, bool* result) {
try {
auto characteristic = co_await retrieveCharacteristic(deviceId, serviceId, characteristicId);
if (characteristic != nullptr) {
auto status = co_await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify);
if (status != GattCommunicationStatus::Success)
saveError(L"%s:%d Error subscribing to characteristic with uuid %s and status %d", __WFILE__, __LINE__, characteristicId, status);
else {
Subscription *subscription = new Subscription();

@nmitrak
Copy link
Author

nmitrak commented Sep 28, 2024

Dear @adabru thank you very for your answer and for clarifying this point. Nevertheless microbit is sending data through bluetooth uart and HoloLens doesn't retrieve them when subscribing to a characteristic id and polling data. I tested the communication between microbit and Hololens 2 with Microsoft's bluetooth sample and data comes in but of unknown format. That's why i thought of implementing the ReadDataAsync function as you suggested at an older post. But being a little bit of a newbie at this made me wondering how this function works as it doesn't seem to take any account of descriptors
Again thank you very much for your time

Edit: Once more you are right @adabru and thank you , the CCCD is writen with Subscription to the Characteristic. The only difference is that in order to read data from Micro:bit bluetooth UART you have to change the GattClientCharacteristicConfigurationDescriptorValue argument from Notify to Indicate. Then the data polling works like a charm. But I assume that this will work only in UART polling.

fire_and_forget SubscribeCharacteristicAsync(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, bool* result) { 
 	try { 
 		auto characteristic = co_await retrieveCharacteristic(deviceId, serviceId, characteristicId); 
 		if (characteristic != nullptr) { 
 			auto status = co_await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Indicate); 
 			if (status != GattCommunicationStatus::Success) 
 				saveError(L"%s:%d Error subscribing to characteristic with uuid %s and status %d", __WFILE__, __LINE__, characteristicId, status); 
 			else { 
 				Subscription *subscription = new Subscription(); 

@adabru
Copy link
Owner

adabru commented Nov 14, 2024

Thank you very much for sharing your solution :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants