diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 2f8bfed5..ed185585 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -143,6 +143,7 @@ add_example (ecezo) add_example (mb704x) add_example (mcp2515) add_example (max30100) +add_example (speaker) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/speaker.c b/examples/c/speaker.c new file mode 100644 index 00000000..e9dde8b7 --- /dev/null +++ b/examples/c/speaker.c @@ -0,0 +1,55 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * 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 +#include +#include "speaker.h" + +int main () +{ +//! [Interesting] + + // Instantiate a Speaker on digital pin D2 + speaker_context speaker = speaker_init(2); + + if (!speaker) + { + printf("speaker_init() failed\n"); + return 1; + } + + // Play all 7 of the lowest notes + speaker_play_all(speaker); + + // Play a medium C-sharp + speaker_play_sound(speaker, 'c', true, "med"); + + printf("Exiting\n"); + + speaker_close(speaker); + +//! [Interesting] + + return 0; +} diff --git a/src/speaker/CMakeLists.txt b/src/speaker/CMakeLists.txt index 8b68ffbb..7f52c96e 100644 --- a/src/speaker/CMakeLists.txt +++ b/src/speaker/CMakeLists.txt @@ -1,5 +1,9 @@ upm_mixed_module_init (NAME speaker - DESCRIPTION "UPM speaker module" + DESCRIPTION "Speaker module" + C_HDR speaker.h + C_SRC speaker.c CPP_HDR speaker.hpp CPP_SRC speaker.cxx - REQUIRES mraa) +# FTI_SRC speaker_fti.c + CPP_WRAPS_C + REQUIRES upmc-utilities mraa) diff --git a/src/speaker/speaker.c b/src/speaker/speaker.c new file mode 100644 index 00000000..f2643d10 --- /dev/null +++ b/src/speaker/speaker.c @@ -0,0 +1,217 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Based on original C++ driver by: + * Author: Zion Orent + * Copyright (c) 2014 Intel Corporation. + * + * The MIT License + * + * 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 +#include +#include +#include + +#include +#include + +#include "speaker.h" + +typedef struct +{ + int delayTimeLow; + int delayTimeLowSharp; + int delayTimeMed; + int delayTimeMedSharp; + int delayTimeHigh; + int delayTimeHighSharp; +} noteData_t; + +// keep this synchronized with the switch statement in play_sound() +static noteData_t note_list[7] = { // index, note + { 1136, 1073, 568, 536, 284, 268 }, // 0, a + { 1012, 0, 506, 0, 253, 0 }, // 1, b + { 1911, 1804, 956, 902, 478, 451 }, // 2, c + { 1703, 1607, 851, 804, 426, 402 }, // 3, d + { 1517, 0, 758, 0, 379, 0 }, // 4, e + { 1432, 1351, 716, 676, 358, 338 }, // 5, f + { 1276, 1204, 638, 602, 319, 301 } // 6, g +}; + +// forward decl +static void speaker_sound(const speaker_context dev, int note_delay); + +speaker_context speaker_init(int pin) +{ + // make sure MRAA is initialized + int mraa_rv; + if ((mraa_rv = mraa_init()) != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv); + return NULL; + } + + speaker_context dev = + (speaker_context)malloc(sizeof(struct _speaker_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _speaker_context)); + + if (!(dev->gpio = mraa_gpio_init(pin))) + { + printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__); + speaker_close(dev); + return NULL; + } + +#if defined(UPM_PLATFORM_LINUX) + // Would prefer, but not fatal if not available + mraa_gpio_use_mmaped(dev->gpio, 1); +#endif // UPM_PLATFORM_LINUX + + mraa_gpio_dir(dev->gpio, MRAA_GPIO_OUT); + + return dev; +} + +void speaker_close(speaker_context dev) +{ + assert(dev != NULL); + + if (dev->gpio) + mraa_gpio_close(dev->gpio); + + free(dev); +} + +void speaker_play_all(const speaker_context dev) +{ + assert(dev != NULL); + + speaker_play_sound(dev, 'c', false, "low"); + upm_delay_us(200000); + speaker_play_sound(dev, 'd', false, "low"); + upm_delay_us(200000); + speaker_play_sound(dev, 'e', false, "low"); + upm_delay_us(200000); + speaker_play_sound(dev, 'f', false, "low"); + upm_delay_us(200000); + speaker_play_sound(dev, 'g', false, "low"); + upm_delay_us(500000); + speaker_play_sound(dev, 'a', false, "low"); + upm_delay_us(500000); + speaker_play_sound(dev, 'b', false, "low"); + upm_delay_us(500000); +} + +void speaker_play_sound(const speaker_context dev, char letter, bool sharp, + const char *vocal_weight) +{ + assert(dev != NULL); + + int index = 0; + switch (letter) + { + case 'a': + index = 0; + break; + case 'b': + index = 1; + break; + case 'c': + index = 2; + break; + case 'd': + index = 3; + break; + case 'e': + index = 4; + break; + case 'f': + index = 5; + break; + case 'g': + index = 6; + break; + default: + printf("%s: The note '%c' is invalid.\n", __FUNCTION__, letter); + return; + } + + int delayTime = 0; + bool valid = true; + if (sharp) + { + if (strstr(vocal_weight, "low")) + delayTime = note_list[index].delayTimeLowSharp; + else if (strstr(vocal_weight, "med")) + delayTime = note_list[index].delayTimeMedSharp; + else if (strstr(vocal_weight, "high")) + delayTime = note_list[index].delayTimeHighSharp; + else + valid = false; + } + else + { + if (strstr(vocal_weight, "low")) + delayTime = note_list[index].delayTimeLow; + else if (strstr(vocal_weight, "med")) + delayTime = note_list[index].delayTimeMed; + else if (strstr(vocal_weight, "high")) + delayTime = note_list[index].delayTimeHigh; + else + valid = false; + } + + if (!valid) + printf("%s: Correct voice weight values are low, med, or high.\n", + __FUNCTION__); + + // If delayTime is zero, that means you tried to choose a sharp note + // for a note that has no sharp + if (sharp && !delayTime) + { + printf("%s: the key '%c' doesn't have a sharp note.\n", + __FUNCTION__, letter); + return; + } + + speaker_sound(dev, delayTime); +} + +static void speaker_sound(const speaker_context dev, int note_delay) +{ + assert(dev != NULL); + + for (int i=0; i<100; i++) + { + mraa_gpio_write (dev->gpio, 1); + upm_delay_us(note_delay); + mraa_gpio_write (dev->gpio, 0); + upm_delay_us(note_delay); + } +} diff --git a/src/speaker/speaker.cxx b/src/speaker/speaker.cxx index 35d81881..e3bbebc9 100644 --- a/src/speaker/speaker.cxx +++ b/src/speaker/speaker.cxx @@ -1,4 +1,8 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Based on original C++ driver by: * Author: Zion Orent * Copyright (c) 2014 Intel Corporation. * @@ -30,121 +34,26 @@ using namespace upm; -Speaker::Speaker(int pin) +Speaker::Speaker(int pin) : + m_speaker(speaker_init(pin)) { - if ( !(m_gpio = mraa_gpio_init(pin)) ) - throw std::invalid_argument(std::string(__FUNCTION__) + - ": mraa_gpio_init() failed, invalid pin?"); - - mraa_gpio_dir(m_gpio, MRAA_GPIO_OUT); - m_note_list['a'] = storeNote(1136, 1073, 568, 536, 284, 268); - m_note_list['b'] = storeNote(1012, 0, 506, 0, 253, 0); - m_note_list['c'] = storeNote(1911, 1804, 956, 902, 478, 451); - m_note_list['d'] = storeNote(1703, 1607, 851, 804, 426, 402); - m_note_list['e'] = storeNote(1517, 0, 758, 0, 379, 0); - m_note_list['f'] = storeNote(1432, 1351, 716, 676, 358, 338); - m_note_list['g'] = storeNote(1276, 1204, 638, 602, 319, 301); + if (!m_speaker) + throw std::runtime_error(std::string(__FUNCTION__) + + ": speaker_init() failed."); } Speaker::~Speaker() { - mraa_gpio_close(m_gpio); -} - -NoteData Speaker::storeNote(int noteDelayLow, int noteDelayLowSharp, - int noteDelayMed, int noteDelayMedSharp, - int noteDelayHigh, int noteDelayHighSharp) -{ - NoteData note; - note.delayTimeLow = noteDelayLow; - note.delayTimeLowSharp = noteDelayLowSharp; - note.delayTimeMed = noteDelayMed; - note.delayTimeMedSharp = noteDelayMedSharp; - note.delayTimeHigh = noteDelayHigh; - note.delayTimeHighSharp = noteDelayHighSharp; - return note; + speaker_close(m_speaker); } void Speaker::playAll() { - playSound('c', false, "low"); - usleep(200000); - playSound('d', false, "low"); - usleep(200000); - playSound('e', false, "low"); - usleep(200000); - playSound('f', false, "low"); - usleep(200000); - playSound('g', false, "low"); - usleep(500000); - playSound('a', false, "low"); - usleep(500000); - playSound('b', false, "low"); - usleep(500000); + speaker_play_all(m_speaker); } void Speaker::playSound(char letter, bool sharp, std::string vocalWeight) { - std::map::iterator it = m_note_list.find(letter); - if(it == m_note_list.end()) - { - std::cout << "The key " << letter << " doesn't exist." << std::endl; - return; - } - NoteData nd = it->second; - int delayTime; - if (sharp) - { - if (vocalWeight.compare("low") == 0) - delayTime = nd.delayTimeLowSharp; - else if (vocalWeight.compare("med") == 0) - delayTime = nd.delayTimeMedSharp; - else if (vocalWeight.compare("high") == 0) - delayTime = nd.delayTimeHighSharp; - else - { - std::cout << "Correct voice weight values are low, med, or high" - << std::endl; - return; - } - } - else - { - if (vocalWeight.compare("low") == 0) - delayTime = nd.delayTimeLow; - else if (vocalWeight.compare("med") == 0) - delayTime = nd.delayTimeMed; - else if (vocalWeight.compare("high") == 0) - delayTime = nd.delayTimeHigh; - else - { - std::cout << "Correct voice weight values are low, med, or high" - << std::endl; - return; - } - } - // If delayTime is zero, that means you tried to choose a sharp note - // for a note that has no sharp - if (sharp && !delayTime) - { - std::cout << "The key " << letter << " doesn't have a sharp note." - << std::endl; - return; - } - sound(delayTime); -} - -void Speaker::sound(int note_delay) -{ - mraa_result_t error = MRAA_SUCCESS; - for (int i = 0; i < 100; i++) - { - error = mraa_gpio_write (m_gpio, HIGH); - usleep(note_delay); - error = mraa_gpio_write (m_gpio, LOW); - usleep(note_delay); - } - if (error != MRAA_SUCCESS) - mraa_result_print(error); + speaker_play_sound(m_speaker, letter, sharp, vocalWeight.c_str()); } diff --git a/src/speaker/speaker.h b/src/speaker/speaker.h new file mode 100644 index 00000000..17f7cc7b --- /dev/null +++ b/src/speaker/speaker.h @@ -0,0 +1,93 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Based on original C++ driver by: + * Author: Zion Orent + * Copyright (c) 2014 Intel Corporation. + * + * The MIT License + * + * 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. + */ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file speaker.h + * @library speaker + * @brief C API for the Speaker + * + * @include speaker.c + */ + + /** + * Device context + */ + typedef struct _speaker_context { + mraa_gpio_context gpio; + + } *speaker_context; + + /** + * Speaker GPIO init + * + * @param pin Digital pin to use + */ + speaker_context speaker_init(int pin); + + /** + * Speaker close function + * + * @param dev Device context + */ + void speaker_close(speaker_context dev); + + /** + * Plays all alto notes (lowest notes) + * + * @param dev Device context + */ + void speaker_play_all(const speaker_context dev); + + /** + * Plays a sound and a note whether it's sharp or not + * + * @param dev Device context + * @param letter Character name of the note + * ('a', 'b', 'c', 'd', 'e', 'f', or 'g') + * @param sharp If true, plays a sharp version of the note; + * otherwise, does not play the note + * @param vocalWeight String to determine whether to play a low ("low"), + * a medium ("med"), or a high ("high") note + */ + void speaker_play_sound(const speaker_context dev, char letter, bool sharp, + const char *vocal_weight); + +#ifdef __cplusplus +} +#endif diff --git a/src/speaker/speaker.hpp b/src/speaker/speaker.hpp index b00cfe3c..b666dacf 100644 --- a/src/speaker/speaker.hpp +++ b/src/speaker/speaker.hpp @@ -1,4 +1,8 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Based on original C++ driver by: * Author: Zion Orent * Copyright (c) 2014 Intel Corporation. * @@ -24,84 +28,70 @@ #pragma once #include -#include -#include -#include -#define HIGH 1 -#define LOW 0 +#include "speaker.h" namespace upm { -typedef struct -{ - int delayTimeLow; - int delayTimeLowSharp; - int delayTimeMed; - int delayTimeMedSharp; - int delayTimeHigh; - int delayTimeHighSharp; -} NoteData; + /** + * @brief Speaker library + * @defgroup speaker libupm-speaker + * @ingroup seeed gpio sound hak + */ - /** - * @brief Speaker library - * @defgroup speaker libupm-speaker - * @ingroup seeed gpio sound hak - */ + /** + * @library speaker + * @sensor speaker libupm-speaker + * @comname Speaker + * @altname Grove Speaker + * @type sound + * @man seeed + * @con gpio + * @kit hak + * + * @brief API for the Speaker + * + * UPM module for the Speaker. + * This sensor can generate different tones and sounds depending on the + * frequency of the input signal. + * + * @image html speaker.jpg + * @snippet speaker.cxx Interesting + */ + class Speaker { + public: + /** + * Speaker constructor + * + * @param pin Digital pin to use + */ + Speaker(int pin); - /** - * @library speaker - * @sensor speaker libupm-speaker - * @comname Speaker - * @altname Grove Speaker - * @type sound - * @man seeed - * @con gpio - * @kit hak - * - * @brief API for the Speaker - * - * UPM module for the Speaker. - * This sensor can generate different tones and sounds depending on the - * frequency of the input signal. - * - * @image html speaker.jpg - * @snippet speaker.cxx Interesting - */ - class Speaker { - public: - /** - * Speaker constructor - * - * @param pin Digital pin to use - */ - Speaker(int pin); - /** - * Speaker destructor - */ - ~Speaker(); - /** - * Plays all alto notes (lowest notes) - * - */ - void playAll(); - /** - * Plays a sound and a note whether it's sharp or not - * - * @param letter Character name of the note - * ('a', 'b', 'c', 'd', 'e', 'f', or 'g') - * @param sharp If true, plays a sharp version of the note; otherwise, does not play the note - * @param vocalWeight String to determine whether to play a low ("low"), - * a medium ("med"), or a high ("high") note - */ - void playSound(char letter, bool sharp, std::string vocalWeight); + /** + * Speaker destructor + */ + ~Speaker(); + /** + * Plays all alto notes (lowest notes) + * + */ - private: - mraa_gpio_context m_gpio; - std::map m_note_list; - void sound(int note_delay); - NoteData storeNote(int noteDelayLow, int noteDelayLowSharp, - int noteDelayMed, int noteDelayMedSharp, - int noteDelayHigh, int noteDelayHighSharp); - }; + void playAll(); + /** + * Plays a sound and a note whether it's sharp or not + * + * @param letter Character name of the note + * ('a', 'b', 'c', 'd', 'e', 'f', or 'g') + * @param sharp If true, plays a sharp version of the note; + * otherwise, does not play the note + * @param vocalWeight String to determine whether to play a + * low ("low"), a medium ("med"), or a high ("high") note + */ + void playSound(char letter, bool sharp, std::string vocalWeight); + + protected: + speaker_context m_speaker; + + private: + }; }