parsing SD text file quetions

Hi ;

This maybe a little long winded . My intent is to assign variables inside a program by reading values from a text file on an SD card. This is to avert recompiling every time I need to change these values. Below are the fields listed in the text file .

test_time_hrs 3

delay 1000

wind_min_volt .41

What I want to do is read each line into a string variable and then parse it to recover the field name and value ie field name on the first line would be test_time_hrs and field value is the 3. Then using conditional statements, match the field name and assign the field value. I am able to read in the string using l_line = test_data.readStringUntil(’\n’);
however I’m having trouble determining the length using m=sizeof(l_line);
so that I can parse it using while() or for(). It seems to give the literal length of l_line which is 6. Enclosed is my code. I spent a lot of time on this so any help would be appreciated .

Thanks

Justin

#include <SD.h>
#include <SPI.h>

File test_data;

String variable;
String l_line="";
int test_duration_hrs;
int time_delay;
double voltageMin;

int num = 0;

void setup() {
// Open serial communications and wait for port to open:

Serial.begin(9600);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

// ***********************SD card initialization

Serial.print(“Initializing SD card…”);

// see if the card is present and can be initialized:
if (!SD.begin(4)) {
Serial.println(“Card failed, or not present”);
// don’t do anything more:
return;
}
Serial.println(“card initialized.”);

if (SD.exists (“test.txt”))
{
test_data = SD.open(“test.txt”, FILE_READ);

while (test_data.available()) {
l_line = test_data.readStringUntil(’\n’);

// l_line=test_data.read();
//l_line+="\n";
Serial.println( l_line);
if (l_line != “”);
{
Serial.println(l_line);

int m, n =0 ;

m=sizeof(l_line);

Serial.println("sizeof m " +String(m));

String r;
variable = “”;

while (n<m) //l_line[n]!="\n")
{
//variable+=l_line[n];
//Serial.print(String(n));
if (l_line[n] != " ")
{
variable += l_line[n];
n++;
}
else
{
r = variable;

Serial.println(r);

while (l_line[n] = " ")
{
n++;
}

}

}

}
Serial.print(variable);
}

}

}

void loop() {

}

SD_text_read.ino (1.63 KB)

however I'm having trouble determining the length using m=sizeof(l_line);

The sizeof() macro is NOT how you determine the number of characters. If you actually had a string, like you said, you'd use strlen(). But, since you do NOT have a string, YOU can go look at the documentation for the thing that you have, and determine the appropriate method.

I do not help people with Strings.

It is not a good idea to use the String (capital S) class as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

The parse example in Serial Input Basics may be helpful if you are using cstrings.

...R

Thanks for the reply - in what library are these functions, cstrings,strlen located and what would be the include statement ?

Justin

There is a header file, string.h, that defines the functions. It is already included in Arduino.h, which the IDE adds to your sketch.

Thanks PaulS but still confused . When I call l_line = test_data.readStringUntil('\n');
it puts what's read from the buffer into a string called l_line correct ? and from there I should be able to manipulate l_line treating it as character array, or am I missing something ?

Thanks again

jtabatch:
When I call l_line = test_data.readStringUntil('\n');
it puts what's read from the buffer into a string called l_line correct

How is l_line defined?

...R

it puts what's read from the buffer into a string called l_line correct ?

No, it does NOT. It puts what's read from the buffer into a String call l_line.

A String and a string are NOT the same thing!

No it does not, it allocates a new String, initialized from what’s read from the buffer, and then
overwrites the variable l_line to point to this new String, and the old one is probably reclaimed.

MarkT:
and the old one is probably reclaimed.

Which is why the String class is not a great idea for Arduino code

…R

Still confused (sorry) . readStringUntil is defined as below from Arduino definition

readStringUntil()
Description
readStringUntil() reads characters from a stream into a string. The function terminates if the terminator character is detected or it times out (see setTimeout()).

There may be a difference between String and string but it seems the return value on read.... is a string.

BTW I initially declared it as a String but then changed it to string using the #include "string.h" and got a compiler error message "string does not name a type"

I'll pull string.h into visual to try to understand why.

Thanks

There may be a difference between String and string but it seems the return value on read… is a string.

Read the code, not the piss-poor documentation:

  // Arduino String functions to be added here
  String readString();
  String readStringUntil(char terminator);

The C++ string class is NOT a C-string.

The ONLY thing you want to use is a C string - a NULL terminated array of chars.

Why don't you just keep the values only on the SD card in one row, using commas between the values; for example:

3,1000,0.41

or whatever.

No need to also store the labels, since your code will "know" that the first one is the test time, the second the delay, etc.

Then use one of the simple functions in this thread to read those values. A Simple Function for Reading CSV Text Files. - Storage - Arduino Forum

Thanks DaveEvans and PaulS , good input , I will try the comma delimitated approach but I would still like to figure out the other option.

See also post #8 in that thread, and post #9 with the reply, coincidentally, by @PaulS.

As a follow up enclosed is my solution ( borrowed a little from a previous post)

thanks - Justin

#include <SD.h>
//#include
#include <Arduino.h>
#include <SPI.h>
//#include “avr/stdio.h”
//#include <fat16lib.h>
#include <string.h>

File params;
char record[80];
char *nametoken;
double test_duration_hrs, time_delay ;
double voltageMin;
char *c;
double value = 0;
int index = 0;

void setup()
{

Serial.begin(9600);

while (!Serial) {

; // wait for serial port to connect. Needed for native USB port only
} // while serial

// ***********************SD card initialization

Serial.print(“Initializing SD card…”);

// see if the card is present and can be initialized:
if (!SD.begin(10)) {
Serial.println(“Card failed, or not present”);
// don’t do anything more:
return;
}
Serial.println(“card initialized.”);

//parse data in text file on SD card

if (!(params = SD.open(“config.txt”, FILE_READ ))) {
Serial.println(“cant open config.txt”);

} // sd.open

while (params.available())
{
while (params.read(c, 1))
{
if (*c != ‘\n’ )
{
record[index++] = *c;
}
else
{
nametoken = strtok(record, " ,=");
value = atof( strtok(NULL, " ,="));

if (strcmp( “test_time_hrs”, nametoken) == 0)
{
test_duration_hrs = value;
Serial.println(nametoken);
Serial.println(value);
break;
}

else if (strcmp( “delays”, nametoken) == 0)
{
time_delay = value;
Serial.println(nametoken);
Serial.println(value);
break;
}

else if (strcmp(nametoken, “wind_min_volt”) == 0) {
voltageMin = value;
Serial.println(nametoken);
Serial.println(value);
break;
}
}
} //while
record[80] = “”;
value = 0;
nametoken = “”;
index = 0;
} // available
}

void loop() {
// put your main code here, to run repeatedly:

}

config.txt ( on SD)

test_time_hrs = 3
delays = 1000
wind_min_volt = .41

output

Initializing SD card…card initialized.
test_time_hrs
3.00
delays
1000.00
wind_min_volt
0.41