Go Down

Topic: Totally puzzled by infinite loop (Read 902 times) previous topic - next topic

dirtshell

Alright, so I am having some trouble parsing data on an SD card (shocker). So the idea is that you access the a config file on an SD card and assign a few values, then add items in the body of the file to a 2D array. I can handle the 2D array and assigning values (at least I think), but I am having trouble getting past the first field in my config file. By the way, the 2D array is composed of buffers of 12 elements (ie byte example[20][12]). I know using 12 is a pain, but I have to for the given application. The buffers are shifted out to an external IC for translation. So here is my code:

Code: [Select]

#include <SD.h>
int chipSelect = 10;
int counter = 0; // Used for count the number of iterations
int currPosition = 0; // Used for keeping track of the current position (the 0 value wont be used)
boolean ignoreFlag = true; // true if you are supposed to ignore

void setup()
{
  Serial.begin(9600);
 
  pinMode(10, OUTPUT);
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.print("failed!"); // If there is an issue, tell us and quit 
    return;
  }
  Serial.print("card initialized"); // You will only be here on success
  Serial.println();
 
  // Dump the file
  File comboFile = SD.open("egFile.txt"); // Open the combo file
  if (comboFile) { // If the file is availble
    while (comboFile.available()) {
      if (comboFile.peek() == ':') {  // If entering a zone
        ignoreFlag = !ignoreFlag;
        if (ignoreFlag) currPosition++; // When it switches to high
        comboFile.read();
      }
      // If not in an ignore zone write the stuff
      else if (!ignoreFlag)  Serial.write(comboFile.read();
    }
  comboFile.close(); // Close the file
  }
 
  // If the file isnt open produce an error
  else Serial.println("There was an error openeing the file");
}

void loop()
{
}


And here is the file it will be reading:

Code: [Select]

:field1: // This is a comment you can throw in
:field2:
// So is this

:field3:
:meter:
:101010101010,
101010101010,
101010101010,
101010101010,
101010101010
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,
101010101010,:


So ideally, the output would be

Code: [Select]

Initializing bla bla bla
field1
field2

and so on


Instead I get:
Code: [Select]

Initializing bla bla bla
field1


And thats it. So to investigate, I added a counter to the while (comboFile.available()) loop. To my surprise, this actually seems to be an infinite loop. I don't know if this is entirely unrelated, but I figured I would give you a heads up on what I have tried.

Thanks for your time, even if it is just to laugh at some egregious error =)

PaulS

All that you are doing with the data read from the SD card is printing it, one character at a time, to the serial port. If that data is interesting, you need to save it in a NULL terminated array of chars. Then, when you read the end of a packet (probably denoted by a carriage return or line feed (or both)), you need to parse the data and reset the array.

Your toggling of ignoreFlag when you see a colon is suspect. Some character to indicate comments and another to indicate data would be more logical.

dirtshell

Sorry, I forgot to mention that this is an excerpt to test the issue. But yep, I am pretty sure thats where it is.

UKHeliBob

The code that you posted won't compile because of a missing right parenthesis.

What is currPosition used for ?  It is initialised and incremented but never used.
How does comboFile.peek() know where to look in the file ?
Does it read the next byte and then update its own pointer to the next byte ?
Same questions for comboFile.read()
What is the difference between the two ?
How do you know that you have reached the end of the input file ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Tom Carpenter

#4
Jan 04, 2013, 01:08 pm Last Edit: Jan 04, 2013, 01:12 pm by Tom Carpenter Reason: 1
Code: [Select]
while (comboFile.available()) {
     if (comboFile.peek() == ':') {  // If entering a zone
       ignoreFlag = !ignoreFlag;
       if (ignoreFlag) currPosition++; // When it switches to high
       comboFile.read();
     }
     // If not in an ignore zone write the stuff
     else if (!ignoreFlag)  Serial.write(comboFile.read());
   }


Where in that bit of code does ignoreFlag get cleared? When it comes across a ':', ok, but you missed something important.

What happens if you have this:

:Hi: :Low:

It will first detect the ':' and read it to move on to the next character. 'ignoreFlag' will be clear so it will read and print 'Hi'. Then it sees a ':' and 'ignoreFlag' becomes set. Now what? It will sit there constantly peeking at the ' ' between the colons, but it will never move on. There is nothing to increment the index in the file.

Code: [Select]
    while (comboFile.available()) {
     if (comboFile.peek() == ':') {  // If entering a zone
       ignoreFlag = !ignoreFlag;
       if (ignoreFlag) {
         currPosition++; // When it switches to high
       }
       comboFile.read();
     } else if (!ignoreFlag)  {
       Serial.write(comboFile.read()); // If not in an ignore zone write the stuff
     } else {
       comboFile.read(); //work through all characters that are in the ignore region by reading them.
     }
   }


An simpler alternative would be this:
Code: [Select]
    while (comboFile.available()) {
     char in = comboFile.read(); //read in the character
     if (in == ':') {  // If entering a zone
       ignoreFlag = !ignoreFlag;
       if (ignoreFlag) {
         currPosition++; // When it switches to high
       }
     } else if (!ignoreFlag)  {
       Serial.write(in); // If not in an ignore zone write the stuff
     }
   }




One last thing. I know it is a valid syntax, but it is best to not do things like:
Code: [Select]
if() code;
and stick to the more readable
Code: [Select]
if() {
 code
}

It makes it much clearer as to what is going on.
~Tom~

dirtshell

Sweet, this works perfectly. Cant believe I forgot about the dual colons. Quick question, when analyzing the body section (the 12 bit buffers), how do I take the result of myFile.peek() and add it to my array as a byte equal to its meaning as a string (ie "1000000000" translates to byte myArray[1][12]= {1,0,0,0,0,0,0,0,0,0,0,0})?

PaulS

Quote
how do I take the result of myFile.peek() and add it to my array as a byte equal to its meaning as a string (ie "1000000000" translates to byte myArray[1][12]= {1,0,0,0,0,0,0,0,0,0,0,0})?

First, don't. Use the result of myFile.read(), instead.

Second, you are not reading a string. You are reading a bunch of characters. So, 1 = '1' - '0'.

If you read a character and subtract '0' from it, you get its value as a number, if the character is in the range '0' to '9'.

dirtshell


Go Up