diff --git a/src/lib/tunes/default_tunes.cpp b/src/lib/tunes/default_tunes.cpp index fe441676e5..d516cccdbe 100644 --- a/src/lib/tunes/default_tunes.cpp +++ b/src/lib/tunes/default_tunes.cpp @@ -37,25 +37,19 @@ #include "tunes.h" -// initialise default tunes +#define PX4_DEFINE_TUNE(ordinal,name,tune,interruptable) tune, +// Initialize default tunes const char *const Tunes::_default_tunes[] = { - "", // empty to align with the index - "MFT240L8 O4aO5dc O4aO5dc O4aO5dc L16dcdcdcdc", // startup tune - "MBT200a8a8a8PaaaP", // ERROR tone - "MFT200e8a8a", // Notify Positive tone - "MFT200e8e", // Notify Neutral tone - "MFT200e8c8e8c8e8c8", // Notify Negative tone - "MNT75L1O2G", //arming warning - "MBNT100a8", //battery warning slow - "MBNT255a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8", //battery warning fast - "MFT255L4AAAL1F#", //gps warning slow - "MFT255L4<<G#6A#6B#4", // home set tune +#include "tune_definition.desc" }; +#undef PX4_DEFINE_TUNE + +#define PX4_DEFINE_TUNE(ordinal,name,tune,interruptable) interruptable, +// Initialize default tunes +const bool Tunes::_default_tunes_interruptable[] = { +#include "tune_definition.desc" +}; +#undef PX4_DEFINE_TUNE // set default_tunes array size const unsigned int Tunes::_default_tunes_size = sizeof(_default_tunes) / sizeof(_default_tunes[0]); diff --git a/src/lib/tunes/tune_definition.desc b/src/lib/tunes/tune_definition.desc new file mode 100644 index 0000000000..7fb757d46f --- /dev/null +++ b/src/lib/tunes/tune_definition.desc @@ -0,0 +1,108 @@ +/**************************************************************************** + * + * Copyright (c) 2018 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * Driver for the PX4 audio . + * + * The tune_control supports a set of predefined "alarm" tunes and + * one user-supplied tune. + * + * Tunes follow the syntax of the Microsoft GWBasic/QBasic PLAY + * statement, with some exceptions and extensions. + * + * From Wikibooks: + * + * PLAY "[string expression]" + * + * Used to play notes and a score ... The tones are indicated by letters A through G. + * Accidentals are indicated with a "+" or "#" (for sharp) or "-" (for flat) + * immediately after the note letter. See this example: + * + * PLAY "C C# C C#" + * + * Whitespaces are ignored inside the string expression. There are also codes that + * set the duration, octave and tempo. They are all case-insensitive. PLAY executes + * the commands or notes the order in which they appear in the string. Any indicators + * that change the properties are effective for the notes following that indicator. + * + * Ln Sets the duration (length) of the notes. The variable n does not indicate an actual duration + * amount but rather a note type; L1 - whole note, L2 - half note, L4 - quarter note, etc. + * (L8, L16, L32, L64, ...). By default, n = 4. + * For triplets and quintets, use L3, L6, L12, ... and L5, L10, L20, ... series respectively. + * The shorthand notation of length is also provided for a note. For example, "L4 CDE L8 FG L4 AB" + * can be shortened to "L4 CDE F8G8 AB". F and G play as eighth notes while others play as quarter notes. + * On Sets the current octave. Valid values for n are 0 through 6. An octave begins with C and ends with B. + * Remember that C- is equivalent to B. + * < > Changes the current octave respectively down or up one level. + * Nn Plays a specified note in the seven-octave range. Valid values are from 0 to 84. (0 is a pause.) + * Cannot use with sharp and flat. Cannot use with the shorthand notation neither. + * MN Stand for Music Normal. Note duration is 7/8ths of the length indicated by Ln. It is the default mode. + * ML Stand for Music Legato. Note duration is full length of that indicated by Ln. + * MS Stand for Music Staccato. Note duration is 3/4ths of the length indicated by Ln. + * Pn Causes a silence (pause) for the length of note indicated (same as Ln). + * Tn Sets the number of "L4"s per minute (tempo). Valid values are from 32 to 255. The default value is T120. + * . When placed after a note, it causes the duration of the note to be 3/2 of the set duration. + * This is how to get "dotted" notes. "L4 C#." would play C sharp as a dotted quarter note. + * It can be used for a pause as well. + * + * Extensions/variations: + * + * MB MF The MF command causes the tune to play once and then stop. The MB command causes the + * tune to repeat when it ends. + * + */ + + +// ordinal name tune interruptable* hint +// * Repeated tunes should always be defined as interruptable, if not an explict 'tone_control stop' is needed +PX4_DEFINE_TUNE(0, CUSTOM, "", true /* empty to align with the index */) +PX4_DEFINE_TUNE(1, STARTUP, "MFT240L8 O4aO5dc O4aO5dc O4aO5dc L16dcdcdcdc", true /* startup tune */) +PX4_DEFINE_TUNE(2, ERROR_TUNE, "MBT200a8a8a8PaaaP", true /* ERROR tone */) +PX4_DEFINE_TUNE(3, NOTIFY_POSITIVE, "MFT200e8a8a", true /* Notify Positive tone */) +PX4_DEFINE_TUNE(4, NOTIFY_NEUTRAL, "MFT200e8e", true /* Notify Neutral tone */) +PX4_DEFINE_TUNE(5, NOTIFY_NEGATIVE, "MFT200e8c8e8c8e8c8", true /* Notify Negative tone */) +PX4_DEFINE_TUNE(6, ARMING_WARNING, "MNT75L1O2G", false /* arming warning */) +PX4_DEFINE_TUNE(7, BATTERY_WARNING_SLOW, "MBNT100a8", true /* battery warning slow */) +PX4_DEFINE_TUNE(8, BATTERY_WARNING_FAST, "MBNT255a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8", true /* battery warning fast */) +PX4_DEFINE_TUNE(9, GPS_WARNING, "MFT255L4AAAL1F#", false /* gps warning slow */) +PX4_DEFINE_TUNE(10, ARMING_FAILURE, "MFT255L4<<G#6A#6B#4", false /* home set tune */) +PX4_DEFINE_TUNE(16, SD_INIT, "MBAGP", false /* Make FS */) +PX4_DEFINE_TUNE(17, SD_ERROR, "MNBG", false /* format failed */) +PX4_DEFINE_TUNE(18, PROG_PX4IO, "MLL32CP8MB", false /* Program PX4IO */) +PX4_DEFINE_TUNE(19, PROG_PX4IO_OK, "MLL8CDE", false /* Program PX4IO success */) +PX4_DEFINE_TUNE(20, PROG_PX4IO_ERR, "ML<(TuneID::STARTUP) || - tune_control.tune_id == static_cast(TuneID::ERROR_TUNE) || - tune_control.tune_id == static_cast(TuneID::NOTIFY_POSITIVE) || - tune_control.tune_id == static_cast(TuneID::NOTIFY_NEUTRAL) || - tune_control.tune_id == static_cast(TuneID::NOTIFY_NEGATIVE)) { + _default_tunes_interruptable[_current_tune_id]) { // Reset repeat flag. Can jump to true again while tune is being parsed later _repeat = false; @@ -116,6 +111,7 @@ int Tunes::set_control(const tune_control_s &tune_control) _strength = TUNE_MAX_STRENGTH; } + // Special treatment for custom tunes if (tune_control.tune_id == static_cast(TuneID::CUSTOM)) { _using_custom_msg = true; @@ -126,9 +122,11 @@ int Tunes::set_control(const tune_control_s &tune_control) } else { _using_custom_msg = false; _tune = _default_tunes[tune_control.tune_id]; - _tune_start_ptr = _default_tunes[tune_control.tune_id]; + _tune_start_ptr = _tune; _next = _tune; } + + _current_tune_id = tune_control.tune_id; } return OK; @@ -171,7 +169,7 @@ int Tunes::get_next_tune(unsigned &frequency, unsigned &duration, int Tunes::get_next_tune(unsigned &frequency, unsigned &duration, unsigned &silence) { - // Return the vaules for frequency and duration if the custom msg was received + // Return the values for frequency and duration if the custom msg was received if (_using_custom_msg) { _using_custom_msg = false; frequency = _frequency; diff --git a/src/lib/tunes/tunes.h b/src/lib/tunes/tunes.h index 105ee572db..ed9eb4c0f6 100644 --- a/src/lib/tunes/tunes.h +++ b/src/lib/tunes/tunes.h @@ -127,8 +127,10 @@ public: private: static const char *const _default_tunes[]; + static const bool _default_tunes_interruptable[]; static const uint8_t _note_tab[]; static const unsigned int _default_tunes_size; + int _current_tune_id = static_cast(TuneID::NONE); bool _repeat = false; ///< if true, tune restarts at end const char *_tune = nullptr; ///< current tune string const char *_next = nullptr; ///< next note in the string diff --git a/src/systemcmds/tune_control/tune_control.cpp b/src/systemcmds/tune_control/tune_control.cpp index cb1e8b156e..d79da8bfe0 100644 --- a/src/systemcmds/tune_control/tune_control.cpp +++ b/src/systemcmds/tune_control/tune_control.cpp @@ -81,7 +81,8 @@ static void publish_tune_control(tune_control_s &tune_control) tune_control.timestamp = hrt_absolute_time(); if (tune_control_pub == nullptr) { - tune_control_pub = orb_advertise(ORB_ID(tune_control), &tune_control); + // We have a minimum of 3 so that tune, stop, tune will fit + tune_control_pub = orb_advertise_queue(ORB_ID(tune_control), &tune_control, 3); } else { orb_publish(ORB_ID(tune_control), tune_control_pub, &tune_control); @@ -233,6 +234,9 @@ tune_control_main(int argc, char *argv[]) tune_control.silence = 0; tune_control.tune_override = true; publish_tune_control(tune_control); + // We wait the maximum update interval to ensure + // The stop will not be overwritten + usleep(tunes.get_maximum_update_interval()); } else { usage();