greiman/SdFat

Issue after latest update.

Opened this issue · 17 comments

I'm using the TMRPcm library and previously sat 2.1.2 with no problems. After updating sdfat to latest version I get the following errors on compile:

TMRpcm.cpp:1442:61: error: use of deleted function 'SdFile::SdFile(const SdFile&)'

SdFat.h:468:7: error: use of deleted function 'PrintFile::PrintFile(const PrintFile&)'

ArduinoFiles.h:43:7: error: 'constexpr FatFile::FatFile(const FatFile&)' is private within this context

Could you point me in the right direction? and Sorry if its been documented.

I had the same problem.
Thanks to codeium.com IA, I solved it this way:
void AudioZeroClass::play(FsFile myFile) {
to
void AudioZeroClass::play(FsFile& myFile) {

Ok, compiler no not give me error, but function do not read the file.
I cannot find a solution.

In the latest version of SdFat the copy constructor for File classes is private to prevent multiple copies of a file object.

A function with this signature will create copy of myFile on the stack.

void AudioZeroClass::play(FsFile myFile) {

This can cause bugs since the File object in the calling program is not updated.

With this call by reference only one copy of the file object exists:

void AudioZeroClass::play(FsFile& myFile) {

I you really want to have multiple, maybe inconsistent, copies of a file object you can edit SdFatConfig.h here.

void AudioZeroClass::play(FsFile& myFile) {

By changing only the definition of audiozero, the file is played, but only the first time.
The following times it does not play.
As if close and open does not it restart.

In the previous version, this did not happen.

`void AudioZeroClass::play(File myFile) {
dacConfigure();
tcConfigure(__sampleRate);
__StartFlag = false;
while (myFile.available()) {
if (!__StartFlag) // Prima volta
{
__SampleIndex = 45; // 45 byte sono l'Header del Wav con le informazioni
myFile.read(__WavSamples, __NumberOfSamples);
__HeadIndex = 0;

  /*once the buffer is filled for the first time the counter can be started*/
   tcStartCounter();
   __StartFlag = true;
}
else  // Successive volte
{
   uint32_t current__SampleIndex = __SampleIndex;
  
   if (current__SampleIndex > __HeadIndex) {   //mentre esce il buffer salendo
     myFile.read(&__WavSamples[__HeadIndex], current__SampleIndex - __HeadIndex);
     __HeadIndex = current__SampleIndex;        
  }
  else if (current__SampleIndex < __HeadIndex) {  //Quando il puntatore dei dati che escono torna a zero
    myFile.read(&__WavSamples[__HeadIndex], __NumberOfSamples -1 - __HeadIndex);  // riempe la fine
    myFile.read(__WavSamples, current__SampleIndex);
    __HeadIndex = current__SampleIndex;
    __HeadIndex = 0;
  }  // analogWrite(A0, __WavSamples[__SampleIndex++]<<2);
}

}
myFile.close();
delay(100);
tcDisable();
tcReset();
analogWrite(A0, 512);
}`

By changing only the definition of audiozero, the file is played, but only the first time.
The following times it does not play.
As if close and open does not it restart.

This is because of the change from call by value to call by reference. The file object in the calling program now used instead of a copy so play now closes the file object in the calling program.

Generally having multiple copies of a file object for an open file causes bugs.

If you don't want to fix the multiple copy problem just edit SdFatConfig.h and allow multiple copies.

How do I get the file to play again?

How do I get the file to play again?

See the above link to the place to change in SdFatConfig.h.

at line 68 of SdFatConfig.h
change

#define FILE_COPY_CONSTRUCTOR_SELECT FILE_COPY_CONSTRUCTOR_PRIVATE

to

#define FILE_COPY_CONSTRUCTOR_SELECT FILE_COPY_CONSTRUCTOR_PUBLIC 

at line 68 of SdFatConfig.h change

#define FILE_COPY_CONSTRUCTOR_SELECT FILE_COPY_CONSTRUCTOR_PRIVATE

to

#define FILE_COPY_CONSTRUCTOR_SELECT FILE_COPY_CONSTRUCTOR_PUBLIC 

Does this fix my issue too?

FILE_COPY_CONSTRUCTOR_PUBLIC

looks like it did... now compiles without error.

Does this fix my issue too?

It doesn't fix the fundamental issue of multiple copies of a file object but it will allow call by value.

It's been a long time since I looked at my code, but am I creating multiple instances?

SdFat sd;
SdFile file;
File dir;

is SdFile an inherited class of File ?

By the way, I'm a novice at C++, so it's a miracle how I managed to get my coding working in the first place.

is SdFile an inherited class of File ?

File is a typedef. The whole class structure has become very complex to allow SdFat to run on many boards. Many of the definitions are here.

There are two basic ways to create a copy of an object. The copy constructor which makes a copy on the stack for call by value.

void AudioZeroClass::play(FsFile myFile)

And the assignment operator:

File file = sd.open("name.txt", O_RDWR | O_CREAT);
File fileCopy = file;  // second copy

The state of the file is in the File object so multiple objects for a file can cause problems. If one object is used for write and the file is closed with another object, file system corruption is likely.

I had the same problem. Thanks to codeium.com IA, I solved it this way: void AudioZeroClass::play(FsFile myFile) { to void AudioZeroClass::play(FsFile& myFile) {

@gioreva BTW I added sdfat to the AudioZero library 5 years ago. Just interested re you using my library https://github.com/rickyelqasem/AudioZeroSdFat or did you modify it yourself?

I think I made a lot of changes.
Especially to use more available wav, e.g. stereophonic, generated online.

But I haven't figured out how I can loop the playback, leaving SdFat private.
Now it only plays the message the first time.

But I haven't figured out how I can loop the playback, leaving SdFat private.
Now it only plays the message the first time.

I would put a rewind at the start of void AudioZeroClass::play(FsFile& myFile) like this:

myFile.rewind();

and remove the myFile.close() at the end.