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).
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
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 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