From 4ac487fe057ded7fd93d1cbb0510592869107853 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Wed, 23 May 2012 15:06:54 +1000 Subject: [PATCH] Selecting the melody to play when alarm goes off --- libraries/Melody/Melody.cpp | 18 +++- libraries/Melody/Melody.h | 1 + .../RTC/examples/AlarmClock/AlarmClock.pde | 13 ++- .../examples/AlarmClock/LowPowerMelody.cpp | 9 ++ .../RTC/examples/AlarmClock/LowPowerMelody.h | 1 + .../RTC/examples/AlarmClock/SetMelody.cpp | 86 +++++++++++++++++++ libraries/RTC/examples/AlarmClock/SetMelody.h | 40 +++++++++ 7 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 libraries/RTC/examples/AlarmClock/SetMelody.cpp create mode 100644 libraries/RTC/examples/AlarmClock/SetMelody.h diff --git a/libraries/Melody/Melody.cpp b/libraries/Melody/Melody.cpp index c4bbd2c0..3960a5d1 100644 --- a/libraries/Melody/Melody.cpp +++ b/libraries/Melody/Melody.cpp @@ -137,7 +137,7 @@ void Melody::setLoopDuration(unsigned long ms) /** * \brief Starts playing the melody, or restarts it if already playing. * - * \sa setMelody(), stop(), loopCount() + * \sa playOnce(), setMelody(), stop(), loopCount() */ void Melody::play() { @@ -150,6 +150,22 @@ void Melody::play() nextNote(); } +/** + * \brief Plays the melody once and then stops. + * + * \sa play(), stop() + */ +void Melody::playOnce() +{ + stop(); + if (size == 0) + return; // No melody to play. + loopsLeft = 1; + posn = 0; + playing = true; + nextNote(); +} + /** * \brief Stops playing the melody. * diff --git a/libraries/Melody/Melody.h b/libraries/Melody/Melody.h index f14a2819..2f1701a8 100644 --- a/libraries/Melody/Melody.h +++ b/libraries/Melody/Melody.h @@ -131,6 +131,7 @@ public: void setLoopDuration(unsigned long ms); void play(); + void playOnce(); void stop(); void setMelody(const int *notes, const uint8_t *lengths, unsigned int size); diff --git a/libraries/RTC/examples/AlarmClock/AlarmClock.pde b/libraries/RTC/examples/AlarmClock/AlarmClock.pde index bc14006f..3bc68dd1 100644 --- a/libraries/RTC/examples/AlarmClock/AlarmClock.pde +++ b/libraries/RTC/examples/AlarmClock/AlarmClock.pde @@ -35,6 +35,7 @@ #include "SetAlarm.h" #include "SetTime.h" #include "SetDate.h" +#include "SetMelody.h" #include "LowPowerMelody.h" // I/O pins that are used by this sketch. @@ -51,6 +52,7 @@ #define SETTING_24HOUR 0 // 0: 12 hour, 1: 24 hour #define SETTING_ALARM_TIMEOUT 1 // Timeout in minutes for the alarm #define SETTING_SNOOZE 2 // 0: no snooze, 1: snooze +#define SETTING_MELODY 3 // Melody to play for the alarm // Initialize the LCD FreetronicsLCD lcd; @@ -60,8 +62,8 @@ SoftI2C bus(RTC_DATA, RTC_CLOCK); DS1307RTC rtc(bus, RTC_ONE_HZ); // Melody to play when the alarm sounds. -int alarmNotes[] = {NOTE_C6, NOTE_C6, NOTE_C6, NOTE_C6, NOTE_REST}; -byte alarmLengths[] = {8, 8, 8, 8, 2}; +int defaultMelodyNotes[5] = {NOTE_C6, NOTE_C6, NOTE_C6, NOTE_C6, NOTE_REST}; +byte defaultMelodyLengths[5] = {8, 8, 8, 8, 2}; LowPowerMelody alarmMelody(BUZZER); uint8_t prevHour = 24; @@ -77,6 +79,7 @@ SetAlarm alarm3(mainForm, "Alarm 3", 2); SetAlarm alarm4(mainForm, "Alarm 4", 3); IntField alarmTimeout(mainForm, "Alarm timeout", 2, 10, 1, 2, " minutes"); BoolField snooze(mainForm, "Snooze alarm", "On", "Off", false); +SetMelody alarmSound(mainForm, "Alarm sound"); SetTime setTime(mainForm, "Set current time"); SetDate setDate(mainForm, "Set current date"); BoolField hourMode(mainForm, "Hour display", "24 hour clock", "12 hour clock", false); @@ -105,7 +108,7 @@ void setup() { lcd.enableScreenSaver(3); // Initialize the alarm melody. - alarmMelody.setMelody(alarmNotes, alarmLengths, sizeof(alarmLengths)); + alarmMelody.setMelody(defaultMelodyNotes, defaultMelodyLengths, sizeof(defaultMelodyLengths)); alarmMelody.stop(); // Force Timer2 to be disabled. // Read the clock settings from the realtime clock's NVRAM. @@ -115,6 +118,8 @@ void setup() { alarmTimeout.setValue(rtc.readByte(SETTING_ALARM_TIMEOUT)); alarmMelody.setLoopDuration(60000UL * alarmTimeout.value()); snooze.setValue(rtc.readByte(SETTING_SNOOZE) != 0); + alarmSound.setValue(rtc.readByte(SETTING_MELODY)); + alarmSound.updateMelody(); // Set the initial time and date and find the next alarm to be triggered. RTCTime time; @@ -176,6 +181,8 @@ void loop() { alarmMelody.setLoopDuration(60000UL * alarmTimeout.value()); } else if (snooze.isCurrent()) { rtc.writeByte(SETTING_SNOOZE, (byte)snooze.value()); + } else if (alarmSound.isCurrent()) { + rtc.writeByte(SETTING_MELODY, (byte)alarmSound.value()); } prevHour = 24; // Force an update of the main screen. findNextAlarm(); // Update the time of the next alarm event. diff --git a/libraries/RTC/examples/AlarmClock/LowPowerMelody.cpp b/libraries/RTC/examples/AlarmClock/LowPowerMelody.cpp index e90d90bc..07745a1a 100644 --- a/libraries/RTC/examples/AlarmClock/LowPowerMelody.cpp +++ b/libraries/RTC/examples/AlarmClock/LowPowerMelody.cpp @@ -34,6 +34,15 @@ void LowPowerMelody::play() Melody::play(); } +void LowPowerMelody::playOnce() +{ + // Turn on Timer2. + power_timer2_enable(); + + // Start the melody playing. + Melody::playOnce(); +} + void LowPowerMelody::stop() { // Stop the melody playing. diff --git a/libraries/RTC/examples/AlarmClock/LowPowerMelody.h b/libraries/RTC/examples/AlarmClock/LowPowerMelody.h index 4e2be183..714a586a 100644 --- a/libraries/RTC/examples/AlarmClock/LowPowerMelody.h +++ b/libraries/RTC/examples/AlarmClock/LowPowerMelody.h @@ -30,6 +30,7 @@ public: LowPowerMelody(uint8_t pin) : Melody(pin) {} void play(); + void playOnce(); void stop(); }; diff --git a/libraries/RTC/examples/AlarmClock/SetMelody.cpp b/libraries/RTC/examples/AlarmClock/SetMelody.cpp new file mode 100644 index 00000000..05480cbd --- /dev/null +++ b/libraries/RTC/examples/AlarmClock/SetMelody.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "SetMelody.h" +#include "LowPowerMelody.h" +#include + +extern LowPowerMelody alarmMelody; +extern int defaultMelodyNotes[5]; +extern byte defaultMelodyLengths[5]; + +static int haircutNotes[] = { + NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, + NOTE_REST, NOTE_B3, NOTE_C4, NOTE_REST +}; +static byte haircutLengths[] = {4, 8, 8, 4, 4, 4, 4, 4, 2}; + +static int sosNotes[] = { + NOTE_C6, NOTE_C6, NOTE_C6, NOTE_REST, + NOTE_C6, NOTE_C6, NOTE_C6, NOTE_REST, + NOTE_C6, NOTE_C6, NOTE_C6, NOTE_REST +}; +static byte sosLengths[] = {8, 8, 8, 8, 4, 4, 4, 8, 8, 8, 8, 2}; + +static const char item_FourBeeps[] PROGMEM = "Four beeps"; +static const char item_Haircut[] PROGMEM = "Shave 'n haircut"; +static const char item_SOS[] PROGMEM = "S.O.S."; +static ListItem melodyNames[] PROGMEM = { + item_FourBeeps, + item_Haircut, + item_SOS, + 0 +}; + +SetMelody::SetMelody(Form &form, const String &label) + : ListField(form, label, melodyNames) + , needsPlay(false) +{ +} + +int SetMelody::dispatch(int event) +{ + int result = ListField::dispatch(event); + if (result == FORM_CHANGED) { + updateMelody(); + needsPlay = true; // Play when we see the button release event. + } else if (needsPlay && event < 0) { + needsPlay = false; + alarmMelody.playOnce(); + } + return result; +} + +void SetMelody::updateMelody() +{ + switch (value()) { + case 0: default: + alarmMelody.setMelody(defaultMelodyNotes, defaultMelodyLengths, sizeof(defaultMelodyLengths)); + break; + case 1: + alarmMelody.setMelody(haircutNotes, haircutLengths, sizeof(haircutLengths)); + break; + case 2: + alarmMelody.setMelody(sosNotes, sosLengths, sizeof(sosLengths)); + break; + } +} diff --git a/libraries/RTC/examples/AlarmClock/SetMelody.h b/libraries/RTC/examples/AlarmClock/SetMelody.h new file mode 100644 index 00000000..f2e49f43 --- /dev/null +++ b/libraries/RTC/examples/AlarmClock/SetMelody.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SetMelody_h +#define SetMelody_h + +#include + +class SetMelody : public ListField { +public: + SetMelody(Form &form, const String &label); + + int dispatch(int event); + + void updateMelody(); + +private: + bool needsPlay; +}; + +#endif