Arduino Web Server Cannot Log Data to SD Card

Hello everybody!

I’m setting up a Web Server to control a couple of devices and log some temperatures on a SD card.
I have an index.htm file (found on the SD card) served from arduino upon a web request and a datalog.txt where I want to save data.

The problem is only the saveSD function, it always prints “error opening datalog.txt”; the rest of the code works perfectly: the card is initialized, I can change the state of the devices, I can read the log remotely and I can read the analog values.

I guess that there is some conflict inside the loop function, but I can’t find it. If I test only the setup function (with a empty loop), the saveSD works fine.

Can someone help me find the problem?
I have added the full code as an attachment.

Loop function

 EthernetClient client = server.available();  // try to get client

  if (client) {  // got client?
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {   // client data available to read
        char c = client.read(); // read 1 byte (character) from client
        // buffer first part of HTTP request in HTTP_req array (string)
        // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c;          // save HTTP request character
          req_index++;
        }
        // last line of client request is blank and ends with \n
        // respond to client only after last line received
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: keep-alive");
          client.println();
          // Ajax request
          if (StrContains(HTTP_req, "analog")) {
            // send XML file containing input states
            GetAnalogState(client);
          }
          else if (StrContains(HTTP_req, "StufaOn")){
            digitalWrite(5, HIGH);
            client.println("Stufa --> ON");
            Serial.println("Stufa --> ON");
          }
          else if (StrContains(HTTP_req, "StufaOff")){
            digitalWrite(5, LOW);
            client.println("Stufa --> OFF");
            Serial.println("Stufa --> OFF");
          }
          else if (StrContains(HTTP_req, "CondizOn")){
            digitalWrite(6, HIGH);
            client.println("Condizionatore --> ON");
            Serial.println("Condizionatore --> ON");
          }
          else if (StrContains(HTTP_req, "CondizOff")){
            digitalWrite(6, LOW);
            client.println("Condizionatore --> OFF");
            Serial.println("Condizionatore --> OFF");
          }
          else if (StrContains(HTTP_req, "log")){

            
            logFile = SD.open("datalog.txt");        // open log file
            if (logFile) {
              while (logFile.available()) {
                client.write(logFile.read()); // send log file to client
              }
              logFile.close();
            }
          }
          else {  // web page request
            // send web page

              webFile = SD.open("index.htm");        // open web page file
            if (webFile) {
              while(webFile.available()) {
                client.write(webFile.read()); // send web page to client
              }
              webFile.close();
            }
          }
          // display received HTTP request on serial port
          Serial.println(HTTP_req);
          // reset buffer index and all buffer elements to 0
          req_index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          break;
        }
        // every line of text received from the client ends with \r\n
        if (c == '\n') {
          // last character on line of received text
          // starting new line with next character read
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // a text character was received from client
          currentLineIsBlank = false;
        }
      } // end if (client.available())
    } // end while (client.connected())
    delay(1);      // give the web browser time to receive the data
    client.stop(); // close the connection
  } // end if (client)


  // log data every now and then
  currentTime = millis();
  if(currentTime - prevTime > interval){
    prevTime = currentTime;
    String data = createData();
    saveSD(data);
  }

saveSD function

void saveSD (String dataToSave)
{
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataToSave);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataToSave);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }

}

webserver_ino.ino (7.83 KB)

Is the datalog.txt file permissions set to read-only? If so, you can't open it for writing.

SurferTim: Is the datalog.txt file permissions set to read-only? If so, you can't open it for writing.

No, it isn't. When I launch the code with the loop function empty, the saveSD function works fine.

Is the Arduino an Uno? If so, you may be running out of SRAM. That will cause the SD.open() call to fail.

Try using the F() function to keep your static strings in program memory. Like this:

          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: keep-alive"));

Do that to all your static strings. See if that makes a difference.

SurferTim: Is the Arduino an Uno? If so, you may be running out of SRAM. That will cause the SD.open() call to fail.

Try using the F() function to keep your static strings in program memory. Like this:

          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: keep-alive"));

Do that to all your static strings. See if that makes a difference.

And now it works! Thank you very much!

For future reference, is there a funcion I could you to print on Serial the status of SRAM?

Add this function to your code.

int freeRam() {
 extern int __heap_start,*__brkval;
 int v;
 return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}

// then you use it like this
 Serial.print(F("SRAM available: "));
 Serial.println(freeRam());

If you run out of SRAM, this function does not return 0, but a negative or unrealistically large value.