Android stops receiving TCP transmissions from Photon after 31-33 transmissions

Hi everyone,

I have a mobile hotspot from my Android device wirelessly connected via TCP to a Photon, which sends back a distance measurement from a LIDAR sensor.

The Photon continuously queries the sensor, and from my terminal, the serial output continuously displays the distance in real-time.

However, after between 31 and 33 transmissions, the TCP client on my Android stops displaying the real-time information. It can’t receive the transmissions that the Photon is supposed to be sending. It appears to hang after 31 transmissions whether there is a delay between transmissions of 1 ms or 1000 ms.

Why is this happening (has the Android stopped receiving or the Photon stopped sending?), and how can I prevent this from happening? The last thing to happen is that the Android is listening and waiting for a message from the Photon.

Please find below my Java code (Android) and my Photon code.

Photon:

    #include "application.h"
    SYSTEM_MODE(MANUAL);
    
    // TCP setup
    TCPServer server = TCPServer(23);
    TCPClient client;
    
    int range;
    // char read;
    String readString;
    String sentRange;
    
    // LIDAR sensor setup
    
    const int monitorPin1 = 3;
    const int monitorPin2 = 1;
    
    const int triggerPin1 = 2;
    const int triggerPin2 = 0;
    
    long pulseWidth;
    
    // Initialise averaging array
    const int numberOfReadings = 10; // reasonable DOF from Measurement and Noise
    const int med = numberOfReadings/2;
    long readings[numberOfReadings];
    int median;
    
    void setup() {
        Serial.begin(9600);
        WiFi.clearCredentials();
        
        //LIDAR 
        pinMode(triggerPin1, OUTPUT); // Set pin 2 as trigger pin
        pinMode(D7, OUTPUT);
        digitalWrite(triggerPin1, LOW); // Set trigger HIGH for non-continuous read
        pinMode(monitorPin1, INPUT); // Set pin 3 as monitor pin
        
        pinMode(triggerPin2, OUTPUT); // Set pin 2 as trigger pin
        digitalWrite(triggerPin2, LOW); // Set trigger HIGH for non-continuous read
        pinMode(monitorPin2, INPUT); // Set pin 3 as monitor pin
        delay(2000);
          
        WiFi.on(); // if this isn't working, make sure it's set up for Photons (not Electrons!)
        WiFi.setCredentials("AndroidAP", "12345678"); // NB: must call WiFi.on() before this line. Not sure why.
        delay(2000);
        WiFi.connect();
        
        // start listening for clients
        server.begin();
    }
    
    int readLIDAR(int triggerPin, int monitorPin){
        pulseWidth = pulseIn(monitorPin, HIGH); // Count how long the pulse is high in microseconds
        pulseWidth = pulseWidth / 10; // 10usec = 1 cm of distance
        return pulseWidth;
    }
    
    long takeReading(int triggerPin, int monitorPin) {
      for (int i = 0; i < numberOfReadings; i++) {
        readings[i] = readLIDAR(triggerPin, monitorPin);
        delay(10); // There doesn't seem to be a requirement for a delay, but to be safe, delay = 10ms.
      }
      return *readings;
    }
    
    // Sort readings
    long sort(long* readings) {
        // bubble sort with flag
        for (int i = 0; i < numberOfReadings; i++) {
            bool flag = true;
            for (int j = 1; j < numberOfReadings; j++) {
                if (readings[j-1] > readings[j]) {
                    int t = readings[j-1];
                    readings[j-1] = readings[j];
                    readings[j] = t;
                    flag = false;
                }
            }
            if (flag) break;
        }
        return *readings;
    }
    
    int range1(String command){
        if (command == "Get range 1\n") *readings = takeReading(triggerPin1, monitorPin1); // gather sufficient (typ: 10) readings
        else if (command == "Get range 2\n") *readings = takeReading(triggerPin2, monitorPin2); // gather sufficient (typ: 10) readings
        
        *readings = sort(readings); // sort in ascending order for median value
        median = (readings[med-1] + readings[med])/2; // get median value to send to app
        memset(readings, 0, sizeof(readings)); //clear previous readings
        
        return median;
    }
    
    String goGetCredentials() {
        WiFiAccessPoint ap[5];
        int found = WiFi.getCredentials(ap, 5);
        for (int i = 0; i < found; i++) {
            Serial.print("ssid: ");
            Serial.println(ap[i].ssid);
            // security is one of WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA, WLAN_SEC_WPA2
            Serial.print("security: ");
            Serial.println(ap[i].security);
            // cipher is one of WLAN_CIPHER_AES, WLAN_CIPHER_TKIP
            Serial.print("cipher: ");
            Serial.println(ap[i].cipher);
        }
    }
    
    void loop() {
        
        if (client.connected()) {
            Serial.println("Client connected.");
            // read client for which sensor to query and send back result
            while (client.available()) {
                readString = "Get range 1\n";
                range = range1(readString);
                sentRange = "u" + String(range) + " cm" + "\n";
                Serial.print(sentRange);
                server.write(sentRange);
                
                delay(300);
                    
                readString = "Get range 2\n";
                range = range1(readString);
                sentRange = "f" + String(range) + " cm" + "\n";
                Serial.print(sentRange);
                server.write(sentRange);
                delay(300);
            }
        } else {
            // if no client is yet connected, check for a new connection
            client = server.available();
            
            if(WiFi.hasCredentials()==true) {
              Serial.println("Has credentials.");
            //   goGetCredentials();
            } else {
              Serial.println("No credentials.");
            }
          
            Serial.println("Looking for server.");
            delay(2000);
        }
    }

Android:

    import android.util.Log;
    
    import java.io.*;
    import java.net.InetAddress;
    import java.net.Socket;
    
    
    public class TCPClient {
        private int i = 0;
        private String serverMessage;
        public static String buttonPushed;
        public static final String SERVERIP = "xxx.xxx.xxx.xxx"; //your Photon IP address
        public static final int SERVERPORT = 23;
        private OnMessageReceived mMessageListener = null;
        private boolean mRun = false;
    
        PrintWriter out;
        BufferedWriter out1;
        OutputStreamWriter out2;
        OutputStream out3;
        BufferedReader in;
    
        /**
         *  Constructor of the class. OnMessagedReceived listens for the messages received from server
         */
        public TCPClient(OnMessageReceived listener) {
            mMessageListener = listener;
        }
    
        /**
         * Sends the message entered by client to the server
         * @param message text entered by client
         */
        public void sendMessage(String message){
            if (out != null && !out.checkError()) {
                out.println(message);
                Log.d("TCP Client", "Message: " + message);
                out.flush();
            }
        }
    
        public void stopClient(){
            mRun = false;
        }
    
        public void run() {
    
            sendMessage(buttonPushed);
            if (buttonPushed == "Disconnect") {
                stopClient();
                return;
            }
    
            mRun = true;
    
            try {
                sendMessage(buttonPushed);
                if (buttonPushed == "Disconnect") {
                    stopClient();
                    return;
                }
                //here you must put your computer's IP address.
                InetAddress serverAddr = InetAddress.getByName(SERVERIP);
    
                Log.e("TCP Client", "C: Connecting...");
    
                //create a socket to make the connection with the server
                Socket socket = new Socket(serverAddr, SERVERPORT);
    
                try {
                    sendMessage(buttonPushed);
                    if (buttonPushed == "Disconnect") {
                        disconnectSession(socket);
                        return;
                    }
                    //send the message to the server
    
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
    
                    sendMessage(buttonPushed);
    
                    //receive the message which the server sends back
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
                    //in this while the client listens for the messages sent by the server
                    while (mRun) {
                        Log.e("TCP Client", "C: Reading from server...");
    
                        serverMessage = in.readLine();
    
                        Log.e("TCP Client", "C: Server successfully read!");
                        new TCPClient(mMessageListener);
    
                        if (serverMessage != null && mMessageListener != null) {
                            //call the method messageReceived from MyActivity class
                            mMessageListener.messageReceived(serverMessage);
                            i++;
                            Log.d("Incoming counter", String.valueOf(i));
                        } else {
                            serverMessage = null;
                        }
    
                        sendMessage(buttonPushed);
                        if (buttonPushed == "Disconnect") {
                            disconnectSession(socket);
                            break;
                        }
                    }
    
                    Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + serverMessage + "'");
    
    
    
    
                } catch (Exception e) {
                    Log.e("TCP", "S: Error", e);
                } finally {
                    if (buttonPushed == "Disconnect") {
                        disconnectSession(socket);
                        return;
                    }
                }
    
            } catch (Exception e) {
                Log.e("TCP", "C: Error", e);
            }
    
        }
    
        public void disconnectSession(Socket socket) throws IOException {
            stopClient();
    
            //the socket must be closed. It is not possible to reconnect to this socket
            // after it is closed, which means a new socket instance has to be created.
    //        socket.close();
            serverMessage = null;
        }
    
        //Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
        //class at on asynckTask doInBackground
        public interface OnMessageReceived {
            public void messageReceived(String message);
        }
    }

Thanks in advance!

Hi @jeremygilly,

I would try this on a wifi network other than your mobile hotspot, and maybe try running a WireShark capture of the traffic to see if you can see packets getting dumped or rejected, or if they’re still coming from the device, but the android device isn’t reading them, etc.

WireShark is a great tool to add to your toolbelt if you haven’t played with it before - https://www.wireshark.org/

I hope that helps!

Thanks,
David

3 Likes

Hi @Dave, thanks for the tip about WireShark!

It seems like I was sending the message “Connect” from the Android to the Photon, it would stop after 32 transmissions. It seems like I’ve filled up a buffer somewhere on the Android or on the Photon, because I can change how many transmissions it takes to stop by changing the number of characters in the message (e.g. “ConnectConnect” stops after 16 transmissions). So it seems that the Photon can only take 7 * 32 = 224 characters from the TCP Client before stopping. I’m guessing that flushing server.read() is the way to go, but I’m not sure how to do so.

As a short term fix, the Photon simply starts writing to the client as soon as it is available (continuous readings), rather than waiting for it to receive a message (readings that would respond to a button being pushed). As I’m hoping to store location data with the readings, it would be good to have the ability to take user input for specific readings.

Hi @jeremygilly,

Make sure you’re reading off the buffer on the photon as fast as you can. TCP connections are meant to be reliable and not “fire and forget” like UDP. If you don’t read from the buffer, the device won’t keep telling your router that it got the messages, and the packets will start to buffer and need to be re-sent all the way up the chain back to your android device.

I hope that helps!

Thanks,
David

2 Likes