Go Down

Topic: Variable SD filename raising "Wmaybe-uninitialized" warning (Read 338 times) previous topic - next topic

Zero_Magnitude


How can I generate a filename to use with SD.open( fileName, FILE_WRITE )? 

I've spent the morning going through forum posts and the online guides for using variable names for SD.open() calls.  Some of the posts predate the library's update to accept String parameters.  (Using a char[] causes a compiler error, so the API that uses that info seems to be deprecated.) 

The error I'm tending to get is:

Code: [Select]
C:\Program Files (x86)\Arduino\libraries\SD\src\SD.cpp:456:12: warning: 'pathidx' may be used uninitialized in this function [-Wmaybe-uninitialized]

   filepath += pathidx;

            ^

C:\Program Files (x86)\Arduino\libraries\SD\src\SD.cpp:450:7: note: 'pathidx' was declared here

   int pathidx;



I am definitely setting default values for the fileName.  If I use a hard-coded value for the file name, it works fine.  If I use a variable, it throws the warning and doesn't write to the SD card.  The String is using the 8.3 format.

The plan is to grab an incrementing number from EEPROM so it gives a unique filename every power cycle.   


Code: [Select]
String logData = "";
unsigned long timeTracker;
int intervalTimer = 0;
int shockPosition;
unsigned int heartbeat = 0;

bool SDworking = false;
unsigned int heartBeatMax = 75;

String fileName = "SWDL_.txt";
//char fileName[] = "SWDL_000.txt";
File SDdataFile;

int logTracker = 0;



/*******************************************************************************
 * 
 * setup()
 * 
 * One-time run on power-up.  Check that the SD card is available, and generate
 * a filename from the EEPROM tracking info.
 * 
 ******************************************************************************/
void setup()
{

  // see if the card is present and can be initialized:
  pinMode( SDSelect, OUTPUT );
  SDworking = SD.begin( SDSelect );

  if( SDworking )
  {
    heartBeatMax = 500;   
   
    //Let's not burn extra EEPROM if there's no SD card.
    EEPROM.get( trackingNumber, logTracker );
    logTracker++;
    if( logTracker > 999 )
    {
      logTracker = 0;
    }
    EEPROM.update( trackingNumber, logTracker );   
  }

}

/*******************************************************************************
 * 
 * loop()
 * 
 * Runs from top to bottom, the back to the top, as long as power is applied.
 * 
 ******************************************************************************/
void loop()
{
  wdt_reset();
  //This will flash super fast if the SD card is failed, or slow if it's fine.
  if( heartbeat > heartBeatMax )
  {
    heartbeat = 0;
    digitalWrite( LED_BUILTIN, !( digitalRead( LED_BUILTIN ) ) );
  }
  if( intervalTimer >= 10 )
  {
    intervalTimer = 0;
    if( SDworking )
    {
      shockPosition = analogRead( positionSensor );
      //It's the only way string concatenation seems to work on Arduino.
      logData = "";   
      logData += timeTracker;
      logData += ": ";
      logData += shockPosition;
      logData += "," ;
     
      // open the file. note that only one file can be open at a time,
      // so you have to close this one before opening another.
      SDdataFile = SD.open( fileName, FILE_WRITE );
   
      // if the file is available, write to it:
      if( SDdataFile )
      {
        SDdataFile.println( logData );
        SDdataFile.close();
      }
    }
  }
}

Zero_Magnitude

More checking inside the sd and sdfat libraries ... it looks like there isn't a single example of using a variable name to open a file? 

That can't be right.  What am I missing here? 

sterretje

Quote
(Using a char[] causes a compiler error, so the API that uses that info seems to be deprecated.)
I have some serious doubts. You might be confusing errors and warnings. Post the exact error message that you get when you compile with a character array as well as the code that you use.

Quote
The error I'm tending to get is:
It's not an error but a warning. You can modify the line int pathidx; in the SD.cpp file
Code: [Select]

File SDClass::open(const char *filepath, uint8_t mode) {
  ...
  ...
  int pathidx = 0;

It will take away the warning; not tested but should not have side effects.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Zero_Magnitude

#3
Dec 20, 2018, 05:18 pm Last Edit: Dec 20, 2018, 05:20 pm by Zero_Magnitude
I think editing the library so I can use a variable filename is probably walking down the wrong path. 

So really, my question is "how do I pass a variable path to an SD.open() call?"  Every example in the libraries, in the tutorials, and in every online guide I've seen uses a fixed value (e.g. "test.txt") , and I've tried as many ways as I can possibly think of to pass a variable path to the SD card. 

I've tried pre-initializing the File, running with various lengths of char arrays, pointers to char arrays, strings, converting to c-strings or char arrays, and let's not talk about the insane switch statement.  I'm obviously missing something because this should be a 5-minute programming exercise, not a week-long forum adventure.



Warning given when using a String or char array:
Code: [Select]
C:\Program Files (x86)\Arduino\libraries\SD\src\SD.cpp:456:12: warning: 'pathidx' may be used uninitialized in this function [-Wmaybe-uninitialized]

   filepath += pathidx;

            ^

C:\Program Files (x86)\Arduino\libraries\SD\src\SD.cpp:450:7: note: 'pathidx' was declared here

   int pathidx;


Any code that compiles with this pathidx warning won't write to the SD card, so it's not an ignorable warning.   If it worked I wouldn't care about the warning.


Error given when using a char *:


Code: [Select]
TEST-LinearPosition:109:54: error: no matching function for call to 'SDLib::SDClass::open(char* [14], int)'

       File SDdataFile = SD.open( logData, FILE_WRITE );



From this code:

Code: [Select]
#include <avr/wdt.h>
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
#include "MEGA.h"

#define trackerStorage 37

//Hard-wired to MEGA board.  Don't change this.
const int SDSelect = 53;

String logData = "SWDL_0000.txt";

int shockPosition;
bool SDworking = false;

unsigned int heartbeat = 0;
unsigned int heartBeatMax = 75;
unsigned long timeTracker = 0;
int intervalTimer = 0;

//File SDdataFile;

int logTracker = 0;


/*******************************************************************************
 * 
 * setup()
 * 
 * One-time run on power-up.  Check that the SD card is available, and generate
 * a filename from the EEPROM tracking info.
 * 
 ******************************************************************************/
void setup()
{
  //Serial.begin( 9600 );
  //This is from the hex code in the datasheet.  We're going to set up the
  //auto-running compare register with the 0xAF value.  This gives us a
  //1ms trigger rate. 
  //The TIM line is bit-wise operation and shorthand. 
  OCR0A = 0xAF;           
  TIMSK0 |= _BV(OCIE0A);
  //Set up a four second watchdog timer.  This will reset the controller, but I'll have to figure out
  //a smart way to recover without requiring a complete reset.
  wdt_enable( WDTO_4S );

  // see if the card is present and can be initialized:
  pinMode( SDSelect, OUTPUT );
  SDworking = SD.begin( SDSelect );

  if( SDworking )
  {
    heartBeatMax = 500;     
    //Let's not burn extra EEPROM if there's no SD card.
    EEPROM.get( trackerStorage, logTracker );
    logTracker++;
    if( logTracker > 99 )
    {
      logTracker = 0;
    }
    EEPROM.update( trackerStorage, logTracker );   
  }

}

/*******************************************************************************
 * 
 * loop()
 * 
 * Runs from top to bottom, the back to the top, as long as power is applied.
 * 
 ******************************************************************************/
void loop()
{
  wdt_reset();
  //This will flash super fast if the SD card is failed, or slow if it's fine.
  if( heartbeat > heartBeatMax )
  {
    heartbeat = 0;
    digitalWrite( LED_BUILTIN, !( digitalRead( LED_BUILTIN ) ) );
  }
  if( intervalTimer >= 100 )
  {
    intervalTimer = 0;
    if( SDworking )
    {
      shockPosition = analogRead( positionSensor );
     
      // if the file is available, write to it:
      File SDdataFile = SD.open( logData, FILE_WRITE );
      if( SDdataFile )
      {     
        SDdataFile.println( logData );
        SDdataFile.close();
      }
    }
  }
}

 
/*******************************************************************************
 *
 * ISR: millisecond timing
 *
 * This has a 1ms call frequency, so we can set this up to trigger anything
 * at arbitrary times.  Everthing triggered requires its own flag and then
 * its own reset.
 *
 * The ISR name is Arduino-coded and can't be changed.
 *
 *******************************************************************************/
ISR( TIMER0_COMPA_vect )
{
  heartbeat++;
  timeTracker++;
  intervalTimer++;
}

sterretje

Quote
I think editing the library so I can use a variable filename is probably walking down the wrong path.
No, it's not walking down the wrong path. It's open source; if the author decides not to fix it, you can fix it.

Your code does not compile because you forgot to give us the file Mega.h. So I can't compile it to verify your error.

I took the DumpFile example and modified it to suite your needs. It demonstrates one way of achieving what you want.
Code: [Select]
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

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
  }


  Serial.print("Initializing SD card...");

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


 
  char fileName[13];
  strcpy(fileName, "abc.txt");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open(fileName);

  // if the file is available, write to it:
  if (dataFile) {
    while (dataFile.available()) {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

void loop()
{
}

[/code]
This compiles with the warning about pathidx.

Code: [Select]
Using library SPI at version 1.0 in folder: C:\Users\Wim\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI
Using library SD at version 1.1.1 in folder: C:\Program Files (x86)\Arduino\libraries\SD
Sketch uses 10166 bytes (31%) of program storage space. Maximum is 32256 bytes.
Global variables use 967 bytes (47%) of dynamic memory, leaving 1081 bytes for local variables. Maximum is 2048 bytes.



Quote
Any code that compiles with this pathidx warning won't write to the SD card, so it's not an ignorable warning.   If it worked I wouldn't care about the warning.
It more than likely does not work because the filename in the code that you posted does not adhere to the 8.3 convention.

PS
Which version of the IDE do you use? On which operatings system? Which version of the SD library is reported?
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Zero_Magnitude

No, it's not walking down the wrong path. It's open source; if the author decides not to fix it, you can fix it.
In my experience, if I think the library should be modified, I'm probably thinking wrong.  (i.e. My code is faulty.)  I've only ever had to do this once, and it was for something way outside of "passing a variable".  


Quote from: sterretje
It more than likely does not work because the filename in the code that you posted does not adhere to the 8.3 convention.
Apologies for the typo in the file, I had been heavily modifying it all day yesterday to try various iterations and hit an extra 0 when I was cleaning it up for posting.  Wasn't seeing straight.


Quote from: sterretje
PS
Which version of the IDE do you use? On which operatings system? Which version of the SD library is reported?

IDE v1.8.7, Win 7, SD v1.2.2

Nevertheless ... it turned out the problem was in EEPROM.update() of all things.  It wasn't writing, and so the fileName logic wasn't generating the filename correctly, so it was giving filenames of "SWDL_00-255.txt", which obviously isn't 8.3.  Switching to a forced .put() instead fixed the issue.  I'll add a remove() call to mitigate any future issues.

I've already let them know not to use it more than 50k times, and not for longer than a month of continuous use.  (This is totally reasonable.)

I still can't figure out why I can't use the Serial port at the same time as the SD card, but that's not important enough to try and solve.

Go Up