UDP Datagram packet receive loop delay - android

I'm running a Thread with a an active loop waiting for UDP packets.
When message is received , I want to process it.
I need to receive several packets per second (~20).
I'm taking a minimalist example, just logging after receiving UDP packet
while (socketUDP != null) {
message = new byte[6];
packet = new DatagramPacket(message, message.length);
try {
socketUDP.receive(packet);
command = new String (message, 0, packet.getLength());
} catch (IOException e) {
Log.e(LOG_TAG, LOG_TAG + " IOException: " + e.getMessage() );
}
Log.d(LOG_TAG, "test");
}
The behaviour is weird, because, for example, I send 50 UDP packets in 1 second, no one is lost, and Android take's about 3/4 seconds to show the 50 log text message "test"!!
So, it seems that Android's VM is saving somewhere all packets in a buffer and process it when possible!
I need to process datagram's packets as soon as possible in Android.
It seems I'm missing something.
Any ideia wich is the best way to do that?!

If you're in a hurry, then:
create all your objects before listening of UDP
log after you're done receiving all your packets, or at least log a minimal amount, and infrequently.
Right now, every single time a packet arrives, you create a DatagramPacket and a String, and then Log.e, all of which should take much more time than receiving the packet itself. Of course, even when optimized, there's no real-time guarantee of delivery.

Try to ping device which is sending packets. It helps me. For example I'm using this code before receiving packets:
pingThread = new Thread(new Runnable() {
#Override
public void run() {
Runtime runtime = Runtime.getRuntime();
try {
// Ping 10 times at 169.254.169.168
runtime.exec("/system/bin/ping -c 10 169.254.169.168");
} catch (IOException e) {
e.printStackTrace();
}
}
});
pingThread.start();
After that you can call:
socketUDP.receive(packet);

Related

Not receiving full packet when sending data from STM32 to Android via Bluetooth

I am sending accelerometer data from STM32 microcontroller to a HC-06 Bluetooth module, and I have developed an Android app to receive the data.
On STM32, I make a 3 byte packet (uartBuffer) which has the following structure: [0] counter, [1] xdata, [2] ydata.
I then send this data via UART to the HC-06 module.
HAL_UART_Transmit(&uartHand, uartBuffer, 3, 10); // {uartHandle, data, dataSize, timeout}
On Android, I have no problem connecting with the device, etc. However, when I receive the packet, it doesn't arrive together. It does always arrive eventually (in the correct order as well), but I might get a packet with only the 1st byte, then a packet with the last 2 bytes, and sometimes other combinations, as can be seen in the logcat picture below. The value which always increments by one (i.e. 20, 21, 22, etc..) is the 1st byte of the packet as sent by STM32.
I have tested this with different sampling rates between up to 100Hz, and with bigger packets (up to 5 bytes).. I never lose any bytes, but the packet arrangement is further divided at higher sampling rates and data sizes.
Here is the ConnectedThread class which does the reading of data in the run method.
`
private class ConnectedThread extends Thread {
private final BluetoothSocket mmBTSocket;
private final InputStream mInStream;
private final OutputStream mOutStream;
public ConnectedThread(BluetoothSocket mSocket) {
Log.d(TAG, "ConnectedThread: Starting");
mmBTSocket = mSocket;
InputStream mTempIn = null;
OutputStream mTempOut = null;
try {
mTempIn = mmBTSocket.getInputStream();
mTempOut = mmBTSocket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Failed to get I/O Stream", e);
}
mInStream = mTempIn;
mOutStream = mTempOut;
}
public void run(){
byte[] mBuffer = new byte[3]
int mBytes = 0; // bytes returned from read
String mIncomingMessage = new String();
mIncomingStringBuilder = new StringBuilder();
while (true) {
try {
mIncomingStringBuilder.setLength(0);
mBytes = mInStream.read(mBuffer, 0, 3);
for (int i=0; i<mBytes; i++) {
mIncomingMessage = String.valueOf(mBuffer[i]);
mIncomingStringBuilder.append(mIncomingMessage + ",");
}
Log.d(TAG, "run: ConnectedThread - InputStream: " + mIncomingStringBuilder);
Intent incomingMessageIntent = new Intent("incomingMessage");
incomingMessageIntent.putExtra("theMessage", mIncomingStringBuilder.toString());
LocalBroadcastManager.getInstance(mContext).sendBroadcast(incomingMessageIntent);
} catch (IOException e) {
Log.e(TAG, "error reading from inputStream, e);
break;
}
}
}
`
So my questions are:
1) Why am I not receiving the full packets in the same structure as they are sent from the STM32? A commentor here mentions here that:
The bluetooth connection is stream based, not packet based. There is no guarantee or attempt to preserve packetization. So any number of writes can result in any number of reads, just the stream of bytes are guaranteed to be correct. If you need to detect packets, you need to provide your own packet structure to wrap your data.
Is this true? Can Bluetooth really not preserve the full packet structure? Can anyone verify this?
2) If this is true, then what is the best method to construct a package which is easy for Android to detect the start of and end? I assume I need a sync/start byte. How do I ensure this sync byte doesn't occur in my accelerometer data? Should I use 2 consecutive sync bytes? Is a checksum at the end of the packet enough to detect if the packet has errors?
3) Finally, is it good practice to only use connectedThread on Android to receive the byte, convert to string and send to main activity so that its free to receive the next as quickly as possible? Then in main activity, I would reconstruct the packet? Or would this be too much work for main activity too?
Thanks in advance for your help.

Android Open Accessory USB communication failing after sending large data packets

I have an android phone communicating with a Linux machine using AOA. The Linux machine is set up to initiate the connection, then wait for incoming data and echo it back to the phone unchanged. This works fine for small packets of data (less than 1024 bytes) from the phone. However, if I send exactly 1024 bytes, it appears to work from the Android end, but the computer never sees the packet, just any following ones that are smaller. If the phone attempts to send packets larger than 1024, these do get received by the computer, but the android phone will no longer be able to receive any packets from the computer. Further confusing the issue, this did work in the past, yet rolling back to earlier versions of the transmitting/receiving code on the phone doesn't seem to have any effect. The code on the computer has not been changed.
The android app checks for a USB accessory at start-up, and if one is found it starts a listener and sender thread. The sender thread waits on a blocking queue for outgoing packets, and sends them as soon as they are received. The listener thread continuously attempts to read from the input stream, which blocks until data is available. This is the code I use for setting up & running the threads:
private boolean openUSB(){
mUSBManager = (UsbManager) getSystemService(Context.USB_SERVICE);
mAccessory = mUSBManager.getAccessoryList();
if (mAccessory != null && mAccessory.length > 0) {
mParcelFileDescriptor = mUSBManager.openAccessory(mAccessory[0]);
mFileDescriptor = mParcelFileDescriptor.getFileDescriptor();
mListener = new Thread() {
public void run() {
listenerThread();
}
};
mListener.start();
mSender = new Thread() {
public void run() {
senderThread();
}
};
mSender.start();
displayText("Connected to USB accessory");
return true;
} else {
displayText("No USB accessory detected");
return false;
}
}
private void listenerThread(){
byte packet[] = new byte[SDR_PREFIX_SIZE+SDR_HEADER_SIZE+SDR_MAX_PAYLOAD+SDR_CRC_SIZE];
FileInputStream input = new FileInputStream(mFileDescriptor);
try {
ByteArrayOutputStream incoming = new ByteArrayOutputStream();
displayText("Listener Started");
while ( mFileDescriptor != null && input != null ) {
int read = input.read(packet,0,packet.length);
/* data in packet gets processed */
}
} catch ( Exception e) {
displayText("Listener Exception - "+e.getMessage(),true);
}
displayText("Listener Exited");
}
private void senderThread(){
displayText("sender started");
FileOutputStream output=new FileOutputStream(mFileDescriptor);
try {
byte data[] = mTransmitQueue.take();
while (data != null) {
displayText("Sending packet " + packet + ", "+data.length + " bytes");
output.write(data);
data = mTransmitQueue.take();
}
} catch ( Exception e) {
displayText("Sender Exception - "+e.getMessage(),true);
}
}
In the past, I had issues getting the listener and sender to work, until I found out that some of the intermediate objects that were used to create the file streams were being garbage-collected, yet were still needed. I now store all those intermediate objects to member variables (mUSBManager, mAccessory, mParcelFileDescriptor, mFileDescriptor) to give them persistence. I suspect that this issue is something similar, but I haven't been able to make any headway. I have been beating my head on this issue without any success, and really hope that others will have some insight on what is causing this.
I've found a work-around, expanding the buffer used for receiving data seems to fix the issue, even though the existing buffer was large enough for all packets. Increasing the buffer from 1524 to 2524 fixed the issue with incoming packets not being received. This is a kludgy solution, but it works.

Send and receive datagram packet

sorry for my bad english. I have to send and receive data from phone to radio using bluetooth pan interface on android. This is the code I've implemented to send, I've made it into the function DoInBackground() of AsyncTask:
try
{
ds = new DatagramSocket();
byte buf[] = "Ciao".getBytes();
DatagramPacket msg = new DatagramPacket(buf, buf.length, InetAddress.getByName(add), p);
ds.send(msg);
}
and it works perfectly. Now I have to wait 100 seconds the answer of the radio. I decide to implement it with this code:
try
{
ds.setSoTimeout(10000);
while(true)
{
try
{
ds.receive(dp);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
catch (IOException e)
{
}
but there are three questions:
1. I need to receive the packet at 192.168.11.2 and 1234 port, but when I declared datagramsocket I set it void, because if i put port and address, send code doesn't work;
2. How can I manage the packet I've received by the radio? I don't need to use address and port bytes;
3. Why have I put the timeout before the loop?
Thank you for the answers.
1) Create the datagram socket with just the port number you are after. DatagramSocket(p);
2) You have a DatagramPacket with a bytebuffer of the size of the response and the length of the response i.e:
int responseLength = 1024;
byte[] responseData = new byte[responseLength];
DatagramPacket response = new DatagramPacket(responseData, responseLength);
After receiving into this datagram packet you need to convert it into same object that it was sent as. Something like this maybe:
String s = new String(response.getData());
3) The setSoTimeout doesn't cause the message to wait for 100s, it is just saying that after 100s if nothing has been read in by the receive() then it will timeout. This only needs to be set once per connection, setting this multiple times during the loop shouldn't be done.
Hope this helps

Android client socket doesn't send data after some time

I'm developing an Android real-time-data app that sends data (floats and ints) to a server on the local subnet via a TCP socket. The problem I'm facing is that after sending some data simultaneously the socket doesn't send anymore data at all. I debugged the app and it shows that data is being sent but doesn't show up on the server. After this happens if I close the connection the server doesn't even get the notification that the connection has been terminated which it should according to my design model. Meanwhile I get an exception on the app saying it can not write to a broken pipe. This tells me that the problem is with the app because I also did test using a desktop app and I can send huge amounts of data to the server and it gets delivered.
And please keep in mind that the data size I'm talking about here is 252 bytes per packet.
Here's my class I'm using. (This runs in an AsyncTask object )
public class Network
{
private Socket handle;
public static enum TASK
{
TASK_CONNECT, TASK_SEND, TASK_CLOSE
}
public Network()
{
}
public String lastError = "";
public boolean Connect(String host, int port)
{
try
{
lastError = "Connecting to server.";
handle = new Socket(host, port);
handle.setTcpNoDelay(true); //
handle.setSendBufferSize(SIZE_OF_PACKET); ///==> These don't seem to help at all
handle.setKeepAlive(true); ///
return true;
}catch(IOException e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
return false;
}
}
private void err(String e){
System.err.println(e);
}
private boolean SendPacket(byte buffer[])
{
OutputStream oStream = null;
err("sending: " + buffer.length + " bytes");
try
{
lastError = "Obtaining output stream.";
oStream = handle.getOutputStream();
lastError = "Error sending data.";
oStream.write(buffer);
oStream.flush();
return true;
}catch(Exception e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
}
return false;
}
public void Close()
{
try{ handle.close(); handle = null; }catch(Exception e){} // swallow exception
}
}
I send my data in a loop depending on how many numbers I have. I tried a Google search but didn't find anything relevant. Has anyone experienced this before? It's making me mad now.
EDIT: Wireshark shows incoming "red" packets that don't reach the desktop app (server)
Look at this picture.
You can see the first few have Len > 0 the red ones have 0.
I think it's time Google interfaced the USB so we can use it. At least that'd would have been my first option.
Should you not be calling oStream.close() after you flush the stream, given that you never use it again?
Also, you say that this is being run in an AsyncTask object. Is it possible that multiple threads could be attempting to send packets at the same time? If so, you might need some form of synchronisation around the SendPacket method.
Ok. I solved the issue by using UDP instead. Thank you all.
But I still didn't find the source of the problem.

Telnet. Android, hanging on send

Im trying to send a command through telnet to my computer which then sends the command to a serial port, when using telnet using
adb shell
$telnet 172.20.104.203 5334
$h
it returns the data from the command h, how ever when I try to do this using android it connects to the socket, I can see this on the computer, it sends the command but then as soon as it logs that it has sent it hangs and comes up with "Application not responding" and it has wait or force close and if I wait it just stays the same.
This is my code for the telnet part
private static final int TCP_SERVER_PORT = 5334;
private void runTcpClient() {
try {
Socket s = new Socket("172.20.104.203", TCP_SERVER_PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//send output msg
String outMsg = "$getPos";
out.write(outMsg);
out.flush();
Log.i("TcpClient", "sent: " + outMsg);
//accept server response
String inMsg = in.readLine() + System.getProperty("line.separator");
Log.i("TcpClient", "received: " + inMsg);
//close connection
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
It logs the send, but it never logs the receive, I thought it might be something to do with the amount of data being received so I just sent
$getPos
instead but it still hangs.
Any one know what could be happening?
I'm not familiar with the particulars of the platform, but its unlikely that a readline will work on a socket/tcp stream, or if it works, it will work unreliably. Data coming in from a socket is not necessarily organized into 'lines', but instead packets of a particular size. A 'read' performed on a socket will return some number of bytes.
The client doing such reads needs to read each packet, buffer them until it receives an agreed-upon 'end of data' marker. The marker agreed-upon is determined by protocol.
You've shown us the client side of your code. Do you have a corresponding server side?
From what you have here, my guess is that your client code is waiting patiently for an 'end of line' that for some reason, will never come. OR there's something wrong at the server end and the server isn't sending any data to the client.

Categories

Resources