Trying to get handle on reading different types of data from a CSV file...

I am trying to figure out how to read various pieces of data stored in a CSV file. Each line would contain a combination of integers, floats, and text strings. I seem to be able to read the data, but I'm having problems storing the retrieved info. I think the primary problem is my attempts to convert the strings read into the proper variable types. Each row has items separated by comma's, and end with a '\n'. Anyone have some suggestions on what I may be doing wrong. I've included the primary routine I am working with below...

/*
  SD card read/write
 
An attempt to show how to read and write data to and from an SD card file  
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
     
 */
#include <SPI.h> 
#include <SD.h>
#include <ctype.h>

File myFile;

struct parameters {
  int Menu;
  int Line;      //1 - 4
  int Item;
  int Colmn;    //0 - 19
  int Size;    //1 or 2
  char description[21];    //text
  int interval;      //just a dummy place holder
} settings;
// Setting for SD-card reader

int index=0;      //the index into the text char array TextStr
const int chipSelect = 10;
char charBuf[21];


/*****************************************************************


******************************************************************/
void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(57600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
   pinMode(10, OUTPUT);
   
  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
 // WriteFile();
  
  ShowFile();
 
  AnalyzeFile(1,1);
}

/*****************************************************************


******************************************************************/
void loop()
{
    // nothing happens after setup
}

/*****************************************************************


******************************************************************/
int AnalyzeFile(int Mnu,int itm)
{
  int Pointer=0;
  int cnt=0;
  char TextStr[21];
  Serial.println("Analyzing File...");
  
 // Open the settings file for reading:
  myFile = SD.open("Menu.csv");
  Serial.print("Menu.csv opened\n");
  
  char ch;
  int j;
  int ignore;
  
   ch = myFile.read();
   
   if (myFile) 
   {
     while(myFile.available())
     {

         if (ch == '\n' || ch == 13 || ch == 10)       //line is done prepare to analyze
         {
            //settings should be filled with info needed
            Serial.print("Line ");
            Serial.print(cnt);
            Serial.print(" Read  = [");
            Serial.print(TextStr);
            Serial.print("]\n");
            
            ignore=false;
            cnt++;
            
                        // description.toCharArray(myStrings,60);
            // arrayStrings[x]=myStrings;
            Serial.print("Menu:\t");
            Serial.print("Menu:\t");
            Serial.println(settings.Menu);
            Serial.print("Line #:\t");
            Serial.println(settings.Line);
            Serial.print("Item #:\t");
            Serial.println(settings.Item);
            Serial.print("Column:\t");
            Serial.println(settings.Colmn);
            Serial.print("Char Size:\t");
            Serial.println(settings.Size);
            Serial.print("Menu Text:\t");
            Serial.println(settings.description);
            Serial.println("end");
            
         } 
          else if(ch != '/')        //simply ignore is a comment
         {      
          ignore=true;   
         }
         
         
         
         
         
         else if(ch != ',' && ignore != true)
         {
           //Serial.println(TextStr);
           
           /*  int Menu;
              int Line;      //1 - 4
              int Item;
              int Colmn;    //0 - 19
              int Size;    //1 or 2
              char TextStr[21];    //text
              int interval;      //just a dummy place holder
              */
           if (Pointer >=1 && Pointer <= 6) { Serial.print(TextStr);}
           
           if (Pointer==1)     //points to particular variable to set...
           {
             settings.Menu = atoi(TextStr);
           } else if (Pointer ==2) {// int Item
             settings.Line = atoi(TextStr);
           } else if (Pointer ==3) {// int Item
             settings.Item = atoi(TextStr);
           } else if (Pointer ==4) {// int Item
             settings.Colmn = atoi(TextStr);
           } else if (Pointer ==5) {// int Item
             settings.Size = atoi(TextStr);
           } else if (Pointer ==6) {// int Item
             for (j==0; j <= 21; j++) 
             {
               settings.description[j] = TextStr[j];
               TextStr[j]='\0';
             }
             Serial.println("Pointer=6 Found \t");
             Pointer=0;
           
             ch = myFile.read();
           }   //endif Pointer
           Pointer++;
         } 
         else 
         {
           TextStr[index++] = ch;      //add the ascii character to the string.
         } //end if 
       ch = myFile.read();
 
     }    //end while
     myFile.close();
  }      // no datafile to read
  else
  {  
    Serial.println("No file to read");
  }      // endif(MyFile)
  
 /* for (int i=0; i< 13; i++) 
  {
    Serial.println(arrayStrings[i]);
    delay(100);
  }
  */
}  //AnalyzeFile


/*****************************************************************


******************************************************************/
void ShowFile() {
  int cnt=1;
  char ch;
  
  // re-open the file for reading:
  myFile = SD.open("Menu.csv");
  if (myFile) {
    Serial.println("\nReading from: Menu.csv");
    Serial.print(cnt);
    Serial.print("\t");
    
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      ch=myFile.read();
      
      if (ch == '\n') {
        cnt++;
        Serial.println();
        Serial.print(cnt);
       Serial.print("\t");
      } else {
        Serial.print(ch);
      }  //endif
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }  
}

/*****************************************************************


******************************************************************/
void WriteFile() 
{
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("Menu.csv", FILE_WRITE);
  
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to Menu.csv...");
    myFile.println("/ This is file containing menu items for Arduino Suziki Motorcycle Program by Larry Tetzner");
    myFile.println("/	Menu #1");
    myFile.println("1,1,1,0,1,This is first menu item");

    myFile.println("/	Menu #2");

   //myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening Menu.csv");
  }
  
  
}

The file I'm reading has these lines....

/ This is file containing menu items for Arduino Suziki Motorcycle Program by Larry
/ Menu #1
1,1,1,0,1,This is first menu item
/
/ Menu #2
/ This is file containing menu items for Arduino Suziki Motorcycle Program by Larry
/ Menu #1
1,1,1,0,1,This is first menu item
/
/ Menu #2
/ This is file containing menu items for Arduino Suziki Motorcycle Program by Larry
/ Menu #1
1,1,1,0,1,This is first menu item
/
/ Menu #2

And results in the following output to the Serial port....

Initializing SD card...initialization done.

Reading from: Menu.csv
1 / This is file containing menu items for Arduino Suziki Motorcycle Program by Larry

2 / Menu #1

3 1,1,1,0,1,This is first menu item

4 /

......
86 Analyzing File...
Menu.csv opened
Line 0 Read = [ú]
Menu: Menu: 0
Line #: 0
Item #: 0
Column: 0
Char Size: 0
Menu Text:
end
Line 1 Read = [ú]
Menu: Menu: 0
Line #: 0
Item #: 0
Column: 0
Char Size: 0
Menu Text:
end
úLine 2 Read = [ú]
Menu: Menu: 0
Line #: 0
Item #: 0
Column: 0
Char Size: 0
Menu Text:
end
/[END POST]***********/

If you compare the way ShowFile (which works) and AnalyzeFile (which doesn't work) are written you'll see that the statement:

   ch = myFile.read();

in AnalyzeFile isn't in the same place as it is in ShowFile. It might explain a lot or at least get you started on the way to fixing things.

Pete

  myFile = SD.open("Menu.csv");
  Serial.print("Menu.csv opened\n");
  
  char ch;
  int j;
  int ignore;
  
   ch = myFile.read();
   
   if (myFile)

Printing that message, and reading from the file, before testing is making a big assumption that may not be true.

Paul I moved the "Opened Menu.csv" after the "if (myFile)". I re-evaluated this and tried to make it simpler, but I am still having problems getting a group of characters (like "18") to convert to an inter using atoi(). Anyone have some suggestions (I am again assuming this is obvious, but as a noob I'm not seeing it). Here is my new code, and the results from the serial monitor. (I apologize if this makes the post too long).....

The Code:

/*
  SD card read/write
 
 This example is an attempt to read and write data to and from an SD card file 	
 	 
 */

#include <SPI.h>
#include <SD.h>
char ch;
File myFile;
char Instring[60];
int InstrPtr=0;
int pointer=1;
int ValFlag=false;

struct parameters {
  int Menu;
  int Line;      //1 - 4
  int Item;
  int Colmn;    //0 - 19
  int Size;    //1 or 2
  char description[21];    //text
} settings;

// change this to match your SD shield or module;
//     Arduino Ethernet shield: pin 4
//     Adafruit SD shields and modules: pin 10
//     Sparkfun SD shield: pin 8
const int chipSelect = 10;
void setup()
{
  int cnt=1;
  int pointer=1;
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
  pinMode(10, OUTPUT);

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");



  // re-open the file for reading:
  myFile = SD.open("Menu.csv");
  if (myFile) {
    Serial.println("Opened Menu.csv:");
InstrPtr=0;

    // read from the file and at the end of each line evaulate it.
    //  keep reading until there's nothing else in the file!
    while (myFile.available()) {
      ch = myFile.read();
      Serial.write(ch);
      
      if (ch == '\n') 
      {
        Serial.print("\n\tLine #");
        Serial.print(cnt++);
        Serial.print(" read.   ");
        if (ValFlag) {
          Serial.print("Will process the following line..\t ");
          ProcessLine();    I moved
          ValFlag=false;
        } 
        Serial.println();
        InstrPtr=0;

      }
      else if (ch == ',')     //if there is a comma in this line, will send for special processing when line is read.
      {
        ValFlag=true;
     }  //endif ch==
      
      
       Instring[InstrPtr]=ch;
       if (InstrPtr<60) { InstrPtr++; }
      

    }  //wend

    // close the file:
    myFile.close();
    Serial.print("\n\n\t\t[Finished Reading the File Menu.csv]\n");

  } 
  else {
    // if the file didn't open, print an error:
    Serial.println("error opening Menu.csv");
  }
}

void loop()
{
  // nothing happens after setup
}


/**************************************************************************
Structure to populate is..

struct parameters {
  int Menu;      // Many different menu's are possible
  int Line;      //1 - 4    for a 4 character LCD display
  int Item;      //  Which item to locate at a specific column
  int Colmn;     //0 - 19
  int Size;      //1 or 2  Size 1 is normal text on line, size 2 is a 3x3 Numeral character
  char description[21];    //text for that part of the menu
} settings; 
***************************************************************************/

void ProcessLine() 
{
    int ValidData=0;    // Flag to indicate that this line contains commas 0=yes, 1-no
    char chh;
    int x=0;    //pointer into description[] array
    
//Debug to show what the contents of the line is.
  for (int j=0; j<= InstrPtr; j++) {
    Serial.print(Instring[j]);
    Serial.print(" ");
    chh = Instring[j];
    if (chh == ',') { ValidData=1; }  //only want to evaluate lines with comma's in them...
  }
  
  // This may be redundant, and should be checked prior to calling this function... fix eventually
   if (ValidData == 1) { 
      Serial.print("\nProcess this csv line, next!...\n");
   }     else {
     Serial.print("ERROR:  This line does not contain a comma!");
     return;
   } 
   
   
   
  // go through each character in this Instring[] array
 for (int j=0; j<= InstrPtr; j++) {
 //for (int j=0; j <= sizeof(Instring); j++) { // didn't work ???
    
  if (Instring[j] == ','  || Instring[j]=='\n')     //process the previous value concatenated in instring.
  {
    Serial.print("Proccessing Variable #");
    Serial.print(pointer);

      Serial.print("\tItem ");Serial.print(pointer);Serial.print("=[");
      
      if (pointer==1) {
        settings.Menu = atoi(settings.description);
        Serial.print(settings.Menu);
      } else if (pointer == 2) {
        settings.Line = atoi(settings.description);
        Serial.print(settings.Line);
      } else if (pointer == 3) {
        settings.Item = atoi(settings.description);
        Serial.print(settings.Item);
      } else if (pointer == 4) {
        settings.Colmn = atoi(settings.description);
        Serial.print(settings.Colmn);
      } else if (pointer == 5) {
        settings.Size = atoi(settings.description);
        Serial.print(settings.Size);
      } else if (pointer == 6) {
        //no need to do anything here, this is already set...
        Serial.print(settings.description);
      }
      Serial.print("]\t");
      Serial.println(settings.description);
      
     // sizeof(array) returns the size of the array in bytes, which is calculatate during compilation
     //  This setts all elements to zero.
      memset(settings.description,0,sizeof(settings.description));
      x=0;
      pointer++;
     
    }  else if (Instring[j] == '\0') {
      break;
    }  else {
      
    
      settings.description[x] = Instring[j];
      x++;
    }  //endif Instring[j]...
  } //next j

}  //end sub

The Results from the Terminal window....

Initializing SD card...initialization done.
Opened Menu.csv:
/ This is file containing menu items for Arduino Suziki Motorcycle Program by Larry Tetzner

Line #1 read.
/ Menu #1

Line #2 read.
1,1,1,0,1,This is first menu item

Line #3 read. Will process the following line..
1 , 1 , 1 , 0 , 1 , T h i s i s f i r s t m e n u i t e m
s
Process this csv line, next!...
Proccessing Variable #1 Item 1=[0]
Proccessing Variable #2 Item 2=[1] 1
Proccessing Variable #3 Item 3=[1] 1
Proccessing Variable #4 Item 4=[1] 1
Proccessing Variable #5 Item 5=[0] 0
Proccessing Variable #6 Item 6=[1] 1

/

Line #4 read.
/Menu #2

Line #5 read.
12,13,14,15,16,This is 2nd menu item

Line #6 read. Will process the following line..
1 2 , 1 3 , 1 4 , 1 5 , 1 6 , T h i s i s 2 n d m e n u i t e m
o
Process this csv line, next!...
Proccessing Variable #7 Item 7=[] This is first menu item
s

Proccessing Variable #8 Item 8=[] 12
Proccessing Variable #9 Item 9=[] 13
Proccessing Variable #10 Item 10=[] 14
Proccessing Variable #11 Item 11=[] 15
Proccessing Variable #12 Item 12=[] 16

/ Menu32

Line #7 read.
88,89,90,91,101,Fifth menu item.

Line #8 read. Will process the following line..
8 8 , 8 9 , 9 0 , 9 1 , 1 0 1 , F i f t h m e n u i t e m .
t
Process this csv line, next!...
Proccessing Variable #13 Item 13=[] This is 2nd menu item
o
s

Proccessing Variable #14 Item 14=[] 88
Proccessing Variable #15 Item 15=[] 89
Proccessing Variable #16 Item 16=[] 90
Proccessing Variable #17 Item 17=[] 91
Proccessing Variable #18 Item 18=[] 101

Just another comment line.

Line #9 read.

[Finished Reading the File Menu.csv]

There are at least two problems with the code you have. First, the function you are calling expects a string. You do not have a string. You have an array of chars. A string is a NULL-terminated array of chars. Your array is not NULL-terminated. Therefore, it is not a string.

Second, the strtok() function KNOWS how to parse strings. Why try to re-invent the strtok() function? Use strtok() and get rid of a lot of code.

Using the / key to comment out code that didn't work is wrong. The delete key is the correct key to use.

    if (chh == ',') { ValidData=1; }  //only want to evaluate lines with comma's in them...

You've decided that the data is valid. So, then you check the rest of the array. Why?

Nothing belongs on the line after the {. Nothing belongs on the same line as the }.

    if (chh == ',')
    {
        ValidData=1;
        break;   // Skip the rest of the array
    }  //only want to evaluate lines with comma's in them...

Again good points Paul, I've modified the code and it seems to be working right now. I didn't have a good grasp of the differences between a string and a character array. In all the reading I've been doing, I have heard people say that strings have a lot of potential for problems. So I've been trying to stay clear of them. Still trying to figure out array pointers, arrays, and strings and all their functions.

I sometimes keep code that didn't work in a file, till I've gotten it working properly. So I learn from the mistake, and don't make it again in an attempt to fix a problem. Then do cleanup (removing code, un needed print statements, etc.) This stuff has certainly been a challenge, but I keep my final goal in mind.

Anyway thank you for the help! I will consider the use of the strtok() function for strings!

In all the reading I've been doing, I have heard people say that strings have a lot of potential for problems.

Strings (with a capital S) do. strings (lower case s) do not, as long as you don't write past the end of the array.

So I've been trying to stay clear of them.

Master them. Don't avoid them. Unless you mean Strings, in which case, good idea.