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.
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'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'm creating an Arduino based drone that can be controlled through an Android application.
In order to improve the user experience, I'd like to show the accelerometer/compass sensor's values on the application, so I need to send them from Arduino to Android, via Bluetooth. The values are simple integer number between 0 and 180.
The best solution I thought is to concatenate all the values (separated with a comma) in one string, and send it to the app, that will separate the single values (the string will be sent only when the app require it, in this case when a 'z' byte is received by Arduino).
if (Serial.available() > 0) {
if (Serial.read()=='z'){
Serial.println(String((int)sensor1) + ',' + String((int)sensor2) + ',' + String((int)sensor3));
}
}
Here are the App Inventor blocks:
It seems that the values are being received quite well, but there is a critical issue: somethimes the string is not received well, and that cause a lot of errors. Sometimes the received string is (for example) 10,10,10, but somethimes it is 10,10,1010 or just 10,10 ecc...
I also tried to send the values one by one, but the result was nearly the same.
I even tried to set 'numberOfBytes' to -1, using a delimiter byte, but this also was not succesful unfortunately.
I getting quite mad, so I hope there is another way to send thoose integers to Android, or to fix the system I'm already using.
I used Serial.print to send each result and then used Serial.write('>'); as the end marker.
In appinventor designer window set the Delimiter byte for Bluetooth client to 62 (the ASCII value for the > character ).
In the blocks window, use Bluetooth cliant1.Receive text and set number of bytes to -1
App invented will then read until a delimiter is found.
However it will cause the app to hang if it doesn't find one.
the problem is that you are not signaling the end of the string
I used his example on a project and was something like this:
while(Serial.available()>0){
Serial.println(String((int)Sensor1) + ',' + String((int)Sensor2)+ ',');
}
If you compare the two codes the difference will be a " , " the most at the end of the print and it solved the problem for you sitad
I have an android app that is essentially a list of timers. Each timer can have the following fields:
title (string, can be up to 255 characters)
id (integer)
seconds (integer)
time_started (integer)
seconds_left (integer)
running (boolean)
order (integer)
There can be an unlimited number of these timers, though for the pebble watch app, it'd be ok if I only send the first n (10, 15, 20).
Currently I've been sending the items to the watch one at a time, and creating the PebbleDictionary like this:
private PebbleDictionary buildTimerDictionary(Timer timer) {
PebbleDictionary data = new PebbleDictionary();
data.addUint32(C.KEY_ID, timer.getId());
data.addUint32(C.KEY_SECONDS, (int)timer.getSeconds());
data.addString(C.KEY_DESCRIPTION, timer.getDescriptionFormatted());
data.addUint32(C.KEY_TIME_STARTED, (int)timer.getTimeStarted());
data.addUint32(C.KEY_TIME_LEFT, (int)timer.getSecondsLeft());
data.addUint8(C.KEY_RUNNING, (byte)(timer.isRunning() ? 1 : 0));
data.addUint32(C.KEY_ORDER, (int)timer.getOrder());
data.addString(C.KEY_TIME_DISPLAY, timer.getSecondsFormatted());
return data;
}
And sending it via a queue that sends the next PebbleDictionary to the watch after the previous is acked.
This works, but it's pretty slow. I feel like I could save a lot of time by packing more than one timer into each message. However, I'm not sure how to do that, considering the inbox size on the pebble watch itself, and the fact that you have to hard define the keys for the dictionary in appinfo.json (it doesn't seem like you can use arbitrary keys).
How is this sort of thing usually done?
There are two ways to do this:
One message for each item (what you are doing now)
Multiple items per message.
In this case you can pack everything into one value by using byte arrays and concatenating all your fields into the byte array.
You can then use the key to send the index of the element in the list.
A few comments:
Defining the keys in appinfo.json is optional and only useful if you are using PebbleKit JavaScript. It has absolutely no use for apps that talk with PebbleKit Android.
You can query the available buffer size on Pebble with app_message_inbox_size_maximum(). Get it when you start your app and send it from Pebble to the Android app.
The best strategy depends on the average size of your messages. Right now your items will be about 25bytes + the strings + the small overhead of a dictionary (7 bytes + 1 byte per key). If the strings are very small you might fit three items per messages, if the description is very long, you might not be able to send the item at all (you should probably truncate it).
I want to make a custom sipdroid client by using reverse byte order. I think that makes other Voip clients cannot decode these data.
So I read the code of the SipDroid. I found RTP data goes this way:
1. AudioRecord.read(originalPCM)
2. encode(originalPCM, encodedData)
3. rtp_socket.send(rtp_packet) //the encodeData is rtp_packet's data part
And the other side is:
1. rtp_receive(rtp_packet)
2. decode(encodeData, PCMData) //the encodeData is rtp_packet's data part
3. AudioTrack.write(PCMData)
So I modified the SipdroidSocket class. In send method, I add the following code at the beginning.
byte[] b = pack.getData();
reverse(b);
pack.setData(b);
And add the following code at the end of the receive method.
byte[] b = pack.getData();
reverse(b);
pack.setData(b);
I think in this way, the two client can work as usual. But it failed. And I don't know the reason. Please help me to find out why. Thanks.
You should not reverse the hole buffer unless you receive 2,4,8 bytes at a time.
You should treat the data as elements of 2,4,8 bytes depending on how the data
were stored. The code i see here will not work.
suppose you have a buffer of data bytes 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
stored as 4 byte elements of 0x04030201-0x08070605.
Reversing the hole buffer will produce 0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01
which is wrong because you will end up with 0x05060708-0x04030201
If you reverse one element(4 bytes) at a time.
Keep in mind that the size of an element depends on how the values were stored