MKR WiFi 1010: Client and server simultaneously: buffers mix up

Hi!

I have been trying to programm my Arduino MKR WiFi 1010 for the last couple of weeks and I keep getting stuck. Firmware is 1.3.0 (latest as of writing), certificates for relevant webpages are installed.

I am running a webserver on the LAN and at the same time want to question a web-API periodically. What keeps happening (after some time) is, that after the request to the web-API is made (via connectSSL()) the webserver reports an available() client and the answer of the web-API lands in the wrong buffer.

After some time, the Webserver is not reachable anymore and the device hangs.

I made a MWE which is basically a combination of the WiFiSSLClient and the SimpleWebServerWiFI examples. I can make the error happen in under 30 Seconds.

#include <SPI.h>
#include <WiFiNINA.h>


#include "settings.h" // char[] arrays: ssid, pass, apiKey, lat, lon

int wifi_status = WL_IDLE_STATUS;

// Initialize the Wifi client library
WiFiSSLClient api_client;

// server address:
char apiserver[] = "www.google.com";

char api_response[8000] = {0};


unsigned long api_lastConnectionTime = 0; //TODO           // last time you connected to the server, in milliseconds
unsigned long api_epochOffset = 0;
unsigned long api_lastCall_millis = 0;
unsigned long secs_today_in15mins = 0;
unsigned long api_interval = 30L * 1000L; // try every 30 seconds at first
unsigned long api_poweron_days = 0;

int api_parse_result = 0;

WiFiServer webserver(80);
bool wifi_noConnection = false;
unsigned long wifi_lastTry_millis = 0;


void setup()
{
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB port only
  }


}

void loop()
{
  // attempt to connect to Wifi network:
  wifi_status = WiFi.status();
  while (wifi_status != WL_CONNECTED && (!wifi_lastTry_millis || wifi_lastTry_millis + 10000 < millis()))
  {
    wifi_noConnection = true;
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network.
    wifi_status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    wifi_lastTry_millis = millis();
  }
  if(wifi_status == WL_CONNECTED && wifi_noConnection)
  {
    // you're connected now, so print out the status:
    printWifiStatus();
    wifi_noConnection = false;
    //begin listening
    webserver.begin();
  }

  // everything after here is useless without wifi
  if(wifi_status == WL_CONNECTED)
  {
    bool api_currentLineIsBlank = true;
    int pos = 0;
    bool first_read = true;
    while (api_client.available())
    {
      if(first_read)
      {
        //this is the first time, log event
        Serial.println("api incomming");
        first_read = false;
      }
      char c = api_client.read();
      Serial.print(c);
      if(api_parse_result) //this char is the first after the empty newline
      {
        if(pos >= sizeof(api_response))
        {
          break;
        }
        api_response[pos] = c;
        ++pos;
      }
  
      if (c == '\n' && api_currentLineIsBlank)
      {
        api_parse_result = 1; //this line is still \n 
      }
      if (c == '\n')
      {
        // you're starting a new line
        api_currentLineIsBlank = true;
      }
      else if (c != '\r')
      {
        // you've gotten a character on the current line
        api_currentLineIsBlank = false;
      }
    }
    //terminate with null byte
    if(pos >= sizeof(api_response))
    {
      pos = sizeof(api_response) - 1;
    }
    api_response[pos] = 0x0;
    
    if(api_parse_result)
    {
      Serial.print("api parse turn ");
      Serial.println(api_parse_result);
      //parse here
      ++api_parse_result;
    }

    if(api_parse_result && !api_client.available())
    {
      Serial.println("disconnecting from server");
      api_client.stop();
      api_parse_result = 0;
    }
    
    // listen for incoming clients
    WiFiClient webserver_client = webserver.available();
    if (webserver_client)
    {
      Serial.println("client connected");
      // an http request ends with a blank line
      bool currentLineBlank = true;
      while (webserver_client.connected())
      {
        if (webserver_client.available())
        {
          char c = webserver_client.read();
          if (c == '\n')
          {
            // if the current line is blank, you got two newline characters in a row.
            // that's the end of the client HTTP request, so send a response:
            if (currentLineBlank)
            {

              // send a standard http response header
              webserver_client.println("HTTP/1.1 200 OK");
              webserver_client.println("Content-Type: text/html");
              webserver_client.println("Connection: close");  // the connection will be closed after completion of the response
              webserver_client.println();
          
              webserver_client.println("<!DOCTYPE HTML>");
              webserver_client.println("<html>");
              webserver_client.println("<head>");
              webserver_client.println("<meta charset=\"utf-8\">");
              webserver_client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
              webserver_client.println("</head>");
              webserver_client.println("<h1>Website</h1>");
              webserver_client.println("</html>");
              break;
            }
            else
            {
              // you're starting a new line
              currentLineBlank = true;
            }
          }
          else if (c != '\r')
          {
            // you've gotten a character on the current line
            currentLineBlank = false;
            
          }
 
        }
      }  
      // close the connection:
      webserver_client.stop();
      Serial.println("client disconnected");
    }
    

    if(api_lastConnectionTime  < (double)millis() - (double)api_interval)
    {
      Serial.println("api requesting");
      // send out request to weather API
      api_lastCall_millis = millis();
      httpRequest();
    }
    
  }
    
}




// this method makes a HTTP connection to the server:
void httpRequest()
{
  // close any connection before send a new request.
  // This will free the socket on the WiFi shield
  api_client.stop();

  // if there's a successful connection:
  if (api_client.connectSSL(apiserver, 443))
  {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    api_client.println("GET / HTTP/1.1");
    api_client.println("Host: www.google.com");
    api_client.println("Connection: close");
    api_client.println();

    // note the time that the connection was made:
    api_lastConnectionTime = millis();
  }
  else
  {
    // if you couldn't make a connection:
    Serial.println("connection failed");
  }
}


void printWifiStatus()
{ 
//left out. Same as example
}

Here is the serial output. I make several connections to the device, the last at 18:05:21.420. After that the answer from the webclient ends up in the wrong buffer.

18:05:13.938 -> Attempting to connect to SSID: ***
18:05:14.141 -> ***
18:05:14.141 -> IP Address: 192.168.178.76
18:05:14.141 -> signal strength (RSSI):-35 dBm
18:05:17.103 -> client connected
18:05:17.137 -> client disconnected
18:05:17.340 -> client connected
18:05:17.375 -> client disconnected
18:05:17.375 -> client connected
18:05:17.409 -> client disconnected
18:05:17.443 -> client connected
18:05:17.443 -> client disconnected
18:05:17.477 -> client connected
18:05:17.511 -> client disconnected
18:05:19.461 -> client connected
18:05:19.494 -> client disconnected
18:05:20.406 -> client connected
18:05:20.406 -> client disconnected
18:05:21.420 -> client connected
18:05:21.453 -> client disconnected
18:05:29.056 -> api requesting
18:05:33.568 -> connecting...
18:05:33.635 -> client connected
18:05:33.703 -> client disconnected

The full code of my project is here: GitHub - Mettbrot/giessbert_wifi

What I tried:

  • making variables global
  • removing all uses of String from Sketch
  • smaller buffer size api_response[2000]. The MKR has 32Kb SRAM though.
  • delay(500) after httpRequest()

It all did not work.
Any ideas?