Go Down

Topic: Totally puzzled by infinite loop (Read 942 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'.


Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy