Hang-up on TCP socket send call in Android native code - android

I have a problem with socket send (or write) function on android.
There is my network lib that I use on Linux and Android. Code is written in C.
On Android, application creates a service, which loads a native code and creates the connection with the help of my network lib. Connection is the TCP socket. When I call send (or write, no difference), code hangs in this call in most cases. Sometimes, it unhangs after 10-120 seconds. Sometimes, it waits longer (until I kill the application). Data size being sent is about 40-50 bytes. First data sending (handshake, 5 bytes) never hangs (or I am just lucky). The hanging send is, usually, next after handshake packet. Time between this first handshake packet sending and hanging sending is about 10-20 seconds.
The socket is used on another thread (I use pthread), where the recv is called. But, I do not send data to Android in this time, so recv is just waiting when I call send.
I am sure that other side is waiting for the data – I see that recv on other side returns with EAGAIN every 3 seconds (I set timeout) and immediately calls recv again. Recv is waiting 10 bytes always (minimal size of packet).
I am unable to reproduce this behavior on Linux-to-Android transfer or Linux-to-Linux, only on Adnroid-to-Linux. I am able to reproduce this with two available to me different Android devices, so I don’t think this is the problem in broken hardware of one particular device.
I tried to set SO_KEEPALIVE and TCP_NODELAY options with no success.
What can issue the hang-up on send/write calls and how can I resolve this?
Socket created with this code:
int sockfd, n;
addrinfo hints, *res, *ressave;
bzero(&hints, sizeof(addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
{ /* stripped error handling*/ }
ressave = res;
do
{
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) continue;
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
{
break; /* success */
}
close(sockfd); /* ignore this one */
} while ((res = res->ai_next) != NULL);
Hanging send operation is:
mWriteMutex.lock();
mSocketMutex.lockRead();
ssize_t n = send(mSocket, pArray, size, 0);
mSocketMutex.unlock();
mWriteMutex.unlock();

The problem is solved with the help of Nikolai N Fetissov in commentaries - his right question has unblocked my mind and I found a problem in RWMutex.

Related

Bluetooth Low Energy (between ESP32 and Android smartphone): Data transmission quite slow

This is my first question ever asked on this board
The project explained short:
5 sensors, connected with an esp32 board are transmitting 1000 samples/second, each sample has 16 bit. Those values should be transmitted via BLE (With the BLE Arduino library and an ESP32). The connected device (Smartphone) should read those values and do something with them (Also via BLE, with the following library: https://github.com/RobotPajamas/Blueteeth). The ESP32 is the Server! Java is used in Android Studio!
The problem:
While testing the BLE connection a simple "hello world" was transmitted as the value for a characteristic. Every time i received the "hello world" on the android-device-side, a variable was incremented: The problem is, the variable only got incremented 4 times in one second. This means (assuming 1 char in a string equals 1 byte) 11byte*4(1/s)=44byte/s are being transmitted. -> This clearly is not enough (should not BLE transmit ~2MBit/s (minus the protocol-data))
Code Fragments
ESP32: BLE-Server that transmits value
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("MyESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
Android Studio Code (Snippet of the receiving source):
try
{
while(sampleBluetoothData)
{
this.selectedDevice.readCharacteristic(MainActivity.characteristicUUID, MainActivity.serviceUUID, (response, data) ->
{
if (response != BlueteethResponse.NO_ERROR) {
return;
}
Log.d("AUSGANG", new String(data) + "times: "+ i);
i++;
});
}
}
catch (Exception e)
{
e.printStackTrace();
}
The write on the ESP32 side is a blank example code of the Arduino IDE, the read on the Android-side is made by the BLE-Library publisher. Yes the Log.d effects the performance, but it does not drop it that much.
The variable "data" of the Android code is the received char-array. The bluetooth-reading runs on a background thread.
Question I ask myself now:
Is the Android-Studio library the problem or the Arduino library
Is this a normal behaviour, that if a value of a characteristic does not change, it is being transmitted quite slowly.
How fast can you update a value of a characteristic
Thank you in advance!
BLE can definitely transfer much more than 4 portions of 11 bytes per second.
Approach of reading:
Generally, continuos reading all the time is NOT the expected BLE way - it's better to subscribe to data changes, so ESP32 will notify only when needed (e.g. do selectedDevice.subscribeToCharacteristic once, instead of reading in a loop, but then ESP32 code should be changed accordingly)
I guess selectedDevice.readCharacteristic requests asynchronous BLE read, and when you call it in while(sampleBluetoothData), your Bluetooth library is adding more and more read requests. Maybe it would be wise to request new read only after the previous read is done - in read callback add if(sampleBluetoothData) { this.readAgain(); }
Consider making a testing prototype from this kickstart example: BLEProof on github - Android & ESP32, read, write, notify (but it uses just system API without Bluetooth library, you approach is better, it's easier and safer to use the library).
What else to check:
Android side: are you sure that your code doesn't go inside of if (response != BlueteethResponse.NO_ERROR) ?
Android side: to ensure Bluetooth library is not overloaded with read requests, try adding a delay 50 milliseconds in the reading loop (just to check, it's not a solution)
Android side: are you sure that you don't have other BLE read/writes while you read those data?
ESP32 side: use shorter BLE connection interval (BLE throughput article) - add pAdvertising->setMinPreferred(0x06); and pAdvertising->setMaxPreferred(0x20); before pAdvertising->start(); (but that sets only "preferred" interval, Android may ignore that)
Using read requests, you are mainly limited by the connection interval for transfer speeds - that is 2 intervals for request + response.
If for example your client has a connection interval of 50ms, you should expect to read a characteristic of up to 20 bytes 10 times per second.
If another client has a connection interval of 30ms, this rate improves to 16.6 reads per second.
The fastest negotiatiable connection interval is 7.5ms for a maximum of 66.6 reads per second (10.7kbps with 20 byte reads).
I was reading BLE wikipedia page and the minimum data rate is 125Kbit/s , so I think that in your case is viable, because you only will transmit 16Kbit/s. Take a look in BLE wikipedia.

Android - Arduino Communication - USB Host

I'm building an android - arduino communication setup with the android USB Host API. Everything is working quite well. The Arduino reads a message and changes some LED and sends back the received byte.
The Problem is the reading of the echo from the arduino. Every second answer reads 0. The Bulk transfer call terminates sucsefull but only receives a zero. The next read returns the character that was expected in the previous reading. For Example:
Sending|Receiving
a a
b 0
a b
x 0
I cant put my finger on what is happening there. Maybe someone can see a mistake? Another Question is regarding the control transfers used (below) I found those on various threads for different ubs/serial converter. Can anyone tell me where to obtain details about those codes and where to find them in datasheets?
My setup:
I'm using an Arduino Uno rev. 3 and android 5.xx
Basic Arduino Code: LED reacts to every sent char.
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
char incomingByte = Serial.read();
Serial.print(incomingByte);
if( incomingByte == 'a' )
digitalWrite( ledPin, HIGH );
else if( incomingByte == 'b' )
digitalWrite( ledPin, LOW );
}
}
Android Code: I removed try/catch, and Debugging stuff and everything unrelated. The code is executed in a separate thread. The "synchronized (sSendLock)" part locks the process until the UI thread gives a "notify". The handler used, just tells the UI Thread, that the value is ready.
The control transfer at the beginning is taken out of a blogpost and seemed to work for the UNO.
usb_connection.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
usb_connection.controlTransfer(0x21, 32, 0, 0, new byte[] { (byte) 0x80,
0x25, 0x00, 0x00, 0x00, 0x00, 0x08 }, 7, 0);
usb_connection.controlTransfer(0x40, 0x03, 0x4138, 0, null, 0, 0);
for (;;) {
(...) synchronized (sSendLock) {
SendLock.wait(); // Thread waits, until notified
(...)
byte_buffer = new byte[1];// initialize buffer
byte_buffer[0]=(byte) data; //get data to send
usb_connection.bulkTransfer(endpOUT,byte_buffer,byte_buffer.length, 200); //send
usb_connection.bulkTransfer(endpIN,byte_buffer,byte_buffer.lenght,200);//receive
usb_connection_handler.sendMessage(Message.obtain(usb_connection_handler, 0));//notify UI Thread
}
Any ideas?
Thanks :-)
EDIT:
I changed the code so that just one bit is read. It read 5 bits before in order to test for more to receive. This did not change the behaviour. The send function looks like this:
public void send_char(char b) {
data =(byte) b;
synchronized (sSendLock) {
sSendLock.notify();
}
I hope the shown extract of code is enough. If there are any question I'll be happy to provide more information :-)
I really dont know how to explain that behaviour.
EDIT III: Just to collect information from the comments:
The bulk transfer function returns -1, if the transfer failed, and if successful, the number of bits transferred. In the case, where I "received" a zero, the function received "zero" bits and did not overwrite the buffer. The zero i got from the buffer was still the initial zero the buffer contained before the transfer.
One of my main concerns are those control transfers. I found several "versions" for different chipsets, but I don't know where those come from. I could not find any requirements or flow charts about those control transfers in any datasheet.
Greetings
#greenapps found the error. Since it is an asynchronious data transfer and the timing of the Arduino device is not known, it is necessary to repeat the bulktransfer until something is received. I used a for loop with some iterations. As soon as the return value of the bulk transfer differs from one, I break out of the loop and continue.
Thanks for the help

Arduino Mega receiving correct data through Serial 0, but not Serial 1-3

I currently have a HC-06 Bluetooth device connected to my Arduino Mega 2560 in order to receive strings sent from an Android device. With the HC-06 on Serial 0, I am receiving the data without error with the following code:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
}
void loop() {
if(stringComplete) {
ParseSerialData(); // Parse the received data
inString = ""; // Reset inString to empty
stringComplete = false; // Reset the system for further input of data
}
}
void serialEvent() {
while(Serial.available() && stringComplete == false) {
char inChar = Serial.read();
inData[index] = inChar; // Store it in char array
index++;
if (inChar == '\n') { // Check for termination character
index = 0; // Reset the index
stringComplete = true; // Set completion of read to true
} else {
inString += inChar; // Also store as string
}
}
}
When I try to replace "Serial" with "Serial1" and "serialEvent()" with "serialEvent1()" and move the Bluetooth device to the TX1 and RX1, this program no longer works.
I have read that some people had similar problems when using AVR-GCC 4.4.x and solved the issue by downgrading to 4.3.x, but I have 4.3.2 (on Windows 8.1, same problem has arisen with Arduino IDE 1.0.3, 1.0.5-r2, and 1.5.6-r2).
I added the following print statements (with Serial 0 to print to the monitor on my PC) to the code with the Bluetooth device still on Serial 1:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
Serial.println("Setting up...");
}
void loop() {
if(stringComplete) {
ParseSerialData();
inString = "";
stringComplete = false;
}
}
void serialEvent1() {
Serial.println("In serialEvent1...");
while(Serial1.available() && stringComplete == false) {
Serial.println("Char in...");
char inChar = Serial1.read();
Serial.println("WTF");
Serial.println(inChar);
Serial.println("WTF2");
inData[index] = inChar;
index++;
if (inChar == '\n'){
Serial.println("Termination char read...");
index = 0;
stringComplete = true;
}else{
inString += inChar;
}
}
}
Doing this, on the monitor I get:
Setting up...
In serialEvent1...
Char in...
WTF
WTF2
inChar typically prints as nothing, but during one test it was printing as an '#' character. The string sent is "s,1\n" from the Android device.
Based on the print out, the serial event is triggered by availability of serial data, but Serial1.available() remains true for only the first iteration, 's' is not read in (nor any of the other characters that do when Serial is used), and a termination character (newline char) is never read in so that I can begin parsing.
I also tried various baud rates with no difference in behavior. Based on reading Arduino documentation, serial port 1 should work just like serial port 0, and I did not miss substituting Serial for Serial1 in any part of the code.
What could be causing errors in communicating over Serial1 in the same way that has worked flawlessly on Serial0?
I also found a related Stack Overflow question, which was solved with something similar to my code (which works perfectly with Serial0 and is based on the Arduino documentation) using an expected termination character (the difference being that his code implements serial reading in the main loop, whereas mine is in a serialEvent). For some reason, it seems that both of us were having issues with Serial1 data not showing as available at the start of the next iteration. For some reason, serialEvent1 is not being called again for me. And I still don't understand why the first/only character read is not 's.' At first I was thinking that the stream was getting flushed before getting to the serial event again, but that still doesn't account for reading in an incorrect first character.
Also, I added the following Serial1 print statement to run multiple times in the Arduino setup and the Android device receives it each time with no errors, so sending data is working just fine:
Serial1.print("b,1\n");
Or even
Serial1.print("A long test message. A long test message.\n");
I'm fairly close to answering my own question now with further testing/debugging. I actually think the answer may end up being hardware-related rather than software. I wanted to find out if the problem was with the data sent from the HC-06 to port 1, or with the reading function of port 1. I basically had serial port 0 read in data, then send it serially to port 1, which would read that data, and send feedback over Bluetooth to the Android device. Serial port 1 read the data fine coming from port 0, so the issue is reading in data specifically from the HC-06. It may simply be a voltage level issue, so the answer may not belong with Stack Overflow. I will leave the question unanswered though until I definitively have found the root cause (allowing for the possibility that I might need some define statement for the HC-06 or serial port 1 for data to be read correctly, though I'm guessing a voltage level conversion may do the trick. I'm not sure why there would be such a difference between Serial0 and Serial1 though).
I solved the problem enabling the pull-up resistor of the RX1 pin:
Serial1.begin(9600);
pinMode(19, INPUT);
digitalWrite(19, HIGH);
Therefore the 3 V is "overridden" by Arduino's 5 V for logical HIGH and zero is pulled down by Bluetooth's TX for logical LOW.
I did it slightly differently by using the INPUT_PULLUP feature to pull the hardware Serial3 pin HIGH:
Serial3.begin(19200);
pinMode(15, INPUT_PULLUP); // Serial3 receive pin
It works a treat. Previously my serial communications between two Arduino Mega 2560s had been mainly corruption with the occasional correct transmission. Now it is mainly the correct transmission. Previously, the time taken to receive a valid serial value was up to 2.5 seconds (due to having to repeatedly retry to get a valid transmit). Now the time taken to get a valid transmit is 20 ms. (I use a twisted pair of single core wires about 35 cm length.)
After checking the serial data lines on my oscilloscope, I was able to come up with a solution to my issue. With the setup described about the related Stack Overflow question (Bluetooth TX → RX0, TX0 → RX1, TX1 → Bluetooth RX), I checked the signals sent by the Bluetooth device and by the Arduino's serial port 0.
The Bluetooth device's signal was low at 400 mV and high at 3.68 V, while the Arduino's port 0 sent low at 0V and high at 5 V. I knew the Bluetooth device was a 3.3V level device, but the Arduino should read anything above about 3V as high, so this should have not been an issue (and it obviously wasn't on Serial 0).
Anyway, I replaced the HC-06 Bluetooth device with a backup one I had purchased and everything works fine with the code using Serial1 that I posted in my question. This Bluetooth device was transmitting low at about 160 mV and high at 3.3 V.
It seems that my problem was rooted in the hardware (voltage levels) as expected, and that for some reason Serial1 is more sensitive to changes in digital levels than is Serial0.

Mono for Android - Activity crash upon service call

My application has a UI (implemented with an Activity) and a service (implemented with the IntentService). The service is used to send data (synchronous, using NetworkStream.Write) to a remote server as well as to update the transmission status to the UI (implemented using Broadcast Receiver method).
Here is my problem:
The application works properly if the size of the buffer used for the NetworkStream.Write is 11 KB or less.
However, if the size of the buffer is larger than 11 KB, say 20 KB (this size needed in order to send jpg images), then the sevice keeps working properly (verified with log file), nonetheless the UI its gone (similar as if device's back button is pushed) and I can't find the way to bring it back. Its important to point out that in this case the Activity its not going into OnStop() nor OnDestroy() states.
At first I thought this would be some ApplicationNotResponding related issue due to a server delay, yet the UI crashes after about 5 sec.
Moreover, this only happens with the Hardware version. The emulator version works fine.
// SEND STREAM:
Byte[] outStream = new Byte[20000];
// -- Set up TCP connection: --
TcpClient ClientSock = new TcpClient();
ClientSock.Connect("myserver.com", 5555);
NetworkStream serverStream = ClientSock.GetStream();
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
// . . .
// RECEIVE STREAM:
inStream.Initialize(); // Clears any previous value.
int nBytesRead = 0;
nBytesRead = serverStream.Read(inStream, 0, 1024);
// -- Closing communications socket: --
ClientSock.Close();
One thing first: I would have been commented the question to clarify one thing before I give an answer, but unfortunately I don't have enough reputation yet.
The thing I would have asked for is: Why do you need to have a buffer greater than 11k to send an JPG image?
I nearly do the same in one (async) task with an image of 260k, but with a buffer of 10240 Bytes. Works without difficulties.
byte[] buffer = new byte[10240];
for (int length = 0; (length = in.read(buffer)) > 0;) {
outputStream.write(buffer, 0, length);
outputStream.flush();
bytesWritten += length;
progress = (int) ((double) bytesWritten * 100 / totalBytes);
publishProgress();
}
outputStream.flush();
I use this part to read an JPG image from resources or SD and post to my server.
Well you may want to change your application to use asynctask and take a look to the guide :
http://developer.android.com/training/basics/network-ops/connecting.html
Network operations can involve unpredictable delays. To prevent this from causing a poor user experience, always perform network operations on a separate thread from the UI.
Since android 4.0 it's impossible to perform network related task in the same thread as the UI thread. Also just to be clear http://developer.android.com/guide/components/services.html
Caution: A service runs in the main thread of its hosting process—the
service does not create its own thread and does not run in a separate
process

android - Bluetooth: program stuck at inputstream reading

Helo.
Im developing an application that transferes data over bluetooth(with a flight recorder device). When i am recieving a lot of data data(3000 - 40000 lines of text, depends of the file size) my aplication seems to stop recieving the data. I recieve the data with InputStream.read(buffer). For example: I send a command to the flight recorder, it starts sending me a file(line by line), on my phone i recieve 120 lines and then the app stucks.
Intresting is that on my HTC Desire the app stucks just sometimes, on the Samsung Galaxy S phone the application stucks every single time i try to recive more than 50 lines.
The code is based on the BluetoothChat example. This is the part of code where i am listening to the BluetoothSocket:
byte[] buffer = new byte[1024];
int bytes =0;
while(true)
{
bytes = mmInStream.read(buffer);
readMessage = new String(buffer, 0, bytes);
Log.e("read", readMessage);
String read2 = readMessage;
//searching for the end of line to count the lines(the star means the start of the checksum)
int currentHits = read2.replaceAll("[^*]","").length();
nmbrOfTransferedFligts += currentHits;
.
.
.
//parsing and saving the recieved data
I must say that i am running this in a while(true) loop, in a Thread, that is implemented in an android Service. The app seems to stuck at "bytes = mmInStream.read(buffer);"
I have tried to do this with BufferedReader, but with no success.
Thanks.
The app seems to stuck at "bytes = mmInStream.read(buffer);"
But that is normal behavior: InputStream.read(byte[]) blocks when there is no more data available.
This suggests to me that the problem is on the other end or in the communication between the devices. Is is possible that you have a communication problem (which is a bit different on the Galaxy vs. the Desire) that is preventing more data from being received?
Also, I would suggest that you wrap a try/catch around the read statement to be sure that you catch any possible IOException's. Though I guess you would have seen it in logcat if that were happening.
Speaking of logcat, I would suggest that you look at the logcat statements that Android itself it generating. I find that it generates a lot for Bluetooth and this might help you to figure out whether there really is any more data to be read().

Categories

Resources