Send and receive datagram packet - android

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

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.

Front-end datagram truncation UDP Android

Thanks in advance to any support,
I'm trying to broadcast a UDP message on the local network. After sending a particular string, responders send back metadata about their location, IP address, status etc.
I've gotten communication to occur, but the issue is in the string response itself.
TLDR: My udp receive packet is cutting off front elements of the datagram.
I dont think this is a buffer size issue. My buff is 2048, much larger than the data I'm looking to receive (about 50-200 characters).
I have worked with this setup before and gotten the first part no problem (with iOS). A wireshark (equivalent) console also confirms. Wireshark and Android output have been attached for comparison.
Proper data coming in via packet app
Front-truncated packet in logcat (notice that everything up until "[Red]" has been omitted)
inside onCreate:
try{
socket = new DatagramSocket();
socket.setBroadcast(true);
socket.setSoTimeout(3000);
broadcastPacket = new DatagramPacket(
broadcastString.getBytes(),
broadcastString.length(),
getBroadcastAddress(),
30303);
}catch (IOException e) {
Log.e("MYAPP", "socket error", e);
}
inside an AsyncTask:
try {
while(true) {
byte[] buffer = new byte[2048];
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
socket.receive(receivePacket);
String receiveString = new String(receivePacket.getData(), 0, receivePacket.getLength() );
Log.d("a", "Received response " + receiveString );
Log.d("a", "From host " + receivePacket.getAddress() );
Log.d("a", "With offset " + receivePacket.getOffset() );
}
}catch (java.io.IOException e) {
Log.d("a", "Receive timed out");
}
note that before using receivePacket.getLength() I'd just get a bunch of ?'s after the partial response
This did end up being an Android Studio bug.
String[] deviceElements = receiveString.split("\r\n");
Log.d("a", deviceElements[0]);
returned the data I was looking for; intially printing the full receiveString returned only a portion of the string.

Android / Iphone socket communication

me and one of my coworkers are working on a simple socket communication between Android and Iphone application. The thing we achieved till now is I can send byte array to him in another thread and receive byte array in service. But the problem that we face is that I can't read the whole message which he is sending to if he don't close the socket. But I need that socket alive, so I can send him response if the data was ok or there were some problems. Here is how I am listening about his messages :
thread = new Thread(new Runnable() {
public void run() {
try {
serverSocket = new ServerSocket(5000);
while(state){
client = serverSocket.accept();
client.setKeepAlive(true);
// LOGS
Log.d("","receivedBufferSize : "+serverSocket.getReceiveBufferSize());
Log.d("","is connected : "+client.isConnected());
Log.d("","port : "+client.getPort());
Log.d("","ipadress : "+client.getInetAddress().toString());
InputStream is = client.getInputStream();
Log.d("","is Size : "+is.available());
byte[] bytes = toByteArray(is);
for(int i=0;i<bytes.length;i++){
Log.d("","bytes["+i+"] : "+bytes[i]);
}
}
serverSocket.close();
Log.d("","client socket : "+client.isClosed() + " serverSocket : "+serverSocket.isClosed());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
So if he don't close the application or don't close the socket, I am sitting on that log message : Log.d("","is Size : "+is.available()); and nothing really happens. After he close the socket I can see the bytes of received byte array.
Any idea what I am doing wrong or any kind of suggestions / help what can cause this?
Thanks in advance!
Actually the problem was on Iphone side, it was just a Input / Output Stream problems with Objective C implementation. So this piece of code is working properly.

UDP Datagram packet receive loop delay

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

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