Unreliable Wi-Fi connection

I am writing some code to send OSC messages from my iPad running Touch OSC to an Arduino Uno fitted with the official Wi-Fi shield. I have updated the Wi-Fi firmware in the last two weeks.

The hardware setup is an RGB LED on three pins wired as a common anode so sinking through the pins, a white LED sourced powered all connected to PWM capable pins. There is also a pot on analogue 0 sending its reading back to the iPad.

Basically this works. However it is unreliable. That is sometimes the odd Touch OSC message doesn't get through and sometimes it locks up completely for a minute or so.

Any ideas why?

/*
  WiFi UDP Send and Receive OSC
  Mike Cook Jan 2014
 
 This sketch wait an OSC UDP packet on localPort using a WiFi shield.
 For use with page 1 & 3 of the "simple.touchosc" layout
 
 based on an example by dlf (Metodo2 srl)
 LEDs pins 3,5 & 6 common anode RGB (sink), pin 9 single LED (source)
 */

#include <SPI.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <OSCBundle.h>
#include <OSCBoards.h>


int status = WL_IDLE_STATUS;
char ssid[] = "myNetwork"; //  your network SSID (name) 
char pass[] = "**********";    // your network password (use for WPA, or use as key for WEP)

int keyIndex = 0;            // your network key Index number (needed only for WEP)

unsigned int inPort = 8000;  // local port to listen on needs to match OSC's outgoing port
unsigned int outPort = 8001; // local port to talk to on needs to match OSC's incoming port

char packetBuffer[255]; //buffer to hold incoming packet
byte leds[] = {3, 3, 5, 6, 9};  // first entry just a dummy

WiFiUDP Udp;  // instance of the WiFi handler

void setup() {
  //Initialise serial and wait for port to open:
  Serial.begin(9600); 
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println(" ");
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present"); 
    // don't continue:
    while(true); // hold here
  } 
  
  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:    
    status = WiFi.begin(ssid, pass);
  
    // wait 10 seconds for connection:
    delay(10000);
  } 
  Serial.println("Connected to wifi");
  printWifiStatus();
  
  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.begin(inPort); 
  for(int i=1 ; i<5; i++) {
  pinMode(leds[i], OUTPUT);
  digitalWrite(leds[i],HIGH);
     }
  delay(500);
  digitalWrite(leds[4],LOW);
}

void loop() {
  // if there's data available, read a packet
  OSCMessage messageIN;
  int packetSize = Udp.parsePacket();
  if(packetSize)
  {  
      while(packetSize--)
       messageIN.fill(Udp.read());
       if(!messageIN.hasError())
       printMessage(messageIN);
     {
        messageIN.route("/1", routeScreen1); // add others for other screens
        messageIN.route("/3", routeScreen3);
     }
 }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

/**
 * Route Screen 1
 * 
 * called when address matched "/1"
 * expected format:
 * /1/push(N) 
 *   (N) = a number corrisponding to a digital pin on the Arduino
 *   (value) = digital write on that pin
 * 
 */

void routeScreen1(OSCMessage &msg, int addrOffset ){
  //match input
  int match = -1;
  
  for(int i=1; i<5; i++){
   if(msg.match(prefixPulsNumOSCAddress("/toggle",i), addrOffset) != 0) match = i;
  }
    // Serial.print("Match toggel");
  // Serial.println(match);
  if(match != -1) { // if we have a match for a /toggle address
  float data = msg.getFloat(0);
  if(match == 4)
  if(data == 1.0) digitalWrite(leds[match], HIGH); else digitalWrite(leds[match], LOW);
  else
  if(data == 1.0) digitalWrite(leds[match], LOW); else digitalWrite(leds[match], HIGH);
  }
  else { // if not a toggle look for a fader
      for(int i=1; i<5; i++){  // don't look for fader 5
       if(msg.match(prefixPulsNumOSCAddress("/fader",i), addrOffset) != 0) match = i;
      }
      if(match != -1) { // if we have a match for a /fader address
        float data = msg.getFloat(0);
          if(match == 4)
          analogWrite(leds[match], data * 255); // set brightness
          else
          analogWrite(leds[match], 255 - (data * 255)); // set brightness
      }
  }
}

void routeScreen3(OSCMessage &msg, int addrOffset ){
  char pad[] = "/xy";
  /*
  char address[255];
  int len = msg.getAddress(address, 0);
  for(int i=0; i<len; i++)
    Serial.print(address[i]);
  Serial.println(" ");
  */
  // get data type
  //Serial.println(msg.getType(0));
  //Serial.println(msg.getDataLength(0));
    if(msg.match(pad, addrOffset) ){
       float data = msg.getFloat(0);
       Serial.print("X = ");
       Serial.print(data);
       float data2 = msg.getFloat(1);
       Serial.print("  Y = ");
       Serial.println(data2);
       analogWrite(leds[3], data * 255); // set brightness
       analogWrite(leds[4], data2 * 255); // set brightness
    }
}

char * prefixPulsNumOSCAddress( char * prefix, int num){
    static char s[12]; // space to construct the string
    int i = 11; // last location in the string
    int len = 0;
    while(prefix[len] != '\0') len++; // find the length of the prefix char array
	
    s[i--]= '\0';  // add a null at the end
	do
        {
		s[i] = "0123456789"[num % 10];
                --i;
                num /= 10;
        }
    while(num && i); // keep on going until num or i drop to zero 
    i++;  // compensate for last --i
    for(int j=0; j<len; j++){ // add the prefix string backwards
      s[i - len + j] = prefix[j];
      }
    return &s[i-len]; // return char array and point to first byte
}
void printMessage(OSCMessage &msg){
  char address[255];
  int len = msg.getAddress(address, 0);
  for(int i=0; i<len; i++)
    Serial.print(address[i]);
    Serial.print(" with data ");
    float data = msg.getFloat(0);
    Serial.print(data);
  Serial.println(" ");
}

EDIT - Removed CheckAnalog function to make things clearer.

What is the last thing displayed on the serial monitor during the lockup?

edit: I just saw this in your checkAnalogue function. This may cause problems. Use Udp.remoteIP() only if receiving a packet and returning a response.

    Udp.beginPacket(Udp.remoteIP(),outPort);

You should specify the remote IP also.

    Udp.beginPacket(outIP,outPort);

Thanks for that.

What is the last thing displayed on the serial monitor during the lockup?

Nothing, just the last successful message to get through.

your checkAnalogue function. This may cause problems

I get very much the same sort of dropped message and unreliable response when I comment out the call to that function so I doubt it is that. What call would you recommend I do here anyway?

It appears you are using the wifi shield as the "client" and the other device as the "server". The "client" sends the "request" packet, and the "server" sends a "response" packet back to the "client". This is the same type protocol as NTP. My code does the same, except I use a Linux/RPi as the "server". Here is my Arduino wifi sketch and Linux C code.
http://forum.arduino.cc/index.php?topic=210151.msg1543236#msg1543236

I have tried everything I know to get the code to fail. I tried disabling the wifi radio in the router. I changed the wireless security type. I changed the frequency (channel). I stopped and restarted the Linux code. The wifi shield always went right back to working as soon as it reconnected without any unpredictable pause or freeze .

If you have a Linux box, try my code. See if you can see where your code is different.

BTW, that code went over a week and 180,000 packets with me screwing with it the entire time.

Thanks Tim, it is just possible that it might be the iPad's Touch OSC not sending data occasionally but things like toggle switches do change it is just that the message that it has changed doesn't always arrive.

Thanks again for taking a look.

Hi Mike. Like I said before, whether the packet sent by the wifi shield arrives at the "server" or not should not affect the operation or sending of the packets by the Arduino. This is UDP. Once the packet is accepted by the next network device, the sender has no idea if the packet got to the receiver unless the receiver sends a response packet.

My code continues to send the packets, even if the Linux "server" is down, without any pause or freeze. The Linux box doesn't receive the packets if I stop the UDP code, but the Arduino continues to send the packets at 5 second intervals despite that.

I don't know about your iPad code. I presume it only sends packets when responding to the Arduno sending a packet to it, correct?

I also don't know about your Arduino code rejecting packets from other devices. My Arduino code checks to insure the response packet it receives is from the ip and port of the "server" it sent the request packet to. It will ignore any packets not from the "server".