Read full 10 bytes of RFID tag to play audio file

Hello,

To begin, I am a complete novice at using this Arduino but I understand the code enough to mess around in it. This is using an arduino UNO and a wave shield with a serial RFID reader from parallax. Originally, the code for this can be found here:

https://cdn.makezine.com/make/28/CharlieBearV2.pde

-It is using the first 8 values from the RFID tag to play the audio file.

Here is my edited code:

// An interactive bear for Charlie -- RFID triggered sound responses

#include <FatReader.h>
#include <SdReader.h>
#include "WaveHC.h"
#include "WaveUtil.h"
#include "LowPower.h"

SdReader memcard;
FatVolume vol;
FatReader root;
FatReader file;
WaveHC wave;

#define ENABLE 7      // Set the pin number for enabling the RFID reader. The Audio Shield uses pins 2-5.
#define NUMTAGS 22

int  val = 0; 
char code[10];
String id;
int bytesread = 0; 

char knowntags[NUMTAGS][11] = {"0300789D24", "2100E0B6ED", "2100DFF660", "2100DFD586", "2100DFB1E5", "2100E0CBAA", "2100E07B21", "2100E0B9D6", "2100D82331", "2100DFA060", "2100DFBC77", "2100DFA69A", "2100D7EFF7", "2100DFE251", "2100E02F09", "2100DFBF83", "2100DFD9EA", "2100E0ABA6", "2100DFDFC4", "2100DFF0DF", "36005B7B50", "36005B7C05"};
char soundfiles[NUMTAGS][9] = {"1000.WAV", "1001.WAV", "1002.WAV", "1003.WAV", "1004.WAV", "1005.WAV", "1006.WAV", "1007.WAV", "1008.WAV", "1009.WAV", "1010.WAV", "1011.WAV", "1012.WAV", "1013.WAV", "1014.WAV", "1015.WAV", "1016.WAV", "1017.WAV", "1018.WAV", "1019.WAV", "1020.WAV", "1021.WAV"};
char filename[1][14];

void setup() { 
  //////// Set up RFID reader to collect tag information /////////////////////
  Serial.begin(2400);         // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
  pinMode(ENABLE,OUTPUT);     // Set digital pin 7 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(ENABLE, LOW);  // Activate the RFID reader
  
  //////// Set the pins to output for driving the Audio Shield
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  ////////// Set up the Audio Shield by initializing the memory card for reading ////////
  if (!memcard.init()) {
    // If something went wrong sdErrorCheck prints out the error check
    putstring_nl("Card init. failed!"); 
    cardErrorCheck();
    return;
  }
  
  //This will optimize the reading of the memory card -- remove it if it times out
  memcard.partialBlockRead(true);
  
  // Find a FAT formatted partition by looking in teh first five slots. Remember your memory card should be FAT16 or FAT32 formatted
  uint8_t partition;
  for (partition = 0; partition < 5; partition++) {
    if (vol.init(memcard, partition))
      break;
  }
  if (partition == 5)
  {
    putstring_nl("No valid FAT partition");
    cardErrorCheck();
    while(1); // This is a point of no return. Format your memory card properly and try again.
  }

  // Open the root directory for reading the files
  if (!root.openRoot(vol))
  {
    putstring_nl("Can't open root directory");
    while(1); // Something went wrong here so investigate the file system on your memory card.
  }
  
  // If you got this far then the card is ready to read
  filename[0][10] = 'a';
  filename[0][11] = 'a';
  filename[0][12] = 'a';
  filename[0][13] = 'a';
  putstring_nl("Ready to go");
  wave.volume = 0;
}

// If we find an error, check what the error is and show it on the serial terminal
void cardErrorCheck(void)
{
  if(!memcard.errorCode()) return;
  putstring("\n\rSD I/O error:");
  Serial.print(memcard.errorCode());
  putstring(", ");
  Serial.print(memcard.errorData());
  while(1); // Stick here if there is an error
}

void loop() { 

  if(Serial.available() > 0) {          // if data available from reader  
    if((val = Serial.read()) == 10) {   // check for header 
      bytesread = 0; 
      while(bytesread<10) {              // read 10 digit code 
        if( Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          }
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {              // if 10 digit read is complete 
        if (wave.isplaying)
        {
          
          //Stop the audio if tag "030091FACB" is read
          if (strcmp(code,"030091FACB") == -10 )
          {
            silence();
          }
        }
        else
        {
          //Serial.print(sizeof(code));
          //char test = char(code) + '.wav';
        
          //Serial.print(code);

          playsound(code);
          //Serial.print("TAG code is: ");   // possibly a good TAG 
          //Serial.println(code);            // print the TAG code 
          Serial.flush();                  // Flush the serial buffer before trying to read a new code
 
        }
              } 
      bytesread = 0; 
    }
  }
  else
  {
    //low power library until woken up 
    //LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);   
    //digitalWrite(ENABLE,HIGH); //Disable the RFID Attena
    
  }

} 

void playsound(char codetoplay[]) {
  
  for(int i = 0; i<10; i++) {    // Make a filename from the first 8 characters of the RFID tag number
    filename[0][i]=codetoplay[i];
  }
  int i = 10;
  while(filename[0][i] != '\0')
  {
    filename[0][10]='.';
    filename[0][11]='w';
    filename[0][12]='a';
    filename[0][13]='v';
    filename[0][14]='\0';
    i++;
  }
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename[0]);
  
}

void playfile(char *name) {
  
  if (!file.open(root, name)) {
      putstring_nl("Couldn't open file"); 
      return;
   }
   if (!wave.create(file)) 
    {
      putstring_nl("Not a valid WAV"); 
      return;
    }
    wave.play();  
}

void silence() {
  if(wave.isplaying) {
    wave.stop();
  }
}

Specifically, in the playsound() method is where my problem begins. After the 13th column it seems to append more char's to the char array "filename" after the declared size of the column.

Output:

Ready to go
030091F9EA.wav030091F9EA
Couldn't open file

But when I use the while loop in my edited code I get:

Ready to go
030091F9EA.wavCouldn't open file

This gets me the desired name for the audio file, but it does not play the audio file on the SD card.
I will attach a picture for that.

My question is: Is it possible to have it read all 10 HEX values or do I have to stick to 8? with 8 it does not append after the declared column size.

char filename[1][14];

I don't understand why you set up a 2d array with only one element instead of using char filename[14].

Arrays are 0 indexed, and the elements are filename[0][0] to filename[0][13] But then you proceed to place data in a memory location you don't own, filename[0][14], and anything can happen. Fix this and report back how the program functions.

[code]char filename[1][15];
void playsound(char codetoplay[]) {
  
  for(int i = 0; i<10; i++) {    // Make a filename from the first 8 characters of the RFID tag number
    filename[0][i]=codetoplay[i];
  }
  int i = 10;
  while(filename[0][i] != '\0')
  {
    filename[0][10]='.';
    filename[0][11]='w';
    filename[0][12]='a';
    filename[0][13]='v';
    filename[0][14]='\0';
    i++;
  }
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename[0]);
  }

This code

cattledog:

  int i = 10;

while(filename[0][i] != '\0')
  {
    filename[0][10]='.';
    filename[0][11]='w';
    filename[0][12]='a';
    filename[0][13]='v';
    filename[0][14]='\0';
    i++;
  }

is totally unnecessary. The first time through, i = 10 and filename[0] is not '\0' so you copy in your filename extension and then increment i. The second time through filename[0] is now 'w' (since you just copied that there) and you do it all again, and again and again until i equals 14.
Just do it once.

So I got rid of the 2d array and made it: char filename[14];

void playsound(char codetoplay[]) {
  
  for(int i = 0; i<10; i++) {    // Make a filename from the first 8 characters of the RFID tag number
    filename[i]=codetoplay[i];
  }
  
  filename[10]='.';
  filename[11]='w';
  filename[12]='a';
  filename[13]='v';
  
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename);  
  
  
}

but that output gave me:

030091F9EA.wav030091F9EA
Couldn't open file
TAG code is: 030091F9EA

Then I changed it to char filename[15];

and the output gave me:

030091F9EA.wavCouldn't open file
TAG code is: 030091F9EA

Here is my current code:

// An interactive bear for Charlie -- RFID triggered sound responses

#include <FatReader.h>
#include <SdReader.h>
#include "WaveHC.h"
#include "WaveUtil.h"
#include "LowPower.h"

SdReader memcard;
FatVolume vol;
FatReader root;
FatReader file;
WaveHC wave;

#define ENABLE 7      // Set the pin number for enabling the RFID reader. The Audio Shield uses pins 2-5.
#define NUMTAGS 22

int  val = 0; 
char code[10];
String id;
int bytesread = 0; 

char knowntags[NUMTAGS][11] = {"0300789D24", "2100E0B6ED", "2100DFF660", "2100DFD586", "2100DFB1E5", "2100E0CBAA", "2100E07B21", "2100E0B9D6", "2100D82331", "2100DFA060", "2100DFBC77", "2100DFA69A", "2100D7EFF7", "2100DFE251", "2100E02F09", "2100DFBF83", "2100DFD9EA", "2100E0ABA6", "2100DFDFC4", "2100DFF0DF", "36005B7B50", "36005B7C05"};
char soundfiles[NUMTAGS][9] = {"1000.WAV", "1001.WAV", "1002.WAV", "1003.WAV", "1004.WAV", "1005.WAV", "1006.WAV", "1007.WAV", "1008.WAV", "1009.WAV", "1010.WAV", "1011.WAV", "1012.WAV", "1013.WAV", "1014.WAV", "1015.WAV", "1016.WAV", "1017.WAV", "1018.WAV", "1019.WAV", "1020.WAV", "1021.WAV"};
char filename[15];

void setup() { 
  //////// Set up RFID reader to collect tag information /////////////////////
  Serial.begin(2400);         // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
  pinMode(ENABLE,OUTPUT);     // Set digital pin 7 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(ENABLE, LOW);  // Activate the RFID reader
  
  //////// Set the pins to output for driving the Audio Shield
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  ////////// Set up the Audio Shield by initializing the memory card for reading ////////
  if (!memcard.init()) {
    // If something went wrong sdErrorCheck prints out the error check
    putstring_nl("Card init. failed!"); 
    cardErrorCheck();
    return;
  }
  
  //This will optimize the reading of the memory card -- remove it if it times out
  memcard.partialBlockRead(true);
  
  // Find a FAT formatted partition by looking in teh first five slots. Remember your memory card should be FAT16 or FAT32 formatted
  uint8_t partition;
  for (partition = 0; partition < 5; partition++) {
    if (vol.init(memcard, partition))
      break;
  }
  if (partition == 5)
  {
    putstring_nl("No valid FAT partition");
    cardErrorCheck();
    while(1); // This is a point of no return. Format your memory card properly and try again.
  }

  // Open the root directory for reading the files
  if (!root.openRoot(vol))
  {
    putstring_nl("Can't open root directory");
    while(1); // Something went wrong here so investigate the file system on your memory card.
  }
  
  // If you got this far then the card is ready to read
  putstring_nl("Ready to go");
  wave.volume = 0;
}

// If we find an error, check what the error is and show it on the serial terminal
void cardErrorCheck(void)
{
  if(!memcard.errorCode()) return;
  putstring("\n\rSD I/O error:");
  Serial.print(memcard.errorCode());
  putstring(", ");
  Serial.print(memcard.errorData());
  while(1); // Stick here if there is an error
}

void loop() { 

  if(Serial.available() > 0) {          // if data available from reader  
    if((val = Serial.read()) == 10) {   // check for header 
      bytesread = 0; 
      while(bytesread<10) {              // read 10 digit code 
        if( Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          }
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {              // if 10 digit read is complete 
        if (wave.isplaying)
        {
          
          //Stop the audio if tag "030091FACB" is read
          if (strcmp(code,"030091FACB") == -10 )
          {
            silence();
          }
        }
        else
        {
          //Serial.print(sizeof(code));
          //char test = char(code) + '.wav';
        
          //Serial.print(code);

          playsound(code);
          Serial.print("TAG code is: ");   // possibly a good TAG 
          Serial.println(code);            // print the TAG code 
          Serial.flush();                  // Flush the serial buffer before trying to read a new code
 
        }
              } 
      bytesread = 0; 
    }
  }
  else
  {
    //low power library until woken up 
    //LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);   
    //digitalWrite(ENABLE,HIGH); //Disable the RFID Attena
    
  }

} 

void playsound(char codetoplay[]) {
  
  for(int i = 0; i<10; i++) {    // Make a filename from the first 8 characters of the RFID tag number
    filename[i]=codetoplay[i];
  }
  
  filename[10]='.';
  filename[11]='w';
  filename[12]='a';
  filename[13]='v';
  
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename);  
  
  
}

void playfile(char *name) {
  
  if (!file.open(root, name)) {
      Serial.print(name);
      putstring_nl("Couldn't open file"); 
      return;
   }
   if (!wave.create(file)) 
    {
      putstring_nl("Not a valid WAV"); 
      return;
    }
    wave.play();  
}

void silence() {
  if(wave.isplaying) {
    wave.stop();
  }
}

I've attached pictures of the serial output and what is on the SD card.

filename[10]='.';
  filename[11]='w';
  filename[12]='a';
  filename[13]='v';

but that output gave me:

030091F9EA.wav030091F9EA
Couldn't open file
TAG code is: 030091F9EA

In this case, with char filename[14] the is no Null terminator to the character array. When you initialize char filename[15] with global scope a 0 winds up in the [14] cell. You are better off explicitly adding it with

filename[10]='.';
  filename[11]='w';
  filename[12]='a';
  filename[13]='v';
  filename[14]='\0';

Stylistically, I would have written your code differently. Null terminate the code[] array when it is read into the Arduino so that it becomes null terminated and then use the c-string function strcat(code,".wav");
http://www.cplusplus.com/reference/cstring/strcat/

This does not look correct to me as code[] is not null terminated.

if (wave.isplaying)
        {
          
          //Stop the audio if tag "030091FACB" is read
          if (strcmp(code,"030091FACB") == -10 )
          {
            silence();
          }
        }

I'm not clear what the match needs to be to stop playing, but typically you would use strcmp() and a return == 0 is a match. != 0 is not a match.
http://www.cplusplus.com/reference/cstring/strcmp/

cattledog:
This does not look correct to me as code[] is not null terminated.

if (wave.isplaying)

{
         
         //Stop the audio if tag "030091FACB" is read
         if (strcmp(code,"030091FACB") == -10 )
         {
           silence();
         }
       }



I'm not clear what the match needs to be to stop playing, but typically you would use strcmp() and a return == 0 is a match. != 0 is not a match.
http://www.cplusplus.com/reference/cstring/strcmp/

If I wanted 0 i would have to do:

char stopArray [11] = {'0','3','0','0','9','1','F','A','C','B','\0'};
int stopVal = strcmp(stopArray,"030091FACB");
Serial.print(stopVal);

This will give 0. I guess I was just lazy and said -10 is good enough. But this only executes when a file is playing which is not happening at the moment. For some reason, when I change it to the 8 HEX values:

char filename[13];

void playsound(char codetoplay[]) {
  
  for(int i = 0; i<8; i++) {    // Make a filename from the first 8 characters of the RFID tag number
    filename[i]=codetoplay[i];
  }
  
  filename[8]='.';
  filename[9]='w';
  filename[10]='a';
  filename[11]='v';
  filename[12]='\0';
  
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename);  
  
  
}

The file will play. This is also if I change the file name on the SD card. And if I put the stop tag on the reader the audio will stop.

when I change it to the 8 HEX values:

I have been focusing on the array and string handling problems and did not pay attention to the issue of playing the file from the sd card.

I'm not familiar with the sd libraries you are using, but do they support more than 8.3 (xxxxxxxx.xxx)filenames?
They may not be designed to support the long file names. That may be why the original code from makezine transforms the read data into a shorter filename with .wav.

// Make a filename from the first 8 characters of the RFID tag number

cattledog:
I have been focusing on the array and string handling problems and did not pay attention to the issue of playing the file from the sd card.

I'm not familiar with the sd libraries you are using, but do they support more than 8.3 (xxxxxxxx.xxx)filenames?
They may not be designed to support the long file names. That may be why the original code from makezine transforms the read data into a shorter filename with .wav.

Well, it looks like it would be the Fatreader.h library. Because the problem always happens at this line:

if (!file.open(root, name)) {

And "file" is a type (FatReader) is that a standard C++ lib? because of its called from:

#include <FatReader.h>

So could I edit it? or what would I be looking for?

#include "WaveHC.h"

From the documentation I see

WaveHC only supports short 8.3 DOS style file names.

I don't know what it will take to modify the WaveHC library and the underlying SD libraries to accept long file names. I doubt it will be simple.

I do know that the SdFat library does accept long file names so I don't think its fundamentally impossible.

What is your motivation to move away from 8.3 filenames?

Another link on file names

cattledog:
What is your motivation to move away from 8.3 filenames?

Well, I can definitely try. Because it will be a learning experience. For the Holidays tomorrow, I will leave it as the 8.3 DOS file naming for this project so I can show my grandma. Then work on the project after.

Is the sdFat library that much different from waveHC lib?

I will leave it as the 8.3 DOS file naming for this project so I can show my grandma. Then work on the project after.

Is the sdFat library that much different from waveHC lib?

The current version of WaveHC is a fairly new library and was authored by Bill Greiman who is the author of SdFat. He did not put long file name support into WaveHC.
I certainly don't know how SdFat was modified from the 8.3 file names and what it would take to work it into WaveHC. If you manage to figure out how to do this, you will amass many karma points when you post the solution. :slight_smile:

I would suggest that you start a new thread in the Storage section of the forum, with a very narrow question around modifying WaveHC to accept long file names instead of being limited to 8.3 names. Bill Greiman does monitor that section of the forum, and might provide an answer.

Another approach would be to suggest the change on the Git Hub page for the library.

Good luck.