Listing + writing files simultaneously.

I am building a data logger / web server for home power monitoring using the W5100/SD sheild and an Atmega2560.

I added the capability to list the files to the web client and now writing to the current day's file is failing.

I've cut the code down a bit to paste here (no ntp/date stuff). Probably a bit out of my depth here, not familiar with initializing a volume and defining a root file but I have a hunch that something in the setup has screwed up the file writing.

void setup() {

  // Open serial communications
  Serial.begin(9600);

  // disable w5100 while starting SD  
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  pinMode(AmpPin,INPUT);


 // Serial.print(F("Starting SD..."));
//  if(!sd.begin(chipSelect, SPI_HALF_SPEED)) Serial.println(F("failed"));
//  else Serial.println(F("ok"));
  
   PgmPrint("Free RAM: ");
  Serial.println(FreeRam());  
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH);                    // but turn off the W5100 chip!
  Serial.print(F("Starting SD..."));
  if (!card.init(SPI_HALF_SPEED, chipSelect)) error("card.init failed!");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();
  
  if (!root.openRoot(&volume)) error("openRoot failed");

  // list file in root with date and size
  PgmPrintln("Files found in root:");
  root.ls(LS_DATE | LS_SIZE);
  Serial.println();
  
  // Recursive list of all directories
  PgmPrintln("Files found in all dirs:");
  root.ls(LS_R);
  
  Serial.println();
  PgmPrintln("Done");
  
  // start Ethernet and UDP
  Serial.print(F("Starting w5100..."));
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }  

--------------------------//--------------------------//--------------------------//

void saveFileRecord() { //creates the filename from the data string and opens/creates the file and saves a record in the file

  char filename_Rec[9] = "000000.d";
  int WattsWrite = watts; //truncate the float value watts to an integer

  filename_Rec[0] = date[0];
  filename_Rec[1] = date[1];
  filename_Rec[2] = date[3];
  filename_Rec[3] = date[4];
  filename_Rec[4] = date[8];
  filename_Rec[5] = date[9]; 

Serial.print("Current File: ");
Serial.println(filename_Rec);

  if (!dataFile.open(filename_Rec, O_RDWR | O_CREAT | O_AT_END)) {
    Serial.println("error writing file");
  }
  else{
    Serial.println("Writing to file : ");                 
    Serial.println(filename_Rec);

    dataFile.print(WattsWrite);
    dataFile.print(" ");
    dataFile.print(KWH);
    dataFile.print(" ");
    dataFile.print(Hour); // hour stored in variable because of the MST conversion in GetNTPTime
    dataFile.print(":");
    dataFile.print((epoch  % 3600) / 60); //mins
    dataFile.print("\n"); //newline

    Serial.println("\n");
    dataFile.close();
    Serial.println("done");
  }
}


void ListFiles(EthernetClient client, uint8_t flags) {
  // This code is just copied from SdFile.cpp in the SDFat library
  // and tweaked to print to the client output in html!
  dir_t p;
  //root.seekSet(0);
  
  Serial.println("Listing Files for client");
  Serial.println(root.readDir(&p));
  root.rewind();
  client.println("<ul>");
  while (root.readDir(&p) > 0) {
  
    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) break;

    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

    // print any indent spaces
    client.print("<li><a href=\"");
    for (uint8_t i = 0; i < 11; i++) {
  
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    client.print("\">");
    
    // print file name with possible blank fill
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    
    client.print("</a>");
    
    if (DIR_IS_SUBDIR(&p)) {
      client.print('/');
    }

    // print modify date/time if requested
    if (flags & LS_DATE) {
       root.printFatDate(p.lastWriteDate);
       client.print(' ');
       root.printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    client.println("</li>");
  }
  client.println("</ul>");
}


void webClient() 
#define BUFSIZ 100
{
  char clientline[BUFSIZ];
  int index = 0;
  
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    
    // reset the input buffer
    index = 0;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        
        // If it isn't a new line, add the character to the buffer
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ) 
            index = BUFSIZ -1;
          
          // continue to read more data!
          continue;
        }
        
        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;
        
        // Print it out for debugging
        Serial.println(clientline);
        
        // Look for substring such as a request to get the root file
        if (strstr(clientline, "GET / ") != 0) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println(KWH);
          client.print(" kwh ");
          client.println(watts);
          client.print("watts");
          
          Serial.print(checkget);
          
          // print all the files, use a helper to keep it clean
          client.println("<h2>Files:</h2>");
          ListFiles(client, LS_SIZE);
       
       // debug - remove -----------------------------------------------------------------------------------------------------------------------------------------------
          client.println("<a href=260616.d>");
          client.print("260616.d");
          client.print("</a>");
       // debug - remove ----------------------------------------------------------------------------------------------------------------------------------------------- 
          
        } else if (strstr(clientline, "GET /") != 0) {
          // this time no space after the /, so a sub-file!
          char *filename_web;
          
          filename_web = clientline + 5; // look after the "GET /" (5 chars)
          // a little trick, look for the " HTTP/1.1" string and 
          // turn the first character of the substring into a 0 to clear it out.
          (strstr(clientline, " HTTP"))[0] = 0;
          
          // print the file we want
          Serial.println(filename_web);

          if (! file.open(&root, filename_web, O_READ)) {
            client.println("HTTP/1.1 404 Not Found");
            client.println("Content-Type: text/html");
            client.println();
            client.println("<h2>File Not Found!</h2>");
            break;
          }
          
          Serial.println("Opened!");
                    
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/plain");
          client.println();
          
          int16_t c;
          while ((c = file.read()) > 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              client.print((char)c);
          }
          file.close();
        } else {
          // everything else is a 404
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File Not Found!</h2>");
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

dhymers:
I am building a data logger / web server for home power monitoring using the W5100/SD sheild and an Atmega2560.

I added the capability to list the files to the web client and now writing to the current day's file is failing.

I've cut the code down a bit to paste here (no ntp/date stuff). Probably a bit out of my depth here, not familiar with initializing a volume and defining a root file but I have a hunch that something in the setup has screwed up the file writing.

So, the file is failing, did it get a 'D' or an 'F'?

Personally I always thought a 'C' was failing.

Does my non sequitur make any sense to you?

Chuck.

p.s. You need to explain what you mean by failing. If you expect anyone to guess how to recommend a 'fix' we must know the problem. 'failing' could be Yellow or Green.

When I call

void saveFileRecord()

It's unable to create the file which I think might have something to do with having a whole bunch of other SD variables flying around which enabled listing the files to the webserver. (in void setup():wink:

So this piece "fails"

if (!dataFile.open(filename_Rec, O_RDWR | O_CREAT | O_AT_END)) {
    Serial.println("error writing file");
  }

or rather it works exactly as it should, it passes with flying marks by letting me know something screwed up :slight_smile:

Heres the main loop, when I comment out calling webclient(); it makes no difference. webclient calls listfiles in the event of a client request but savefilerecord should occur once every 30 seconds.

void loop() {

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= Eight_sec_int) {
    previousMillis = currentMillis;   
    GetNTPTime(); // get and print NTP/MST time to the serial port
    Serial.println(watts);
    Serial.println(KWH);
    saveFileRecord(); //save the current reading from the sensor in the file with the current date
  }

  AmpRead = map(analogRead(AmpPin), 1023, 0, 0, 50); //read current
  watts = (AmpRead * 240); ///// -------------------- watts calculated here, change for 1 or 2 pole circuit voltage
  KWH = KWH +(watts * sec2Hr) /1000; //calc power
   webClient();

}

Thanks for your interest, I hope this is a bit more helpful.

#include <Ethernet.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SPI.h>
#include <EthernetUdp.h>

SdFat sd;   //instance for sdfa
const int chipSelect = 4;

// file handeling vars

SdFile dataFile;
SdFile root;
boolean datewrite = true;
Sd2Card card;
SdVolume volume;
SdFile file;

void setup() {

  // Open serial communications
  Serial.begin(9600);

  // disable w5100 while starting SD  
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  pinMode(AmpPin,INPUT);


 // Serial.print(F("Starting SD..."));
//  if(!sd.begin(chipSelect, SPI_HALF_SPEED)) Serial.println(F("failed"));
//  else Serial.println(F("ok"));
  
   PgmPrint("Free RAM: ");
  Serial.println(FreeRam());  
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
  digitalWrite(10, HIGH);                    // but turn off the W5100 chip!
  Serial.print(F("Starting SD..."));
  if (!card.init(SPI_HALF_SPEED, chipSelect)) error("card.init failed!");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("vol.init failed!");

  PgmPrint("Volume is FAT");
  Serial.println(volume.fatType(),DEC);
  Serial.println();
  
  if (!root.openRoot(&volume)) error("openRoot failed");

  // list file in root with date and size
  PgmPrintln("Files found in root:");
  root.ls(LS_DATE | LS_SIZE);
  Serial.println();
  
  // Recursive list of all directories
  PgmPrintln("Files found in all dirs:");
  root.ls(LS_R);
  
  Serial.println();
  PgmPrintln("Done");
  
  // start Ethernet and UDP
  Serial.print(F("Starting w5100..."));
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }  

  // start the Ethernet connection and the server:
  Serial.print("\n");  
  Serial.println(F("Starting w5100..."));  
  //  Ethernet.begin(mac, ip); <- will not work using the SD card and trying to get NTP time...
  server.begin();
  Serial.print("ok, server is at: ");
  Serial.println(Ethernet.localIP());

  //start UDP  
  Udp.begin(localPort);

  GetNTPTime(); // grab time for the first time, once
  SetDate(); // set the date string once at setup
  printDate(); // print the date to the serial port
  
  root.close();
  
   if (!file.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
    sd.errorHalt("opening test.txt for write failed");
  }
 
}

Even attempting to create a file at startup fails, what could be going wrong ? I've reformatted the SD using the SDfat sketch and tried a second SD, no joy, it will not write a file, only list files/dirs and read from them.

The errorHalt spits out

"error: opening test.txt for write failed
SD errorCode: 0X19,0X0"