Skipping function calls in loop()

Refer this code below. It works as expected …well atleast most of the time that is.

When I press a push button, the code has to Erase a file on SD card, then go ahead and create a fresh version of the same file on the SD card and finally read the file and display in Serial monitor.

I have a delay(scanMs); so as not to run the loop at break neck speeds (!). But what happens is when I set this scanMs to say 100ms then at times the erasePendingFile() function alone is skipped. I don’t see any serial output from that function. And the contents are also not erased…

Rest of the two functions called execute as expected.

But when I set scanMs to 10ms then every single time it happens without fail.

I am curious about this behaviour. Any suggestions regarding the recommended delay for the loop() ??

/*

  Hardware is EtherTen Board / UNO board. SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK  - pin 13  ( So this pin cannot be used for the LED connected to it.)
 ** CS   - pin 4
*/

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

const int chipSelect = 4;                                   // SD card select on shield

// Define the Machine Digital Inputs and Outputs
#define StartPB 12                                          // EtherTen mapping
#define IncrPB 14
#define DecrPB 6
#define EnterPB 7
#define total_buttons 4
char mapDIN[] = {'S', 'I', 'D', 'E'};                      // This is a list of names for each button.
byte pinDIN[] = { StartPB, IncrPB, DecrPB, EnterPB};       // The digital pins connected to the 4 buttons.
phi_button_groups MyDIN(mapDIN, pinDIN, total_buttons);

char ValidDIN = '0';

unsigned long scanMs = 10;

boolean rdAllData = false;

// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                        SETUP
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Initializing SD card..."));           // Check if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    return;                                               // No card .. just return..
  }
  Serial.println(F("SD Card initialized."));
  Serial.println(F("SerialToSD program ready "));
  pinMode(chipSelect, OUTPUT);
 }
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                      MAIN LOOP
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void loop()
{

  ValidDIN = MyDIN.getKey();

  if ( ValidDIN == 'S' ) {
    ValidDIN = '0';
    Serial.println( "Got the command !");
    erasePendingFile();
    createPendingSummary();
    readPendFile();
  }
  
  delay(scanMs);
}

// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                       FUNCTIONS
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

//FUNCTION TO ERASE PENDING.CSV FILE ..

void erasePendingFile() {
  if (SD.exists("PENDING.CSV")) {
      if (!SD.remove("PENDING.CSV")) {
      Serial.println( " Error Erasing PENDING.CSV");
    }
    else {
      Serial.println( "PENDING.CSV Erased !!");
    }
  }
}

// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

// FUNCTION TO CREATE THE PENDING FILE FROM ACTUAL FILE.CSV

void createPendingSummary() {

  char statusToken = '0';
  int data;
  File dataFile = SD.open("ACTUAL.CSV", FILE_READ);    // Open the existing Actual File
  File pendFile = SD.open("PENDING.CSV", FILE_WRITE);  // Open the file to write the selected records..
  
  while ((data = dataFile.read()) >= 0)  {
    
    if ( data == '<') {
      statusToken = dataFile.read();
    }
    
    if (statusToken == '&') {
      pendFile.write('<');
      do {
        data = dataFile.read();
        pendFile.write(data);                        // Criteria token matches. Write the record to file..
      } while ( data != '>');
      pendFile.write("\n");
      statusToken = '0';
    }

    if ( statusToken == '#') {
      do {
        data = dataFile.read();                     // Ignore record. But move the read pointer for next
      } while ( data != '>');
      statusToken = '0';
    }
  }
  pendFile.close();                                 // Write the data and close file. 
  dataFile.close();
} // Function end


//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void readPendFile(){
  File pendFile = SD.open("PENDING.CSV", FILE_READ);
  if ( pendFile ){
  while (pendFile.available()) {                      // Data file exists ..read it.
    Serial.write(pendFile.read());
  }
  Serial.println ( pendFile.position());
  pendFile.close();
  }
  else {
    Serial.print( "No PENDING.CSV"); 
  }
}
//*****************************************************

I have a delay(scanMs); so as not to run the loop at break neck speeds (!).

That is the wrong approach. The blink without delay example shows the correct way.

I am curious about this behaviour. Any suggestions regarding the recommended delay for the loop() ??

It's hard, as a human, to press a button for less than 10 milliseconds. It it not hard to press the switch for less than 100 milliseconds.

While you have your head buried in the sand (during the delay() call), the state of the switch is ignored.

PaulS: That is the wrong approach. The blink without delay example shows the correct way. It's hard, as a human, to press a button for less than 10 milliseconds. It it not hard to press the switch for less than 100 milliseconds.

While you have your head buried in the sand (during the delay() call), the state of the switch is ignored.

Got it .. the delay() of course can be eliminated.

But my query was when the if( ValidDIN == 'S') {} is executed is it not supposed to handle all the functions inside the curly brackets ? Why does it skip the erase function alone ??

But my query was when the if( ValidDIN == 'S') {} is executed is it not supposed to handle all the functions inside the curly brackets ?

Yes, it should.

Why does it skip the erase function alone ??

Some serial output to prove this assertion would be interesting.

This is the Serial output with scanMs = 10ms :

Initializing SD card...
SD Card initialized.
SerialToSD program ready 
Got the command !
PENDING.CSV Erased !!
<2  ,604E95FF  ,10 ,VrP Part9       ,102,6670    ,Drive shaft NDE     ,ShellGadus3        >
<4  ,70E691FF  ,15 ,VrP Part9       ,104,Cold 1  ,CldPrWshCon1TailNDE ,ShellGadus3        >
<6  ,2C52B0F8  ,5  ,VrP Part9       ,103,Cold 2  ,CldPrWshCon2TailNDE ,ShellGadus3        >
<8  ,D0FC97FF  ,8  ,VrP Part12      ,105,2.02    ,BtmWireGuideRollTS  ,MA6040-150-1.5     >
<10 ,70E891FF  ,20 ,VP3 Part11      ,104,2.04    ,BtmWireBreastRollTS ,MA6040-150-1.5     >
460

And this is the Serial output with scanMs = 100ms. You can see that Erase function has been skipped - no serial confirmation and the file size is now double .

Initializing SD card...
SD Card initialized.
SerialToSD program ready 
Got the command !
<2  ,604E95FF  ,10 ,VrP Part9       ,102,6670    ,Drive shaft NDE     ,ShellGadus3        >
<4  ,70E691FF  ,15 ,VrP Part9       ,104,Cold 1  ,CldPrWshCon1TailNDE ,ShellGadus3        >
<6  ,2C52B0F8  ,5  ,VrP Part9       ,103,Cold 2  ,CldPrWshCon2TailNDE ,ShellGadus3        >
<8  ,D0FC97FF  ,8  ,VrP Part12      ,105,2.02    ,BtmWireGuideRollTS  ,MA6040-150-1.5     >
<10 ,70E891FF  ,20 ,VP3 Part11      ,104,2.04    ,BtmWireBreastRollTS ,MA6040-150-1.5     >
<2  ,604E95FF  ,10 ,VrP Part9       ,102,6670    ,Drive shaft NDE     ,ShellGadus3        >
<4  ,70E691FF  ,15 ,VrP Part9       ,104,Cold 1  ,CldPrWshCon1TailNDE ,ShellGadus3        >
<6  ,2C52B0F8  ,5  ,VrP Part9       ,103,Cold 2  ,CldPrWshCon2TailNDE ,ShellGadus3        >
<8  ,D0FC97FF  ,8  ,VrP Part12      ,105,2.02    ,BtmWireGuideRollTS  ,MA6040-150-1.5     >
<10 ,70E891FF  ,20 ,VP3 Part11      ,104,2.04    ,BtmWireBreastRollTS ,MA6040-150-1.5     >
920

You can see that Erase function has been skipped - no serial confirmation

No, I can't see that. What I can see is that erasePendingFile() has three possible paths, and that only two of them produce serial output.

If you put every { on a new line, and used Tools + Auto Format, you'd see that, too.

I think I was tying myself in knots with the blocking delay() in loop and then with a Serial print inside the START button code. Once I removed this line out from the code below all things worked nice.

if ( ValidDIN == 'S' ) 
{
    ValidDIN = '0';
    Serial.println( "Got the command !");
    erasePendingFile();
    createPendingSummary();
    readPendFile();
  }

And of course it works best with a scanMs of 10ms or even better with 0ms !!

Thanks for the } in every line tip. Makes code more neat to follow..