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.
Related
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 :)
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.
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).
Thanks for reading this question. I am sure the experts on this site will be able to provide the help I need.
I am trying to write an app which allows users to edit the exif information of the photos on their Android Phone.
As a part of improved user experience, I want to apply data validation where ever possible.
For the Exif Tag - TAG_GPS_PROCESSING_METHOD I am not able to apply the validation correctly.
Here is the part of code that I have applied :
String strGPSProc = etGPSProc.getText().toString();
if(strGPSProc.equalsIgnoreCase("GPS") || strGPSProc.equalsIgnoreCase("CELLID") || strGPSProc.equalsIgnoreCase("WLAN") || strGPSProc.equalsIgnoreCase("MANUAL") ) {
returnValue = true;
}else {
returnValue=false;
showToast("Incorrect value for GPS Processing Method. Correct value options are GPS, CELLID, WLAN or MANUAL.");
etGPSProc.requestFocus();
}
This code checks if the value entered in the EditText meant for GPSProcessingMethod, has any one of the four prescribed value as described in the documentation of EXIF.
But when I try to save this using setAttribute() and saveAttributes() functions, a non catch-able exception appears in logcat.
Unsupported encoding for GPSProcessingMethod
I understand from Exif Documentation that values for GPSProcessingMethod needs to be stored with some header information.
I need some expert advise on how to implement this correctly, with out using any other 3rd part classes.
Accoridng to the Exif specification:
GPSProcessingMethod
A character string recording the name of the method used for location finding. The first byte indicates the character
code used (Table 6、Table 7), and this is followed by the name of the method. Since the Type is not ASCII, NULL
termination is not necessary
Atually, Table 6 lists the character codes as 8 byte sequences, so the above should probably read "The first bytes indicate...". Anyway, the character code designation for ASCII is defined as 41.H, 53.H, 43.H, 49.H, 49.H, 00.H, 00.H, 00.H., Unicode is (unsurprisingly) 55.H, 4E.H, 49.H, 43.H, 4F.H, 44.H, 45.H, 00.H. I guess these should be all you need.
Hope that helps.
EDIT:
Just discovered that ExifInterface.setAttribute() only supports String values... You could try encoding the value at the beginning of your string, but I doubt that would work. Sounds like the encoding should be handled by the setAttribute() or saveAttributes() method. Could it be a bug in the API? I had a look at the source code, but the actual writing of values is done by native code so I stopped digging further.
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.