I think I'm doing character arrays incorrectly (door chime)

Greetings, Arduino community. Long time lurker, first time caller.

I’ve spent several days studying FAQ and self-help resources.

I can make this ‘work’ with one sound file, but it fails when I try to implement a second file.

It’s an older Arduino Duemilanove with the ATmega168 with an Adafruit Wave Shield.

5 years ago I made a door chime with a normally open switch. Switch contact is made when the door opens. I knew the code had flaws.

New location, I want to implement changes. I want to add a “door closed” sound and add support for multiple doors. (switches)

The old program had an asterisk pointer for the array (deprecated). I thought I had dealt with that, but maybe misunderstood.

I’ve had to omit lines of code to stay within the forum post limit.

/
 Input pin is assumed to connect to a normally open switch HIGH.  When door opens, the switch makes contact LOW.
 */

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"


SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play
WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

int debounce = 100;           //Used to debounce the switch
int playopen = 0;             //flag used to keep the sound from playing more than once
int playclosed = 0;           //flag used to keep the sound from playing more than once

char const switch_1_contact_made_sound[] = "open_1.wav";
char const switch_1_contact_lost_sound[] = "close_1.wav";

// char const switch_2_contact_made_sound[] = "open_2.wav";
// char const switch_2_contact_lost_sound[] = "close_2.wav";




void setup() 
{
  // set up serial port
  Serial.begin(9600);
  putstring_nl("WaveHC with 6 buttons");
  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());     // if this is under 150 bytes it may spell trouble!

  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(13, OUTPUT);   //I don't know what this is for, but it has a wire soldered on it, so leaving it alone

  pinMode(19, INPUT);   //Connected to Door 1 reed switch
//pinMode(18, INPUT);   //Connected to Door 2 reed switch

  // enable pull-up resistors on switch pins (analog inputs which are 14 thru 19)
  digitalWrite(19, HIGH);
  digitalWrite(18, HIGH);
  //Add more pins if we want to implement more trigger methods.  Like a trip wire, or a pushbutton, whatever.
  

  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) 
  {                                      //play with 8 MHz spi (default faster!)  
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    sdErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }


  // Lets tell the user about what we found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?

  // Try to open the root directory
  if (!root.openRoot(vol)) 
  {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }
  // Whew! We got past the tough parts.
  putstring_nl("Ready!");
}

void loop() 
{
  check_switch();   //Go decide if the switch is closed or open (LOW or HIGH)
}



void check_switch()
{
  int door_1_switch_currently;
  int door_1_switch_previously;

//We're going to read the value of the pin, pause a moment, then read it again.  
//  1.)  HIGH first time, HIGH second time means door is open
//  2.)  LOW first time, LOW second time means door is closed

  door_1_switch_currently = digitalRead(19);                   //Read the state of door switch 1
  door_1_switch_previously = door_1_switch_currently;          //Set the two values equal to each other.  What 'was' becomes what 'is'
  delay(debounce);                                             //wait a little bit for the switch to settle
  door_1_switch_currently = digitalRead(19);                   //Read the switch again


//The switch has been read, now do something based on the observation
//1.)  The door just opened, so play the open sound

  if(door_1_switch_currently == HIGH && door_1_switch_previously == HIGH && playopen == 0)  //Door switch 1 is in contact (door is open)
  {
      playopen = 1;               //Set the flag so we play it only once
      playclosed = 0;             //Reset the closed flag so that sound can play when this door closes
      putstring_nl("Playing open sound for door 1.");
      playcomplete(switch_1_contact_made_sound);   //play the door 1 open sound
  }


//2.)  The door has just closed, so play the closed sound

  if(door_1_switch_currently == LOW && door_1_switch_previously == LOW && playclosed == 0)  //Door switch 1 is not in contact (door is closed)
  {
      playclosed = 1;              //Set the flag so we play it only once
      playopen = 0;                //Reset the open flag so that sound can play when this door opens
  //    playcomplete(switch_1_contact_lost_sound);   //play the door closed sound
  }

}    //This bracket closes void check_switch function




// Plays a full file from beginning to end with no pause.
void playcomplete(char filename[]) 
{
  // call our helper to find and play this name
  playfile(filename);
}

void playfile(char filename[]) 
{
  // see if the wave object is currently doing something
  if (wave.isplaying) 
  {                             // already playing something, so stop it!
    wave.stop(); // stop it
  }
  // look in the root directory and open the file
  if (!f.open(root, filename)) 
  {
    putstring("Couldn't open file "); 
    Serial.print(filename); 
    return;
  }
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) 
  {
    putstring_nl("Not a valid WAV"); 
    return;
  }
  // ok time to play! start playback
  wave.play();
}

I get these compiler warnings:

In function 'void check_switch()':

153:47: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]

       playcomplete(switch_1_contact_made_sound);   //play the door 1 open sound

                                               ^

172:6: note: initializing argument 1 of 'void playcomplete(char*)'

 void playcomplete(char filename[])

the sound plays and the serial monitor outputs this:

WaveHC with 6 buttons
Free RAM: 119
Using partition 1, type is FAT16
Ready!
Playing open sound for door 1.    <this one happens at boot>
Playing open sound for door 1.
Playing open sound for door 1.

If I un-comment the line to play the door closed sound,

playcomplete(switch_1_contact_lost_sound);   //play the door closed sound

then strange things happen. There are additional compiler warnings and this is output.

<snip>
Ready!
Playing open sound for door 1.    <this happens at boot, but no sound>
WaWWWWWWWWWWWWWWWWWWWWWWWWW        <ad infinitum>

I am completely lost.

I don’t understand the warnings about invalid conversion from const char* to char* I declared it as a constant because the FAQs seemed to advise this.

What is the compiler telling me with the note about initializing argument?

My suspicion is that the file name isn’t being properly passed to void playcomplete and rather than arriving as text it is arriving as a memory address or overwriting the variable with random memory bytes.

I think I lack enough understanding about how the programming language passes and receives the array arguments from one function to another.

Can you point me in the right direction?

The compiler warning is easy to deal with. The function expects a char pointer. You are supplying a const char *. While these are very similar, the function is allowed to change the array passed in. That is probably not what you want, so the function's argument type should be const char . But, if you don't want to change that, and don't want to remove the const from the variable declaration, use a cast in the function call:

    playcomplete((char *)switch_1_contact_lost_sound);

Your state change code looks wrong. You should look at the state change detection example again. It makes sense to see if the current state is not the same as the previous state, not to see if they are same.

If they are the same, no change has taken place, so that is not the time to play the music.

Still, I suspect that the Duemilanove, with the 168 chip, just doesn't have enough memory.

Thank you for sharing your knowledge.

I made the change in the function call and the compiler no longer gives warnings.

I will read more about that to understand exactly how it is different.

My LOW and HIGH were flip-flopped. Good catch. I recently rolled back to an old-old sample copy where I had not yet changed it from normally closed to normally open.

I suspect you are correct about memory. I did not realize how limited it was. After compiling, it says there are 173 bytes available for local variables.

Would you expect the Arduino Uno Rev3 SMD to allow enough memory? It appears to have twice as much.

notagoodprogrammer:
Would you expect the Arduino Uno Rev3 SMD to allow enough memory? It appears to have twice as much.

The Arduino Uno has twice the RAM as the Duemilanove, but the good news is that the ATmega328P-PU is pin compatible with the Duemilanove's ATmega168. This means you won't need a completely new Arduino. You can buy blank chips and burn the bootloader and set the fuses, or you can buy "Arduino" ready chips.

Update - the project is finished.

It is installed and has been working for several weeks now. Thank you all for helping.

The additional memory of the Atmega328 seems to have made the difference in running my program.

The compiler does give a warning about low memory available (431 bytes left for local variables), but it's up and running on an Arduino UNO R3

I thought I would share the code, but the text exceeds what is allowed here.

notagoodprogrammer:
The compiler does give a warning about low memory available (431 bytes left for local variables), but it’s up and running on an Arduino UNO R3

That’s not the compiler. The compiler could care less how close you get to the limits, that message comes from the IDE builder that has a memory warning set to print when usage exceeds 75% of available. This threshold can be changed in the preferences.txt file. Look for build.warn_data_percentage.