I am using the ArduinoBLE library to create a service and characteristic:
BLEService angleService("1826");
BLEFloatCharacteristic pitchBLE("2A57", BLERead | BLENotify);
I add the services and characteristics and advertise my device:
BLE.setLocalName("acsAssist");
BLE.setAdvertisedService(angleService);
angleService.addCharacteristic(pitchBLE);
BLE.addService(angleService);
pitchBLE.writeValue(0);
BLE.advertise();
I perform some calculations and then write my calculated value to the service:
pitchBLE.writeValue(posiPitch);
posiPitch is a float value, like 1.96 for example. it can go from -90.00 to 90.00
I try to read this value from my Android app:
(characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT,0))
I get crazy numbers such as -1.10300006E9.
How can I read my float value so that my android app value matches that of the arduino value?
I ran into a similar issue. Instead of using getFloatValue(), I used getValue() which returns a byte array.
The reason for the weird numbers is that the byte order in which arduino stores data is different from that of java.
To change the order use byteBuffer:
byte[] b = characteristic.getValue();
float f = ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getFloat();
This post helped me: How to convert 4 bytes array to float in java
I have simplified the situation drastically by utilizing a string characteristic instead.
Although this is probably more resource intensive, it reduces the headache of having to parse through a byte array to convert the data into what I want.
My string characteristic is made with a custom UUID (to avoid Bluetooth GATT standard conflicts):
BLEStringCharacteristic pitchBLE("78c5307a-6715-4040-bd50-d64db33e2e9e", BLERead | BLENotify, 20);
After I advertise and perform calculations as shown in my original post, I simply write to my characteristic and pass in the value as a string:
pitchBLE.writeValue(String(posiPitch));
In my Android application, I simply get the characteristic's string value:
characteristic.getStringValue(0)
I hope this will help future developers like me who are struggling to find clearer resources on information such as this :)
Related
I'm using a BluetoothLeScanner present in Android API levels 21+. In the onScanResult(int callbackType, final ScanResult result) of ScanCallback. I want to get the bytes of the manufacturer specific data from the advertisement frame.
When I do a result.getScanRecord().getManufacturerSpecificData(2), I get a byte[] array of the company with 16 bit Id of 0x0002 which can be directly logged as a hex string of the form [B#5db845a.
I use an nRF Connect Android app on another phone and from there Advertise with company Id 0x0002 and some fixed other bytes of data.
However, my BluetoothLeScanner phone sees the above-said bytes like [B#5db845a continuously changing in the logged output. There is no other device advertising with same company Id close by. I even changed the company Id to 0x0006 and tried.
Why are these bytes changing? I need to take some decision in my app based on fixed bytes in this data. Am I missing something?
Answering my own question after finding something that works:
I did some reading on this and then while searching online for something else related to the same project and which also dealt in a byte array and hex string I stumbled upon something. I can't remember the link of the question to cite it but it went something like:
Dumping the result.getScanRecord().getManufacturerSpecificData(2) directly in the log doesn't give an error but it actually doesn't get cast or dumped properly as a string.
You need one of the following 2 methods to observe the data properly:
finalString = new String(byteArray) .eg. new String(result.getScanRecord().getManufacturerSpecificData(2)) This will give an o/p log like �B��u����j�oL. But, you'll have to go online and use raw string to hex string converters to check it. But, there is a catch that online converters may have a different complement system and may consider null bytes as 0xFF instead of 0x00. So, 0x000000030503 may become ...ff3f5f3. Or else you can see the integer value at each element in the byte array using the below
finalString = Arrays.toString(byteArray) .eg. Arrays.toString(result.getScanRecord().getManufacturerSpecificData(2)). This gives an o/p [0, 0, 0, 3, 5, 3]. Although and int[] array but you can always check integer to hex values online for each element in this array.
I have a program on micro-controller (uC) which send data in intmax_t format (my goal is to send 19 bytes). I'm receiving on my Android app value which is send from uC (I'm sending data through Bluetooth Low Energy module). Then I'm parsing this value and putting it as Double. Here it is my code for this operations:
byte[] bytes = characteristic.getValue();
String val = new String(bytes);
String[] couple = val.replaceAll("\r\n","\n").replaceAll("\n\r","\n").replaceAll("\r","\n").split("\n");
double dValue;
for (String aCouple : couple) {
if (aCouple != null && !aCouple.isEmpty() && !aCouple.equals("\n")) {
dValue= Double.parseDouble(aCouple);
PlotUtills.addNextSample(dValue);
}
}
My question is what is the biggesest number that LineChart from AndroidPlot can handle? Maybe something is incorrect in my conversion?
My question is what is the biggesest number that LineChart from AndroidPlot can handle?
Anything that fits into a Java Double will work. Beyond that, the details of your specific issue are unclear. What are you expecting to see happen and what are you actually seeing happen? Are exceptions being thrown?
I am using RN4020 BLE hardware. Form my hardware, the characteristic.getValue() will return 20 bytes chuck at a time. The hardware will spit the notifying data if the data exceed more than 20 bytes. I don't know whether it a hardware specific.
For example, if the hardware sent 36 bytes information into the application through notification. The application will get two notification with the first chunk as 1-20 bytes and the second chunk as 21-36. I hope this will help you.
So i want to use the MessageApi and not the DataApi to send multiple items to the wearable. However the sendMessage() of the MessageApi only allows a byte array to be sent.
For reference:
Wearable.MessageApi.sendMessage(mGoogleApiClient,
String id,
String path,
byte[] bytes)
My guess would be to create an array of byte arrays and then serialize that into one big byte array and send it off.
To make things clearer these are the steps in pseudo code:
byte[][] arrayOfByteArrays;
String a --> convert to byte[];
Bitmap b --> convert to byte[];
Add a and b byte[]'s to arrayOfByteArrays;
Serialize arrayOfByteArrays to just a byte[] and send it off;
Is this the correct approach? or Should I just call sendMessage() multiple times? Thanks.
In general, it is more efficient (battery, bandwidth, ...) to send one message instead of multiple ones. However, there may be other factors involved in your specific case that may warrant sending multiple messages. Looking at your pseudo code, I noticed you are also trying to send a bitmap using the MessageApi. That, in general, is not the best approach to send across an image, or other types of assets; you can use Assets or you can use ChannelApi. Otherwise, the approach of serializing a bunch of small objects and putting them into one byte array and then desrializing at the other end would work; one simple way to do so (if dealing with simple objects) is to use json as a serialization means.
I am developing an android app where I want to read serial data via the phone's port(I use OGT cable). For this I have been using the following libray
https://github.com/mik3y/usb-serial-for-android
Library would read serial data as a byte array where I want to read it as an integer value between 0-255. Reason to do this is, I have been using "read()" method of the Inputstream in "java.io.InputStream".
Here the read method would return an int evenn though it reads them as bytes.
Now I am trying to port this code to an android app, but I could not find a method to read integer from the serial input.
I tried converting the byte to int using the following code
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1
Where "arr" is the byte array read from the serial input. But this made the app crash in between and the numbers were not something in between 0-255.
I can not change my requirements of "integer values between 0-255" since there is a whole project built on this logic in the pc using Java.
Any suggestions to solve this?
Use Byte(arr[0]).intValue() (using index 0 just as an example).
I'm a little confused about how to send data over a Bluetooth connection. In the Android API documentation, from the Bluetooth Chat example, the class BluetoothChat.java constructs a Handler object. Within there is a switch statement, and a MESSAGE_WRITE case. Do I need to implement similar code to send Strings over Bluetooth? A case statement for each String I want to send? In particular I want to send (name,value) pairs so I know what is sent and what it's value is. How do I implement this? If, following the example, I call BluetoothChatService.write(String.getBytes()) a bunch of times to send...? Then how would I know which strings are associated with which names? Please help.
I'm using Google's Protocol Buffers to send structured data over bluetooth connections in my Android app. protobuf takes care of figuring out how to serialize the message for you so that you only have to send a byte value (length of the message) and then the serialized message; the library takes care of unserializing the message on the other end and populating the fields of a custom object. Definitely take a look at it; it made the writing of a custom bluetooth socket protocol quite easy.
Serialize pairs to any of formats which allows byte representation. Such as XML or JSON. Or even your custom format, it wouldn't be difficult for pairs of strings. And then send it.
For simple pairs of strings (Such as names), you could simply use some character to define when the first string stops, and the next begins.
For example, I use a format such as this to send a set of 3 strings from one device to another:
String toSend = partOne + ":" + partTwo + ":" + partThree;
On the other device, to get the strings you sent, use the String.split() method like so:
String parts[] = received.split(":",3);
The 2nd parameter is a limit to how many times to split. In this example, there are 3 strings, so split 3 times max.
The downside to doing this is that you need to use characters that will never be in all but the last string.
In my application, I used this method to send data about text messages, and the first 2 parts are the phone number and timestamp, so there can never be a : in it. For names, a newline would probably work.
If your going to send more complex data, definitely use something like Protocol Buffers.