C# Converting a byte array from BT LE device - c#

I am using a Nordic Thingy:52 to record environmental data in a UWP app and have followed the example in the Windows Universal Sample apps to connect to BT LE devices.
So far I have been able to connect to the device to retrieve service and characteristic information but when receiving the actual data from the sensors I can't manage to convert the byte array into usable data.
async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
// An Indicate or Notify reported that the value has changed.
var reader = DataReader.FromBuffer(args.CharacteristicValue);
byte[] input = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(input);
}
When checking the contents of the byte array you can see that something has been received but I'm stuck when it comes to knowing how to convert this array to useful data.
Code to read the byte array
Data specification for data sent by the device

From the document we can see the definition of pressure data:
5 bytes contains one int32 for integer part and one uint8 for decimal part. Uint is hPa.
You get a string like this:
Int32 pressureInteger = BitConverter.ToInt32(input, 0); //252-3-0-0
string pressureString = pressureInteger.ToString() + "." + input[4].ToString() + "hPa";
The string will be "1020.28hPa"
More reference "BitConverter Class" and note little-endian/big-endian.

Related

Windows BLE GattValueChangedEventArgs.Characteristic.Value missing data

I use windows BLE to connect and read from BLE barcode scanner. Everything works fine while the value I receive from the BLE device is only short string. If I scan a barcode which is more than 16 bytes, the GattCharacteristic.ValueChanged event fires multiple times, and each time I receive a chunk from the data. It would not be problem but I don't receive everything and parts are missing. I use identical method on Xamarin.IOS and the event raised once and I receive 1 long string containing the whole data. So it works in Xamarin.IOS but not in winform.net.
It seems windows uses about 16bytes IBuffer for GattCharacteristic.Value and while it raises the event, that buffer gets cleared and replaced with new data.
Is there any way to increase Windows BLE IBuffer size or tell windows to get the whole data together before raise the event?
What I should receive:
Collection: 1000
From: West Midlands
To: Distribution
RaisedBy: holloway
Raised: 29/09/2021
Item: Camargue 572 4m - hometx44cama
SKU: 26479
Identifier: 174435
SubIdentifier: 21642727-6
Qty: 4.27
What I receive:
Collection: 1000
From: West Mid
land To: Distr
edBy: holloway
ised: 29/09/20
21 Item: Camarg
ue 572 4m
Identifier
: 174435
SubIde
ntifier: 21642
4.27
The code:
CurrentConnectedDevice = await BluetoothLEDevice.FromIdAsync(deviceid);
GattDeviceServicesResult result = await CurrentConnectedDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);
var services = result.Services;
GattDeviceService ScannerService = services.Single(d => d.Uuid == ScannerServiceUUID);
var Characteristics = await ScannerService.GetCharacteristicsAsync(BluetoothCacheMode.Uncached);
ScanCharacteristic = Characteristics.Characteristics.Single(c => c.Uuid == ScannerNotifyUUID);
var status = await ScanCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
ScanCharacteristic.ValueChanged += BarcodeScanned;
private void BarcodeScanned(GattCharacteristic sender, GattValueChangedEventArgs args)
{
byte[] data;
CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
Console.WriteLine(Encoding.UTF8.GetString(data));
}
In the Buffer constructor (link) you can pass the size of the buffer. In your implementation, you are using args.CharacteristicValue as the buffer. If you can control the value of args.CharacteristicValue then you can increase the buffer size, or you can pass in a new Buffer to the CopyToByteArray method.

Serial Communication - Sending Hex Data via Modbus

I am new to using Modbus Communication, and I found some other related threads here but unfortunately, it was for other languages or using TCP rather than RTU connection for Modbus.
So I have this segment of C# code that I can use to send data:
byte address = Convert.ToByte(txtSlaveID.Text);
ushort start = Convert.ToUInt16(txtWriteRegister.Text);
short[] value = new short[1];
if(Int16.TryParse(txtWriteValue.Text, out short numberValue))
{
value[0] = numberValue; //This part works!
}
else
{
value = new short[3] { 0x52, 0x4E, 0x56 }; //This is where I am trying to send letters/ASCII
}
try
{
mb.SendFc16(address, start, (ushort)value.Length, value);
}
catch (Exception err)
{
WriteLog("Error in write function: " + err.Message);
}
WriteLog(mb.modbusStatus);
So when I want to send down a single value, this code works. It will take the short array and dow the following to build the packet:
//Put write values into message prior to sending:
for (int i = 0; i < registers; i++)
{
message[7 + 2 * i] = (byte)(values[i] >> 8);
message[8 + 2 * i] = (byte)(values[i]);
}
So as you can see I attempted to use the hex values in the array, and send them down to the registers.
How can I modify the first sample of code to be able to send down HEX values, and write out characters into the register space in the first image?
I think you are not able to write the character at the device's register.
You need not to store the hex values into the short array. Simply store the characters into array, before writing them into the register convert them into byte.
Note - Whatever data will be written into the devices register, should be in byte.

Sending commands via I2C to PIC16F1503 using Windows 10 IoT Core

Scenario
I want to communicate with a PIC16F1503 controller using C# while running as an UWP app on a Raspberry Pi using Windows 10 IoT Core.
It seems that my source detects the controller using I2cDevice.FromIdAsync(...). But if I try to send the "Servo1" command 0x01 via:
pic16f1503.Write(new byte[] { COMMANDO_SERVO_1 });
pic16f1503.Write(data.ToArray());
Nothing happens. I (hopefully) enabled the "Servo1" with:
private void WriteConfiguration()
{
// Create configuration mask.
byte config = 0;
// Enable servo 1
config |= 1;
// Enable servo 2
config |= 0 << 1;
// Enable lights
config |= 0 << 2;
// Light mode
config |= 0 << 3;
// Light on
config |= 0 << 4;
// Write configuration to device.
pic16f1503.Write(new byte[] { COMMAND_CONFIG});
pic16f1503.Write(new byte[] { config });
}
Full source
GitHub Gist
Does somebody know further tutorials or new "entry" points to get along with C# und this mc? Thanks!
You send several bytes from Raspberry Pi to PIC16F1503 via I2C and I get them via debugging your code: 1, 1, 1, 1-43-7-0-0, 1.
But they seems not all match what you want to send actually because I found a problem in your WriteByte function like:
(You are trying to change a value-type variable: byte[] data. Refer to "Passing Parameters (C# Programming Guide)")
private void WriteByte(byte command, byte[] data)
{
data.ToList().Insert(0, command);
data.ToArray();
pic16f1503.Write(data);
}
I edit above function to this:
private void WriteByte(byte command, byte[] data)
{
var sendData = data.ToList();
sendData.Insert(0, command);
pic16f1503.Write(sendData.ToArray());
}
Then send datas: 0-1, 0-1, 1, 1-43-7-0-0, 0-1
Little issue when print the int array.
Edit this line: Debug.WriteLine($"PIC16F1503 - SetDegrees to {ms} start.\nData: {data}");
To this in order to print the right format data:
Debug.WriteLine($"PIC16F1503 - SetDegrees to {ms} start.\n");
Debug.WriteLine("Data: ");
foreach (var element in data)
{
Debug.WriteLine(element);
}
Debug.WriteLine("\n");
After that you will send right data to PIC16F1503. If still not working please check two devices I2C speed match or not. And hardware pins connection correct or not.

Bluetooth C# using 32feet.net to connect to a speaker

I am currently trying use 32feet.net to connect to a bluetooth speaker that once shutdown (the computer or the speaker) they stay paired but they dont auto reconnect. Therefore I want to make an windows service that tries to reconnect to it every so often if its not connected and if it can find it.
I have tried
C# 32feet.Net: Handling two bluetooth connections in seperate threads, gives SocketException
Code but for some reason there is a few things that light up red.
I am also trying to figure out and make this code work at the same time for the same purpose
public void btconnect()
{
List<Device> devices = new List<Device>();
InTheHand.Net.Sockets.BluetoothClient bc = new InTheHand.Net.Sockets.BluetoothClient();
InTheHand.Net.Sockets.BluetoothDeviceInfo[] array = bc.DiscoverDevices();
int count = array.Length;
for (int i = 0; i<count; i++)
{
Device device = new Device(array[i]);
devices.Add(device);
}
foreach(Device d in devices)
{
if (d.DeviceInfo.ToString().Equals("myphonesdevicenumber"))
{
Guid MyServiceUuid
= new Guid("{00112233-4455-6677-8899-aabbccddeeff}"); // found this somewhere not sure what the string represents.
byte[] guidbytearray = d.DeviceInfo.ToByteArray(); // guid as a byte array.
string guidstring = d.DeviceInfo.ToString(); //guid as a string.
Int64 guid64 = d.DeviceInfo.ToInt64(); // guid as an int64.
Guid g = new Guid(guidbytearray);
bc.Connect(d.DeviceInfo,MyServiceUuid);
// turnoff = false;
}
}
}
List devices = new List();
in the orignal code this wasnt there and I dont know if he was using (Device) it from a external reference or not.
In the article of 32feet, they list an inner-class named Device. You should use it in your program.
The Guid is the identifier for the socket used to connect to your BT device.
The format is a 32 digit long of hex numbers divided into group of 8, 4 ,4 ,4 and 12. Between the groups there is a '-'.

Unable to return same double using Google Protocol Buffers from C# to C++ and back

I'm trying to communicate between C# and C++ with varying amounts of success.
I am able to send a message between the two using reply/request, but the doubles that I am receiving are not correct.
For debugging purposes and understanding, I am currently running the following:
Clrzmq 3.0 rc1, Google ProtocolBuffer 2.5, Protobuf-csharp-port-2.4, ZeroMQ-3.2.3
.Proto
package InternalComm;
message Point
{
optional double x = 1;
optional double y = 2;
optional string label = 3;
}
server.cpp (the relevant part)
while (true) {
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
zmq::message_t reply (request.size());
memcpy ((void*)reply.data(), request.data(), request.size());
socket.send(reply);
}
client.cs (the relevant part)
public static Point ProtobufPoint(Point point)
{
Point rtn = new Point(0,0);
using (var context = ZmqContext.Create())
{
using (ZmqSocket requester = context.CreateSocket(SocketType.REQ))
{
requester.Connect("tcp://localhost:5555");
var p = InternalComm.Point.CreateBuilder().SetX(point.X).SetY(point.Y).Build().ToByteArray();
requester.Send(p);
string reply = requester.Receive(Encoding.ASCII);
Console.WriteLine("Input: {0}", point);
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reply);
var message = InternalComm.Point.ParseFrom(bytes);
rtn.X = message.X;
rtn.Y = message.Y;
Console.WriteLine("Output: {0}", rtn);
}
}
return rtn;
}
On the C# side, Point is a very simple struct. Just x and y properties.
Here is what I'm getting from my unit tests as a result of running the above code.
Input (1.31616874365468, 4.55516872325469)
Output (0.000473917985115791, 4.55516872323627)
Input (274.120398471829, 274.128936418736)
Output (274.077917334613, 274.128936049925)
Input (150.123798461987, 2.345E-12)
Output (145.976459594794, 1.11014954927532E-13)
Input (150, 0)
Output (145.96875, 0)
I am thinking that the problem is my protobuf code is incorrect (doubtful this is a bug on Skeet's side). I am also running under the assumption that server.cpp is doing nothing to the message but returning it as is.
Thoughts?
The requestor.Receive(Encoding.ASCII) call is designed to receive a string, not a block of bytes. You are asking the ZmqSocket instance to return the message as an ASCII string, which is highly likely to cause modifications to the content. If you're sending a byte array, receive a byte array.
Try this:
int readSize;
byte[] reply = requester.Receive(null, out readSize);
var message = InternalComm.Point.ParseFrom(reply);
The readSize variable will contain the actual number of valid bytes in the received block, which may vary from the size of the reply array, so you may need to slice up the array to make it palatable to ProtoBuf.
Why the ASCII --> bytes --> parsing step? If you're parsing bytes, you should read bytes. If you're parsing text, you should read that.
Unnecessary charset-conversions look very likely to be erroneous.

Categories

Resources