[SOLVED]Electron not receiving UDP messages

Hello.

I have just tested an application where an electron sends UDP messages to my own server -the elctron is not connected to Particle’s cloud- and the server answers either with an OK or a command. I have tested the same software with a Photon and it works correctly. Bunt when using the electron, it does not receive the answers from the server.

The server also receives commands from a PC using the same kind of UDP messages and the PC also receives the server answers. Is it possible that the cellular provider refuses to deliver the messages to the electron? I am really puzzled as I am sure that the program is correct, so I cannot understand what is happening.

Thank you very much for your help.
Germán Fabregat.

What port are you answering to?
If you show your code (or a compressed version of it that exhibits that behaviour) for both sides of the connection we could have a look at it.

Thank you again for your fast answer.

The electron is listening at port 10000. Te code uses normal UDP sockets on the server side, gets the IP from the received message and sends to this IP, port 100000. The code works on the photon and a PC -c code using sockets. I have no problem in posting my code if the port number does not clarify the problem.

Thank you very much,
Germán.

This is the loop on my Electron program. It connects to the cellular netowrk and sends a message. If it receives an answer it goes to sleep. Else it claims the answer to the server until one is received. On the Photon everything run without problems, using WiFi obviously. On the Electron, the server gets all messages but apparently the Electron does not get the answer as it continues to claim for it until I power it off.

void loop()
{
  int recData, i;
  unsigned int command;
  char *msg;
  float charge;
  static float tlast, hlast;
  static bool charging = false;
  // To prevent flashing blue?
  int conCount = 0;

  delay(100);
  // Check for battery status. If below low threshold,
  // activate charge. If over high, deactivate.
  charge = battery.getSoC();
  if (!charging && (charge < BATT_LOW)) {
    digitalWrite(BAT_PIN, HIGH);
    charging = true;
  }
  else if (charging && (charge > BAT_HIGH)) {
    digitalWrite(BAT_PIN, LOW);
    charging = false;
  }
  switch (st) {

    case SEND:
        // Always connect at the beginning of the state
        Cellular.on();
        Cellular.connect(WIFI_CONNECT_SKIP_LISTEN);
        // and wait for IP
        while(!Cellular.ready()) {
          delay(1000);
          conCount++;
          if (conCount == MAXCONTRY)
          System.sleep(SLEEP_MODE_DEEP, CONWAITMIN * 60L);
        }
        // Create UDP framework
        skt.begin(REC_PORT);
        // Read values
        measure();
        tlast = d.temp;
        hlast = d.hum;
        // Deactivate
        digitalWrite(LIGHT_ENA, LOW);
        // Send data
        skt.sendPacket((char *)&d, sizeof(d), rIP, SEND_PORT);
        // Wait order o confirmation, setting a timer
        st = LISTEN;
        waitAnswer = millis();
        countRetry = 0;
        if (dispON)
          dispShow(tlast, hlast, "");
    break;

    case LISTEN:
        recData = skt.receivePacket((char *)&command, sizeof(int));
        if (recData < 0) {
          // An error has occurred. Restart UDP server and go on.
          skt.begin(REC_PORT);
          // And count the number of errors
          countError++;
          st = RECEIVED;
          if (dispON)
            dispShow(tlast, hlast, "Error RED");
        }
        else if (recData > 0) {
          // Process data
          st = RECEIVED;
          if (command == CMD_OK) {
            if (dispON)
              dispShow(tlast, hlast, "Ack OK");
            break;
          }
          switch(command & 0xFF00) {
            // Activate pin and set bit in deepSleep
            case CMD_DEVON:
               digitalWrite(devices[command & 0xFF], HIGH);
               deepSleep |= 1 << (command & 0xFF);
               msg = "Ack DevOn";
            break;
            case CMD_DEVOFF:
                digitalWrite(devices[command & 0xFF], LOW);
                deepSleep &= ~(1 << (command & 0xFF));
                 msg = "Ack DevOff";
            break;
            case CMD_DISPON:
               dispON = true;
               deepSleep |= DISPBIT;
               display.begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
               msg = "Ack DispOn";
            break;
            case CMD_DISPOFF:
               dispON = false;
               deepSleep &= ~DISPBIT;
               display.clearDisplay();
               display.display();
               msg = "Ack DispOff";
            break;
            case CMD_ALLOFF:
               dispON = false;
               deepSleep = 0;
               for (i = 0; i < NDEV; i++)
                 digitalWrite(devices[i], LOW);
               display.clearDisplay();
               display.display();
               msg = "Ack AllOff";
            break;
          }
          if (dispON)
            dispShow(tlast, hlast, msg);
        }
        else {
          // Waiting. Verifiy elapsed time and resend if not received
          if ((millis() - waitAnswer) > WAIT_TIME) {
            // Prepare data to claim answer
            d.light = CMD_RETRY;
            d.temp = 0.0;
            d.hum = 0.0;
            // Send data to claim the answer again
            skt.sendPacket((char *)&d, sizeof(d), rIP, SEND_PORT);
            waitAnswer = millis();
            // And count the number of timeouts
            countRetry++;
            if (dispON)
              dispShow(tlast, hlast, "Error MSG");
          }
        }

    break;

    case RECEIVED:
        // Network activity is over, so disconect
        Cellular.off();
        // Sleep only if safe pin low and no device is on
        if ((deepSleep == 0) && (digitalRead(SAFE_PIN) == LOW))
            System.sleep(SLEEP_MODE_DEEP, WAITMIN * 60L);
        // Else just wait and reactivate enables
        else {
          delay(WAITMIN * 60000L);
          digitalWrite(LIGHT_ENA, HIGH);
          st = SEND;
        }
    break;
  }
}

=================================================
And this is the server main code. Just waits for a message and logs it to a file -or console in debug mode-. According
to the higher byte of an integer determines the type of message. If it is a command, queues it, if it is a claim resends
the last answer. If it is a data message, sends the first command on the queue or ok.

int main()
{
 struct in_addr c_ip;
 int mi_ip, err, tam, resp, lastData, lastAction;
 char name[NAMELEN], ipc[NAMELEN], txt[NAMELEN];
 unsigned char orden;
 struct hostent *ipdir;
 struct sockaddr_in miSocket, recSocket, cmpSocket;
 SOCKET miConexion;
 struct info data;
 struct tm *t;
 time_t now;
#ifndef DEBUG
 FILE *file;

 if ((file = fopen(logFile, "a")) == NULL)
     exit(EXIT_FAILURE);
#endif


// Leemos el nombre de nuestro ordenador, y la IP desde el nombre
 err = gethostname(name, NAMELEN);
 ipdir = gethostbyname(name);
 if ((ipdir == NULL) || (err == SOCKET_ERROR)) {
    PUTS("Error inesperado detectando parametros de red\n");
    exit(EXIT_FAILURE);
 }
 mi_ip = *((int *)(ipdir->h_addr));
 c_ip.s_addr = mi_ip;
 strcpy(ipc, inet_ntoa(c_ip));
// Si no hay error damos la informacion leida
 sprintf(txt, "Configuracion de red correcta.\n   Nombre: %s\n   Dir.IP: %s\n", name, ipc);
 PUTS(txt);    
    
// Creamos la conexion tipo INET y protocolo UDP (DGRAM)
 if ((miConexion = socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR) {
    PUTS("Imposible crear el socket para recibir\n");
    exit(EXIT_FAILURE);
 }
// Creamos el socket
 miSocket.sin_family = AF_INET;
 miSocket.sin_addr.s_addr = INADDR_ANY;
 miSocket.sin_port = htons(PUERTO);
// y lo activamos para escuchar de el
 if (bind(miConexion, (SOCKADDR *)&miSocket, sizeof(miSocket))) { 
    PUTS("Error en el bind del socket\n");
    exit(EXIT_FAILURE);
 }
    
// Todo ha ido bien. Entramos en el bucle de recepción y proceso de datos.
 PUTS("Socket creado y listo para recibir\n");
#ifndef DEBUG
 fclose(file);
#endif
 tam = sizeof(recSocket);
 cmpSocket.sin_port = 0;

// Creamos la cola de acciones
 actQ.head = 0;
 actQ.tail = 0;
 actQ.used = 0;

 while (1) {
   err = recvfrom(miConexion, &data, sizeof(data), 0, (SOCKADDR *) &recSocket, &tam);
#ifndef DEBUG
   if ((file = fopen(logFile, "a")) == NULL)
     exit(EXIT_FAILURE);
#endif
   if (err == SOCKET_ERROR)
      PUTS("Error recibiendo datos\n");
   else {
      now = time(NULL);
      t = localtime(&now);
      if ((cmpSocket.sin_addr.s_addr != recSocket.sin_addr.s_addr) || (cmpSocket.sin_port != recSocket.sin_port)) {
        cmpSocket.sin_addr = recSocket.sin_addr;
        cmpSocket.sin_port = recSocket.sin_port;
          sprintf(txt, "Datos recibidos de %s:%d\n", inet_ntoa(recSocket.sin_addr), recSocket.sin_port);
    PUTS(txt);
      }
      // El byte más alto de la luz nos indica si son datos (0) u otra cosa.
      orden = (data.light >> 24) & 0xFF;
      switch (orden) {
        // Mensaje normal de datos. Enviamos la respuesta que sale de la cola. Será OK si está vacía.
        case DATA: 
             sprintf(txt, "%d/%d %2d:%02d %d;%.2f;%.2f\n", t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, data.light, data.temp, data.hum);
             PUTS(txt);
           resp = getResp();
       lastData = resp;
        break;

        // Reclaman respuesta de datos. Se envía la última.
        case CLAIMDATA:
       resp = lastData;
       sprintf(txt, "Resend DOK: %08X\n", resp);
             PUTS(txt);
        break;
    
    // Encolamos la accion, devolvemos OK si todo va bien o NOADM si hay error.
        case ACTION:
           resp = setResp(data.light & 0xFFFF);
           lastAction = resp;
           sprintf(txt, "Received action: %04X\n", data.light & 0xFFFF);
             PUTS(txt);
        break;

        case CLAIMACTION:
       resp = lastAction;
       sprintf(txt, "Resend AOK: %08X\n", resp);
             PUTS(txt);
        break;
      }
      recSocket.sin_port = htons(PUERTO_SEND);
      err = sendto(miConexion, &resp, sizeof(int), 0, (SOCKADDR *) &recSocket, tam); 
      if (err == SOCKET_ERROR)
         PUTS("Error enviando datos\n");
#ifndef DEBUG
 fclose(file);
#endif
   }
 }
}

Regards and thank you.

AFAIK, the port you need to answer to is not the port the device is listening on but the port you get handed as remote port, since the network provider will do a translation in between.

1 Like

Yes, what ScruffR said is correct. When responding to a UDP request from an Electron you must respond to the port the request came from, not the port that they Electron is listening on. The carrier does port forwarding for reply packets.

2 Likes

Thank you very much, it works now.

Really I do very much appreciate your help and your reponsiveness to help developers.

Best regards, and many, many thanks.
Germán.

2 Likes