UDP read fails as Photon restarts

In my project I send UDP data every 10 millisecond. Each UDP packet is 2338 bytes. It works great for a few minutes untill my Photon gets “Device went offline”. It takes some time before it comes online again and even though I contintue to send my UDP data it does not receive it as it restarts again. Why does it restart all the time anyway?

Is there a way to restart the code as it comes online again?

Here it my code:

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  myIP = WiFi.localIP();

  if (Udp.setBuffer(EXPECTED_PACKED_SIZE))
    Udp.begin(localPort);

  String ip_str = String(myIP);
  Particle.publish(ip_str, "1");
}

void loop() {
  int32_t bytes = Udp.parsePacket();

  if (bytes >= EXPECTED_PACKED_SIZE) {

    // Read first char of data received
    char data[EXPECTED_PACKED_SIZE];
    Udp.read(data, EXPECTED_PACKED_SIZE);
    // Ignore other chars

    Udp.flush();
    int offset = 0;
    int count = 0;
    strip.setBrightness(10);

    for (int i = 0; i < 167; i++) {
      int neopixel = String(String(data[0 + offset]) + String(data[1 + offset]) + String(data[2 + offset])).toInt();

      String red = String(data[4 + offset]) + String(data[5 + offset]) + String(data[6 + offset]);
      String blue = String(data[7 + offset]) + String(data[8 + offset]) + String(data[9 + offset]);
      String green = String(data[10 + offset]) + String(data[11 + offset]) + String(data[12 + offset]);

      strip.setPixelColor(neopixel, red.toInt(), blue.toInt(), green.toInt());
      offset = offset + 14;
    }
    // 001:255255255;

    strip.show();




  }
  //Particle.publish("red","1");
  // strip.show();

}

This it my log:

Hi @ellensundh

Do you see a red flashing SOS pattern on the main LED when it fails? You migth see a red LED flash SOS, followed by a number of flashes (count them) and then another SOS.

https://docs.particle.io/guide/getting-started/modes/photon/#red-flash-sos

I think you could be having memory troubles with your String’s.

3 Likes

Thanks for your fast reply! No SOS flashing. Do you have any advice on how to handle the strings in a more efficient way?

If your format is free to be adaped, I’d suggest to going binary rather than text, but if you want to stick to your format then something like this can avoid String completely

  char token[4];
  int px,r,g,b;
  ...
    for (int i = 0; i < 167; i++) 
    {
      memcpy(token, &data[0+offset], 3); // copy 3bytes over to a single token
      token[3] = 0; // terminate that string
      px = atoi(token); // convert ASCII to int

      memcpy(token, &data[4+offset], 3); // copy 3bytes over to a single token
      token[3] = 0; // terminate that string
      r = atoi(token); // convert ASCII to int

      memcpy(token, &data[7+offset], 3); // copy 3bytes over to a single token
      token[3] = 0; // terminate that string
      b = atoi(token); // convert ASCII to int

      memcpy(token, &data[10+offset], 3); // copy 3bytes over to a single token
      token[3] = 0; // terminate that string
      g = atoi(token); // convert ASCII to int

      strip.setPixelColor(px, r, b, g);
      offset = offset + 14;
    }
  ...

And this could be reduced even further if the format used delimiters between each value (e.g. 001:255-255-255;002...) by use of strtok() (instead of memcpy() and manual terminating the string) and an array for your parameters (e.g. int prgb[4]; and strip.setPixelColor(prbg[0], prbg[1], prbg[2], prbg[3]);).

2 Likes

Thanks @ScruffR! Yes I changed to binary so my code looks like this but maybe I should change it even more to resemble your example?

for(int i = 0;i < 167;i++) {
    int red =  binary2decimal(data[offset]);
    offset = offset + 1;
    int blue =  binary2decimal(data[offset]);
    offset = offset + 1;
    int green =  binary2decimal(data[offset]);
    offset = offset + 1;
    
    strip.setPixelColor(i, red, blue, green);
}

int binary2decimal(byte b) {
 int dec = 0;
 int power = 1;
 byte mask; 
 int weight;

  for (mask = 0x01; mask; mask <<= 1) {
    if (b & mask) {
      weight = 1;     
    } else {
 weight = 0;     
    }

    dec = dec + (power * weight);   
    power = power * 2; 

 }

  return dec;
    }

No, binary is fine (FWIW, I’d prefere it anyway :wink: )
Are you sending BCD data? Only then you’d need a binary2decimal conversion. If you are already receiving raw binary, you could just write

  uint8_t data[EXPECTED_PACKED_SIZE];
  ...
  for(int i = 0;i < 167;i++) {  
    strip.setPixelColor(i, data[i*3 +0], data[i*3 +1], data[i*3 +2]);
  }

Just a note:
You are using mask <<= 1 for the bit to shift, but further down power = power * 2 but actually both do the same thing. Shift left by one is an integer multiplication by two (right shift is integer division by two) - as long the result still fits the data type.

3 Likes

2000+ bytes for a UDP packet is large. You run the risk of the packet being fragemented and parts of it lost. Any reason to chose UDP over TCP for this application?

Yes, I went down to 511 bytes now. I want to use UDP because I want to stream new information to the Photon fast. @mdma

That’s a much better size. How’s it working for you now?

Much better thank you! @mdma

2 Likes