Arduino UNO and RedFly nicht stabil

Hallo zusammen,
ich habe einen Arduino Uno mit RedFly als Webserver und UDP Client im Einsatz. Leider gibt es 2 Probleme.

Problem 1: der WebServer antwortet nach 4 bis 5 Tagen nicht mehr. Das Problem liegt wahrscheinlich daran, dass ich zur Auswertung des HttpRequest die String Klasse verwende. Nun die Theorie. Da die Implementierung der String Klasse einen Memory Leak hat ist irgendwann der Hauptspeicher voll. Der Mega ist da stabiler wegen des größeren Hauptspeichers. Nun habe ich die Stringklasse durch ein Char Array ersetzt. Bei dieser Variante hängt sich der RedFly auf und startet neu. Das sieht aus wie ein Timeout auf dem RedFly.
Anbei der Code für die String Variante

Anbei die Variante mit Char Array

      char c = server.read();
      *p_httpRequest++ = c;  <--- mit Char Pointer hängt sich auf

Problem 2: Beim Senden UDP- Broadcast kommen auf dem UDP-Scanner und dem Port auf dem iPhone der durch den UDP-Broadcast gesendeten UDP String und zusätzliche sich verändernde Sonderzeichen auf. Aus meiner Sicht sieht es so aus, dass der gesendete UDP String nicht richtig terminiert ist. Ich habe durch einen Workaround dieses Problem erst mal umgangen auf dem iPhone bleibt zu klären, warum an den UDP-String zusätzliche Zeichen angehangen werden.

Vielen Dank für Eure Hilfe

WebServer.ino (8.04 KB)

prüfst du vorher server.available() ?

wann wird p_httpRequest zurückgesetzt, und wie groß ist der Puffer auf den er zeigt ?

Danke für die schnelle Antwort, der Programm Code im Anhang.

#include <RedFly.h>
#include <RedFlyServer.h>
#include <RedFlyClient.h>


#define doorBuzzerPin 7             //Pin for door buzzer
#define errorLedPin   6             //error indicator Led Pin
#define buzzerTime 5                //5s time buzzer
#define udpTime 3                   //2s do udp broadcast   
#define clientConnectionTestTime 60 //60s do client connetcion test   
#define tempPin  0                  //analogRead Pin 0   



char ssid[] = "xxxx";
char key[]="xxxx";

char router[]="192,168,1,1";
char func[]="d,t";
char ip_all_func_on[120];
char ip_all_func_off[120];



const char action_door_buzzer[] = "door_buzzer";

uint8_t http=INVALID_SOCKET;               //socket handle for Client Connect


float actualTemp = 0.0;


uint8_t bytes[4];                         //ip adress for the client connect

// Config RedFly
byte ip[4];                               //ip adress from RedFly after DHCP connect
byte mac[8];                              //mac adress of the shield


//UDP Broadcast ip
byte udpip[] = {255,255, 255, 255 };

//String httpRequest;
char *p_httpRequest;
boolean mustSwitchDoorBuzzerOff = false;  
RedFlyClient udpClient(udpip,65000);      //UDP Broadcast an Port 65000
RedFlyServer server(80);

void setup()
{
  int i;
  Serial.begin(115000);                   //init serial port and set baudrate
  while(!Serial);                         //wait for serial port to connect (needed for Leonardo only)

  pinMode(doorBuzzerPin, OUTPUT);        //door buzzer 
  pinMode(errorLedPin, OUTPUT);          //error indicator

  digitalWrite(errorLedPin, LOW);

  char *p_router = router;
  for ( int i = 0; i < 5; i++ )
  {
    bytes[i] = strtol( p_router , &p_router, 10 );
    p_router++;
  }

  //start WiFi
  while(startwifi() != 0){ 
    delay(1000); 
    digitalWrite(errorLedPin, LOW);
  }
  //init p_httpRequest
  p_httpRequest = 0;
}

void loop()
{
  
  unsigned long time;
  static unsigned long next_time_router_connect=0;
  static unsigned long next_time_udp_call=0;
  static unsigned long time_switch_off_buzzer=0;
  static uint8_t connection=0;
  char tmp[200];
  char tempStr[10];

  time = millis();
 
  
  // do door buzzer
  //if (httpRequest.indexOf(action_door_buzzer) >0) 
  if(strstr(p_httpRequest,action_door_buzzer))
  {
    debugoutln("Door buzzer switch on");
    digitalWrite(doorBuzzerPin, HIGH);
    time_switch_off_buzzer = time + (buzzerTime*1000UL);
    mustSwitchDoorBuzzerOff = true;
  }

  if (time > time_switch_off_buzzer && mustSwitchDoorBuzzerOff)
  {
    mustSwitchDoorBuzzerOff = false;
    debugoutln("Door buzzer switch off");
    digitalWrite(doorBuzzerPin, LOW);     // deactivate door buzzer
  }
  //httpRequest = String();                                    //init http Request String
   p_httpRequest = 0;


    if(time > next_time_udp_call)
  {
    next_time_udp_call = time + (udpTime*1000UL);           //every 2s
    udpClient.connectUDP();
    if(mustSwitchDoorBuzzerOff) udpClient.println(ip_all_func_on);
    else udpClient.println(ip_all_func_off);
    server.stop();
    udpClient.stop();
  }  


  //client code for connection test
  if(time > next_time_router_connect)                       //connection test every 60s
  {
    //new temperature measurement
    calculateActualTemperature();
    next_time_router_connect = time + (clientConnectionTestTime*1000UL); //every 60s

    http = RedFly.socketConnect(PROTO_TCP, bytes, 80);     //start connection to the router on port 80
    if(http == 0xFF)
    {
      debugoutln("client not ok");  
      RedFly.disconnect();

      if(++connection >= 3)
      {
        while(startwifi() != 0){ 
          delay(1000); 
        } //restart WiFi module
        connection = 0;
      }
    }
    else
    {
      debugoutln("client ok");
      connection = 0;
    }

  }


  //listen for incoming clients
  if(server.available()>10)
  {
    //a http request ends with a blank line
    boolean currentLineIsBlank = true;
    while(server.available())
    {
      char c = server.read();
 

      *p_httpRequest++ = c;

      if(c == '\n' && currentLineIsBlank)
      {
        //clear input buffer
        server.flush(); 

        //send standard HTTP 200 header
        server.print_P(PSTR("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"));

        //send some text
        server.println_P(PSTR("<HTML><HEAD><TITEL>RedFly und Arduino </TITEL></HEAD><BODY>"));
        server.println_P(PSTR("<table border=0 cellpadding=2 cellspacing=2 with250><tbody><tr>"));

        memset(tempStr,0,sizeof(tempStr));
        dtostrf( actualTemp, 7, 1, tempStr );                    //convert float to char  
        memset(tmp,0,sizeof(tmp));        
        sprintf_P(tmp, PSTR("<td>Temp :</td><td>%s</td></tr><tr>"),tempStr);
        server.print(tmp);


        memset(tmp,0,sizeof(tmp));  
        sprintf_P(tmp, PSTR("<td>Func :</td><td>%s</td></tr></tbody></table></body></html>"), ip_all_func_on);
        server.print(tmp);        

        break;
      }
      if(c == '\n')
      {
        //you're starting a new line
        currentLineIsBlank = true;
      } 
      else if(c != '\r')
      {
        //you've gotten a character on the current line
        currentLineIsBlank = false;
      }
    }

    //close connection
    server.stop();
  }
  else if(!server.connected()) //listening port still open?
  {
    server.stop(); //stop and reset server
    server.begin(); //start server
  }
}


void debugout(char *s)
{
  RedFly.disable();
  Serial.print(s);
  RedFly.enable();
}

void debugoutln(char *s)
{
  RedFly.disable();
  Serial.println(s);
  RedFly.enable();
}



void calculateActualTemperature()
{
  float temp_all = 0;

  for (int i=0;i<10;i++)
  {
    temp_all += (analogRead(tempPin)/2)-2;
  }
  actualTemp = temp_all/10;
}  

uint8_t startwifi()
{
  uint8_t ret;
  char ip_ch[10];
  char mac_ch[20];
  char *p_ssid = &ssid[0]; 
  char *p_key = &key[0];

  //init the WiFi module
  if(RedFly.init(115000,HIGH_POWER) != 0) //LOW_POWER MED_POWER HIGH_POWER
  {
    digitalWrite(errorLedPin, HIGH);
    debugoutln("Fehler 1");
    return 1;
  }

  //join network the ssid of network must be visible
  RedFly.scan();


  ret = RedFly.join(p_ssid, p_key, INFRASTRUCTURE);
  if(ret)
  {
      digitalWrite(errorLedPin, HIGH);
      debugoutln("Fehler ssid key");
      return 2;
  }    


  ret = (RedFly.begin() !=0);
  if (ret)
  {
    digitalWrite(errorLedPin, HIGH);
    debugoutln("Fehler 3");
    RedFly.disconnect();
    return 3;
  }

  memset(ip_all_func_on,0,sizeof(ip_all_func_on));  // initialize ip adress, function for udp
  memset(ip_all_func_off,0,sizeof(ip_all_func_off));
  memset(mac,0,sizeof(mac));
  RedFly.getlocalip(ip); //receive shield IP 
  RedFly.getmac(mac);


  for (int i=0;i<6;i++)      //build mac adress is used for udp broadcast
  {
    memset(ip_ch,0,sizeof(ip_ch));
    itoa(mac[i],ip_ch,10);
    if(i==0) strcpy(ip_all_func_on,ip_ch);
    else
    {
      strcat(ip_all_func_on,ip_ch);
      if (i==5) strcat(ip_all_func_on,",");
      else strcat(ip_all_func_on,"-");
    }
  }  

  for (int i=0;i<4;i++)      //build ip adress is used for udp broadcast
  {
    memset(ip_ch,0,sizeof(ip_ch));
    itoa(ip[i],ip_ch,10);
    strcat(ip_all_func_on,ip_ch);
    if (i==3) strcat(ip_all_func_on,",");
    else strcat(ip_all_func_on,".");
  } 


  strcpy(ip_all_func_off,ip_all_func_on);
  strcat(ip_all_func_on,"on");
  strcat(ip_all_func_on,",2,");

  strcat(ip_all_func_on,func);
  ip_all_func_on[strlen(ip_all_func_on)] = '\0';
  
  strcat(ip_all_func_off,"off");
  strcat(ip_all_func_off,",2,");
  strcat(ip_all_func_off,func);

  ip_all_func_off[strlen(ip_all_func_off)] = '\0';
  server.begin();
  return 0;      
}

WebServer.ino (7.52 KB)

wann wird p_httpRequest zurückgesetzt, und wie groß ist der Puffer auf den er zeigt ?

Die grundsätzliche Frage war meiner Kristallkugel gar nicht in den Sinn gekommen:
… und wohin zeigt p_httpRequest überhaupt ?

So ist doch der Pointer definiert char *p_httpRequest; Und dann werden nacheinander die char's dem inkrementierten Pointer zugewiesen.
char c = server.read();

*p_httpRequest++ = c;

Oder mache ich einen Denkfehler?

Ich habe das Ganze auch über ein char Array versucht und jedes einzelne Byte aus dem server.read in ein Byte des Arrays geschrieben, da war der gleiche Effekt festzustellen, dass beim httpRequest[index] = c; der RedFly neu startet.

Ich sehe nur

p_httpRequest=0;

... das ist sicher kein guter RAM- Bereich.

Du brauchst schon irgendwo einen Platz wo die gelesenen Zeichen hin können.

char httpRequest[80];
...
p_httpRequest = httpRequest; // initialisieren
if (server.available() > 0 ) {
char c = server.read();
*p_httpRequest++ = c;
if ( c == '\n' ) {
*p_httpRequest = 0; // Ende-Kennung
// Zeile auswerten, z.B. mit strstr oder so
p_httpRequest = httpRequest; // für nächste Zeile, falls erforderlich p_httpRequest wieder zurücksetzen
}
}

Danke für die Hilfe,

funktioniert die Verbindung zwischen char array und Pointer nicht so?

char *p_httpRequest = &httpRequest[0];

ja, &httpRequest[0] ist das gleiche wie httpRequest ( die Adresse des ersten ( nullten ) Zeichens ),
wenn dieses Array in einer ausreichenden Größe erstmal definiert ist.

ich habe die Änderungen entsprechend Deiner Vorschläge gemacht, leider ohne Erfolg.

das Witzige ist ein Beispiel vom RedFly-Hersteller funktioniert. Die Verarbeitung erfolgt gleich nach dem
der httpRequest kam und nicht erst im nächsten Schleifendurchlauf

void loop()
{
  char file[32], param[64], *ptr, *p1, *p2, *p3;
  int c, i, len;

  //NBNS service routine
  NBNS.service();

  //listen for data (HTTP server)
  if(server.available() > 10)
  {
    //analyze HTTP header/request
    file[0] = 0;
    server.read((uint8_t*)file, 4);
    if(strncmp_P(file, PSTR("GET "), 4) == 0) 
    {
      //get file
      file[0] = 0;
      ptr = file;
      do
      {
        c = server.read();
        if(isalnum(c) || (c == '/'))
        {
          *ptr++ = c;
          *ptr   = 0;
        }
      }while((c != ' ') && (c != '?') && (c != -1));

      //get parameter
      param[0] = 0;
      p1       = 0;
      p2       = 0;
      p3       = 0;
      if(c == '?')
      {
        //read parameter
        ptr = param;
        len = 0;
        do
        {
          c = server.read();
          if((c != ' ') && (len < (sizeof(param)-1)))
          {
            *ptr++ = c;
            *ptr   = 0;
            len++;
          }
        }while((c != ' ') && (c != '\n') && (c != '\r') && (c != -1));

        //decode paramter
        ptr = param;
        while(len != 0)
        {
               if(strncasecmp(ptr, "p1=", 3) == 0)
          { ptr+=3; len-=3; p1=ptr; i=url_decode(ptr, ptr, len); ptr+=i; len-=i; }
          else if(strncasecmp(ptr, "p2=", 3) == 0)
          { ptr+=3; len-=3; p2=ptr; i=url_decode(ptr, ptr, len); ptr+=i; len-=i; }
          else if(strncasecmp(ptr, "p3=", 3) == 0)
          { ptr+=3; len-=3; p3=ptr; i=url_decode(ptr, ptr, len); ptr+=i; len-=i; }
          else
          {
            ptr++; 
            len--;
          }
        }
      }

WebServer.ino (7.7 KB)

Ja, gutes Beispiel:

char file[32]; // Der Puffer, sowohl für den Namen und für den ersten Test ob gerade die "GET … " Zeile gelesen wird

if(server.available() > 10) { // Die Mindestlänge an Daten

server.read((uint8_t*)file, 4);
if(strncmp_P(file, PSTR("GET "), 4) == 0) // Wenn die ersten 4 Zeichen "GET " sind …

ptr = file; // ptr initialisieren ( entspricht deinem p_httpRequest = httpRequest; )

*ptr++ = c; // Zeichen sammeln
*ptr = 0; // und gleich EndeKennung dran

Aber wo liegt das Problem bei meinem Programm. Ist im vorherigen Post im Anhang. In der init() wird der Pointer mit einem char Array verbunden. p_httpRequest = httpRequest httprequest ist char[100] und in der loop() wird er der Pointer inkrementiert und Byte für Byte aus dem server.available gefüllt. Was ist da falsch. Mit meiner String Variante hat es ja auch funktioniert. Was bleibt, die loop aus dem Beispiel bei mir schrittweise anzupassen. Oder hast Du noch einen Vorschlag

Was bleibt, die loop aus dem Beispiel bei mir schrittweise anzupassen. Oder hast Du noch einen Vorschlag

Schrittweise ist immer gut. Serial.print testausgaben auch ...

if(strstr(p_httpRequest,action_door_buzzer))

Ist der Pointer schon zurückgesetzt ?, oder solltest du nicht besser im kompletten Text suchen ? strstr(httpRequest,action_door_buzzer)
strstr findet nur exaxte Übereinstimmung (richtige Groß/Klein-Schreibung).