Why is data from Arduino to Android using Android host api garbled? - android

I followed this tutorial to get started using Android host api with an Arduino board. I am using the Arduino Uno. I am able to transmit data and turn on a LED on the Arduino board and I can receive feedback from the Arduino board. I am trying to write to my Android device over the USB connection from the Arduino board like so:
Serial.print("Test");
I am receiving the Arduino data on the Android side like this:
byte[] buffer = new byte[10];
int bytes;
//try-catch statements omitted for simplicity
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
Every once and awhile the data will be intact but more often than not, what I receive from the Arduino is a garbled mix of those letters from my original message(t,e,s, and t). Many times only 1 or 2 letters are displayed. If anyone could point me in the right direction or share some similar experience I would be appreciative. Thanks.
Edit
When I print out the data into Logcat, there are multiple copies of the data. For example, if I receive "ste" from Arduino, it will be printed out 2-5 times in Logcat.

I think I found something that works at least temporarily:
public void run(){
int i = 0;
byte[] buffer = new byte[4];
byte[] finalBuffer = new byte[8];
byte[] sendBuffer = new byte[8];
int bytes = 0;
while(true){
try{
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
if (bytes == EXIT_CMD) {
return;
}
if (bytes > 0){
byte[] temporaryBuffer = new byte[bytes];
System.arraycopy(buffer, 0, temporaryBuffer, 0, bytes);
System.arraycopy(temporaryBuffer, 0, finalBuffer, i, bytes);
i += bytes;
java.util.Arrays.fill(buffer, (byte) 0);
}
//Dollar sign terminates string to indicate end of line
if (finalBuffer[7] == 36){
i = 0;
System.arraycopy(finalBuffer, 0, sendBuffer, 0, sendBuffer.length);
messageHandler.obtainMessage(UsbHostTestActivity.ARDUINO_MESSAGE,
sendBuffer.length, -1, sendBuffer).sendToTarget();
java.util.Arrays.fill(finalBuffer, (byte) 0);
}
I had to send strings that were 8 characters exactly from Arduino and they had to end with a dollar sign($) in order to indicate the end of the line, but the data being passed to my message handler always seemed to be correct. It's not the most robust solution but maybe someone can modify it to make it better or take another approach? Please let me know!

Related

Android USB host : interrupt do not respond immedietly

I have a usb device which have a button.
And I want to an android app to catch a signal of the button.
I found inferface and endpoint number of the button.
It had seemed to perform ordinarily at galaxy S3 and galaxy note.
But later, I found that it has delay at other phones.
I was able to receive instant responses about 10% of the time; usually there was a 2-second delay, with some cases where the whole response was lost.
Although I couldn't figure out the exact reason, I realized that the phones that had response delays were those with kernel version 3.4 or later.
Here is the code that I used initially.
if(mConnection != null){
mConnection.claimInterface(mInterfaces.get(0), true);
final UsbEndpoint endpoint = mInterfaces.get(0).getEndpoint(0);
Thread getSignalThread = new Thread(new Runnable() {
#Override
public synchronized void run() {
byte[] buffer = new byte[8];
final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
while(mConnection!=null){
int len = mConnection.bulkTransfer(endpoint, buffer, buffer.length, 0);
if( len>=0 ){
// do my own code
}
}
}
});
getSignalThread.setPriority(Thread.MAX_PRIORITY);
getSignalThread.start();
}
edit timeout
when the timeout was set to 50ms, I wasn't able to receive responses most of the time. When the timeout was 500ms, I was able to initially get some delayed-responses; however, I lost all responses after several tries with this setting.
Using UsbRequest
In addition to using the bulktransfer method, I also tried using UsbRequest and below is the code that I used.
#Override
public synchronized void run() {
byte[] buffer = new byte[8];
final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
UsbRequest inRequest = new UsbRequest();
inRequest.initialize(mConnection, endpoint);
while(mConnection!=null){
inRequest.queue( byteBuffer , buffer.length);
if( mConnection.requestWait() == inRequest ){
// do my own code
}
}
}
However, the same kind of delay happened even after using UsbRequest.
Using libusb
I also tried using libusb_interrupt_transfer from an open source library called libusb.
However this also produced the same type of delay that I had when using UsbDeviceConnection.
unsigned char data_bt[8] = { 0, };
uint32_t out[2];
int transfered = 0;
while (devh_usb != NULL) {
libusb_interrupt_transfer(devh_usb, 0x83, data_bt, 8, &transfered, 0);
memcpy(out, data_bt, 8);
if (out[0] == PUSH) {
LOGI("button pushed!!!");
memset(data_bt, 0, 8);
//(env)->CallVoidMethod( thiz, mid);
}
}
After looking into the part where libusb_interrupt_transfer is processed libusb, I was able to figure out the general steps of interrupt_transfer:
1. make a transfer object of type interrupt
2. make a urb object that points to the transfer object
3. submit the urb object to the device's fd
4. detect any changes in the fd object via urb object
5. read urb through ioctl
steps 3, 4, 5 are the steps regarding file i/o.
I was able to find out that at step 4 the program waits for the button press before moving onto the next step.
Therefore I tried changing poll to epoll in order to check if the poll function was causing the delay; unfortunately nothing changed.
I also tried setting the timeout of the poll function to 500ms and making it always get values of the fd through ioctl but only found out that the value changed 2~3 seconds after pressing the button.
So in conclusion I feel that there is a delay in the process of updating the value of the fd after pressing the button. If there is anyone who could help me with this issue, please let me know. Thank you.
Thanks for reading

Getting data back from bytes

I am continuously getting data from remote bluetooth device which I am storing in a buffer readBuf.
I copy this readBuf to buf.
System.arraycopy(readBuf, 0, buf, 0, readBuf.length);
Now my buf contains data such that -
buf[0] == 0x7D
buf[1] == 0x51
buf[2] == 0x42
...and so on...
I want to log this data to know what is coming from remote bluetooth device.
I tried,
Log.i(TAG, "Buffer Data---- "+Arrays.toString(buf));
But it is not giving data correctly to be 7D 51 42 and so on....
How to get the data in order to log ?
This is working fine -
StringBuffer bufData = new StringBuffer();
for(byte b : readBuf)
{
bufData.append(String.format("%02X", b));
bufData.append(" ");
}
Log.i(TAG, "Data Coming from Remote Device---"+bufData.toString());
Arrays.toString(byte[])
Works fine, although what you are seeing is an signed integer representation of each byte. That's because in Java all integers are signed with a Two's Complement .
You can learn a lot on how to convert bytes to hex in this answer.

Sending USB commands using usbmanager api to thermal printer

Hello I am using the following printer and emulation commands from the following doc:
http://www.hengstler.com/gfx/file/shop/printer/eXtendo_X-80/D-684-112_EmulationCommandSetReference_eXtendo-E-V1_07.pdf
I doing this in Java using the Android USB Manager class like so:
....
public void printData(String str, int characterSize, int startPos){
Log.d(TAG, str);
final String character = str;
setCharSize(characterSize);
startPage(startPos);
if(character != null){
Thread t = new Thread(new Runnable() {
#Override
public void run() {
byte[] bytes = character.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
UsbRequest req = new UsbRequest();
req.initialize(mConnection, ep);
req.queue(buffer, bytes.length);
if(mConnection.requestWait() == req){
buffer.clear();
endPage();
} else{
Log.d("USB", "No USBRequest received");
}
}
});
t.start();
}
}
public void endPage(){
Thread t = new Thread(new Runnable() {
#Override
public void run() {
byte[] array = new byte[]{29,(byte)240,06,1,20};
ByteBuffer buffer = ByteBuffer.allocate(array.length);
buffer.put(array);
UsbRequest req = new UsbRequest();
req.initialize(mConnection, ep);
req.queue(buffer, array.length);
if(mConnection.requestWait() == req){
buffer.clear();
} else{
Log.d("USB", "No USBRequest received");
}
}
});
t.start();
}
....
This all works great, I am able to print, use line feeds, set font/char sizes...etc. The only methods I am having trouble with is the one above (endPage function) which is supposed to cut the paper (see PDF above).
This is in the PDF:
2.1.18 ESC [F0]+[06]+[x]+[n]+[m] End of page
Page 27
This does not seem to do anything. I thought maybe I needed to use the controlTransfer instead and perhaps endpoint0 (which I have captured in an endpoint as well) but this doesn't do anything either. Does anyone see an obvious issue with how I'm sending this particular command to the device? This is the first time using the USB Manager / Device API and Transfers so I'm not super familiar with it. Since the other functions work, I'm hoping it may be an easy find/fix for someone more familiar with the USB interface / Communication.
UPDATE
The PDF has some errors I think, the function for cut says 29 but 1B^16..obviously incorrect, so I've also tried like this:
char[] initEP = new char[]{0x1B, 0xF1, 0x01, 0x03, 0x0A, 150};
char[] cutP = new char[]{0x1B,0xF0,0x06,01,10};
String Ptxt= new String(initEP)+ " text data \n \n \n"+ new String(cutP);
byte[] array = Ptxt.getBytes();
Still nothing. Also, the initial setup (page size) doesn't seem to do anything anyway, which leads me to believe there is an issue with the ESC??
In your code above, the command for initiating a full cut should be ...
char[] cutP = new char[]{0x1B, 0xF0, 0x06, 1, 2}
... and, in case your printer is capable of doing partial cuts, then it should be ...
char[] cutP = new char[]{0x1B, 0xF0, 0x06, 1, 1}
According to support from the manufacturer, the following is correct (and works for me):
byte[] array = {0x1B,(byte)0xF0,0x06,01,01};
The char[] array was not working I had to use a byte[] array for the cut to work and send the print data in a previous buffer. Here are the correct values:
End of print ->02
hex
0x02 = full cut
0x01 = partial cut
0x12 = intermediate full cut
0x11 = intermediate partial cut

Byte Dropped Over Bluetooth Connection in Android

I am having some issues with bytes being dropped over a bluetooth connection between an android device (Gingerbread 2.3.1) and a PC. The way I receiving the data is in a 2 byte buffer. The values being received is streaming from the PC over a few minutes (values represent a waveform). Here are just a few snippets of code so you can get the idea. The base of my code is from the android bluetooth chat sample code.
BluetoothSocket socket;
...
mmInStream=socket.getInputStream;
...
byte[] buffer= new byte[2];
...
bytes = mmInStream.read(buffer);
Has anyone has issues with this type of thing? The dropped bytes seem to happen at random times while at other times the values received are as expected. I am using a 2 byte buffer because the values I am receiving are 16 bit signed integers. From the PC side of things I am using RealTerm to send the binary files of data.
Is it possible that my buffer is too small and that is causing the dropped bytes?
Thanks
Following up to your answer. You could just use a counter to remember how many bytes already read and compare it to the number wanted and also use it for the index to write the next byte(s). See a C# version at http://www.yoda.arachsys.com/csharp/readbinary.html
public static void ReadWholeArray (Stream stream, byte[] data)
{
int offset=0;
int remaining = data.Length;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
}
}
I have found what the issue is. I want to thank alanjmcf for pointing me in the right direction.
I wasn't checking by bytes variable to see how many bytes were returned from the mmInStream.read(buffer). I was simply expecting that every buffer returned would contain 2 bytes. The way i solved the issue was with the following code after getting the buffer back from the InputStream:
//In the case where buffer returns with only 1 byte
if(lagging==true){
if(bytes==1){
lagging=false;
newBuf=new byte[] {laggingBuf, buffer[0]};
ringBuffer.store(newBuf);
}else if(bytes==2){
newBuf=new byte[] {laggingBuf, buffer[0]};
laggingBuf=buffer[1];
ringBuffer.store(newBuf);
}
}else if(lagging==false){
if(bytes==2){
newBuf = buffer.clone();
ringBuffer.store(newBuf);
}else if(bytes==1){
lagging=true;
laggingBuf=buffer[0];
}
}
This fixed my problem. Any suggestions on a better methodology?

Android getInputStream() does not retrieve all bytes, but only sporadically

First, I have a class that extends AsyncTask. Then in the doInBackground() method, I have some code that posts an HTTP post message, and gets a response. This response is read into a string as follows:
DataInputStream dis = new DataInputStream(conn.getInputStream());
byte[] data = new byte[32768];
len = dis.read(data, 0, 32768);
if (len > 0)
{
response = new String(data, 0, len);
}
At this point, response should be 4127 bytes (as confirmed by the server). 1/5th of the time it IS 4127 bytes. 2/5 of the time it's 1205 bytes, and 2/5 of the time it's 3853 bytes. I can close the app, reinstall, and I get the same variation.
The person who manages the server logs everything and can confirm the same data is being sent over and over. But Android isn't getting the full stream. This is wireless, not 3g. When I use the debugger, I can see that the string returned is always identical, just chopped off at a random spot.
Sorry for such a vague (stupid?) question, but I've been looking at this for hours and I can't see what's wrong with it...
The read method documentation says: Reads up to len bytes of data from the contained input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read, possibly zero. The number of bytes actually read is returned as an integer.
Depending on different conditions, sometimes you can read all server-sent data, sometimes there is a short-read. In order to get all data you should keep reading the stream in a loop until len is -1, indicating an EOF.
InputStream in = ...;
byte[] dst = new byte[32768]; /* Assuming total len is < 32768 */
int idx = 0;
do {
int len = in.read(dst, idx, 32768 - idx);
idx += len;
} while (len >= 0 || idx < 32768);

Categories

Resources