My logger using ReadWriteSdFat needs a little help

I am building a serial communication sketch that uses serial print and serial read to talk to a computer. I have the sketch very close using the new SdFat library. The SdFat library is AWESOME and has helped my speed so much!!! Thanks to the creator!

The only problem I have I am aware of is that it looks like I am only saving one string of data then, erasing it and doing it again. If I am correct could someone help me with the change that I need to make to the sketch?

I would like to log my communication reads until the 2GB card is full or until I turn off the unit. At the moment, I think my string is 50 Bytes long.

// Ported to SdFat from the native Arduino SD library example by Bill Greiman
// On the Ethernet Shield, CS is pin 4. SdFat handles setting SS
const int chipSelect = 8;
/*
 SD card read/write
 
 This example shows how to read and write data to and from an SD card file 	
 
 	 
 */
int startattempt = 0;     //counter for start attempts:
int  talking = 0;        // communication status bit:
String readString;        // storage for incoming characters:
int dataadd = 0;      // counter to reduce file closes:
char intalk = 0;    // incoming serial hex byte marker:
long rxbyte = 0;         //used for storing incoming :
int txbyte = 0;         //outgoing serial hex byte:
int bytecount = 0;      //may use for counting string inputs:
int outputpin = 1;      //TX pin control to for HIGH/LOW state:
int failurepin = 9;     // led pin to show card failure:
long charAt = 0;        // possibly used to find characters in string:
unsigned long previousMillis = 0;        // will store last time:
unsigned long currentMillis = 0;         // stores current time:
unsigned long interval = 150;           // interval at which to time communication events:
int i = 0;
char inChar = 0;
String stringOne = 0;   // string for storing incoming bytes
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);   // initialize the library with the numbers of the interface pins:
#include <SdFat.h>
SdFat sd;
SdFile myFile;

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);    // set up the LCD's number of columns and rows:   
  lcd.setCursor(2,1);  
  lcd.print("Ini. SD card");// Print a message to the LCD.
  Serial.print("Ini SD card"); 
  pinMode(10, OUTPUT); // default chip select pin output, even if you don't use it:
  // see if the card is present and can be initialized:

  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // change to SPI_FULL_SPEED for more performance.
  if (!sd.init(SPI_FULL_SPEED, chipSelect)) sd.initErrorHalt();

  pinMode(13, OUTPUT);

  Serial.println("serial test"); // so I can keep track of what is loaded:     
  digitalWrite(outputpin, HIGH); // digital pin 1 as an output to control communication intialization:
  delay(300);
  
  while (i < 2 && Serial.available()) {
    delay(2000); // to allow me to manually enter a number for testing:
    char c = Serial.read();
    readString += c;  
    i = i + 1;
  }
  if (readString.length() > 0 ) {
    Serial.println(readString);
    if (readString == "00" ) {
      readString = "";    // clear readstring to reuse it
      talking = 1;
      digitalWrite(13, HIGH);
      Serial.println("completed ini");
      lcd.print("completed ini");
      Serial.print(129,HEX); 
     

    }
    else { 
      digitalWrite(13, LOW);
      Serial.println(" ini. failed" );
      lcd.print(" ini. failed");
      Serial.println (readString);
      readString = "";    // clear readstring to reuse it
      talking = 0;

    }
  }
  currentMillis = millis(); 
  previousMillis = currentMillis; // set the time counter: 
}




void loop() {

  Serial.println (talking);

  while (talking == 1 && currentMillis - previousMillis < interval){
    Serial.println(" big dog"); // at way to see progress:
    currentMillis = millis(); 

  }


  talking = 3;  // lock into the next loop of communication
  interval = 140; // adjusted interval for delay in the loop;
  currentMillis = millis(); 
  previousMillis = currentMillis; // set the time counter: 
  Serial.println("data request");  
  lcd.print("data request"); 
  Serial.print(128, HEX);  
 
  bytecount = 0;
  delay(10);

  while (bytecount < 50 && currentMillis - previousMillis < interval ) {            
    char c = Serial.read();
    readString += c;  
    bytecount = bytecount + 1; 
    currentMillis = millis(); // refresh the timer:
  }

  if (readString.length() > 0 && talking == 3) {
    Serial.println ("bytecounter full");
    Serial.println(bytecount);
  }





  // open the file for write at end like the Native SD library
  if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
    sd.errorHalt("opening test.txt for write failed");
  }
  // if the file opened okay, write to it:
  Serial.print("Writing to test.txt...");
  myFile.println(readString);
  readString = "";    // clear readstring to reuse it           
  talking = 1; // go back to data request

  // close the file:
  myFile.close();
  Serial.println("done.");

  // re-open the file for reading:
  if (!myFile.open("test.txt", O_READ)) {
    sd.errorHalt("opening test.txt for read failed");
  }
  Serial.println("test.txt:");

  // read from the file until there's nothing else in it:
  int data;
  while ((data = myFile.read()) > 0) Serial.write(data);
  // close the file:
  myFile.close();
}
  while (i < 2 && Serial.available()) {
    delay(2000); // to allow me to manually enter a number for testing:
    char c = Serial.read();
    readString += c;  
    i = i + 1;
  }

If you haven't entered any data, Serial.available() will return 0, and the while loop will be skipped. The delay() does absolutely nothing for you, except waste time. It most definitely does not wait for you to enter anything.

  while (bytecount < 50 && currentMillis - previousMillis < interval ) {            
    char c = Serial.read();
    readString += c;  
    bytecount = bytecount + 1; 
    currentMillis = millis(); // refresh the timer:
  }

I guess it doesn't matter that there may be nothing to read. Stuff that buffer full of garbage.

PaulS:

  while (i < 2 && Serial.available()) {

delay(2000); // to allow me to manually enter a number for testing:
    char c = Serial.read();
    readString += c; 
    i = i + 1;
  }



If you haven't entered any data, Serial.available() will return 0, and the while loop will be skipped. The delay() does absolutely nothing for you, except waste time. It most definitely does not wait for you to enter anything. 



while (bytecount < 50 && currentMillis - previousMillis < interval ) {           
    char c = Serial.read();
    readString += c; 
    bytecount = bytecount + 1;
    currentMillis = millis(); // refresh the timer:
  }





I guess it doesn't matter that there may be nothing to read. Stuff that buffer full of garbage.

I could be mistaken but, during some tests using the delay () I was able to enter and show characters typed in. I don't know how else I am supposed to wait for a return serial message.

You are correct. Currently, I am stuffing it full of garbage like "yyyyyyyyyy" which is what I get with the RX pin unattached to anything. I expect that when I do connect to the computer it will start talking immediately after I make my data request. It is basically a different version of OBD2 that you would find on a vehicle. I have left out a few of the serial.print messages to simplify the troubleshooting.

I apologize for my lack of experience in programming this is my first Ardiuno. I have been working on it almost everyday for 12 days. I think I will get it I just need to keep at it.

I do still need help with saving my "garbage" until I fill the card.

Thanks,
Mark

I expect that when I do connect to the computer it will start talking immediately after I make my data request.

I would NOT expect that. The Serial.available() function will tell you how much data there is to read. Call that function. Don't just expect that there is going to be data.

I could be mistaken but, during some tests using the delay () I was able to enter and show characters typed in. I don't know how else I am supposed to wait for a return serial message.

while(Serial.available() == 0)
{
  // Do nothing
}
// When you get to here there is at least one byte.

I do still need help with saving my "garbage" until I fill the card.

First thing to do is determine if the problem is with what you are trying to write to the card, or with the way that you are opening the file on the card. Create a sketch that, on each pass through loop, opens the file the way you are opening it here, writes the value returned by millis(), closes the file, and waits one second.

Let it run for a minute, stop the program, remove the card, and see what is in the file. If the file has more than one entry, the problem is the data that you are writing, in this sketch, to the file. If there is still only one entry, the problem is with how you are opening/closing the file.

while(Serial.available() == 0)
{
  // Do nothing
}
// When you get to here there is at least one byte.

Ok that would do the trick! The loop will repeat until I get data, then allow me to move to the next part of the sketch. I will also use that loop everywhere I need to wait for a response. I will make good use of it.

I will also write the file saving sketch you described and troubleshoot that.

Thank you PaulS, you have solved some problems that I just couldn't get my head around.

I can now continue with my attempt at world domination with the Arduino!,
Mark

PaulS, I did the test you suggested using millis stored at every write to the SD card. My results indicate that I have the correct setup for writing to the card. My "garbage" I was putting into was just making it difficult to tell what was going on.

I should mention, I did not erase the card before I ran the the sketch so, I left out the "garbage" stored in it. It starts to run when the Arduino is power so, when I activate the monitor the results look like this:

90
2418
4751
7090
9434
90
2451
4812
7180
9554
11934
14321
16716
19119
21528

Thank you PaulS for the testing idea,
Mark