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.