diff --git a/examples/c++/grovecircularled.cxx b/examples/c++/grovecircularled.cxx index 72031d56..066e017b 100644 --- a/examples/c++/grovecircularled.cxx +++ b/examples/c++/grovecircularled.cxx @@ -43,9 +43,9 @@ int main() //! [Interesting] - // Instantiate a Grove Circular LED on gpio pins 5 and 4 + // Instantiate a Grove Circular LED on D9 for data, D8 for clock - upm::GroveCircularLED *circle = new upm::GroveCircularLED(5, 4); + upm::GroveCircularLED *circle = new upm::GroveCircularLED(9, 8); int level = 0; while (shouldRun) @@ -54,6 +54,7 @@ int main() level = (level + 1) % 24; usleep(100000); } + //! [Interesting] cout << "Exiting" << endl; diff --git a/examples/c++/my9221-ledbar.cxx b/examples/c++/my9221-ledbar.cxx index dc4ce937..090a8fe0 100644 --- a/examples/c++/my9221-ledbar.cxx +++ b/examples/c++/my9221-ledbar.cxx @@ -27,37 +27,36 @@ #include "my9221.h" #include -int running = 0; +int shouldRun = true; -void -sig_handler(int signo) +void sig_handler(int signo) { - printf("got signal\n"); - if (signo == SIGINT) { - printf("exiting application\n"); - running = 1; - } + if (signo == SIGINT) + shouldRun = false; } -int -main(int argc, char **argv) +int main(int argc, char **argv) { - //! [Interesting] - upm::MY9221 *bar = new upm::MY9221(8, 9); + signal(SIGINT, sig_handler); - signal(SIGINT, sig_handler); + //! [Interesting] + upm::MY9221 *bar = new upm::MY9221(8, 9); - while (!running) { - for (int idx = 1; idx < 11; idx++) { - bar->setBarLevel (idx); - usleep(1000); + // Green to Red + bar->setBarDirection(true); + while (shouldRun) + { + for (int i = 0; i < 11; i++) + { + bar->setBarLevel(i); + usleep(250000); } } - //! [Interesting] + //! [Interesting] - std::cout << "exiting application" << std::endl; + std::cout << "Existing..." << std::endl; - delete bar; + delete bar; - return 0; + return 0; } diff --git a/examples/c++/my9221-updown.cxx b/examples/c++/my9221-updown.cxx index a478e01b..4bcda361 100644 --- a/examples/c++/my9221-updown.cxx +++ b/examples/c++/my9221-updown.cxx @@ -25,7 +25,7 @@ #include #include #include -#include "my9221.h" +#include "groveledbar.h" using namespace std; @@ -44,26 +44,25 @@ int main () //! [Interesting] - // Instantiate a MY9221, we use D2 for the data, and D3 for the - // data clock. This was tested with a Grove LED bar. - - upm::MY9221* bar = new upm::MY9221(2, 3); + // Instantiate a GroveLEDBar, we use D8 for the data, and D9 for the + // clock. This was tested with a Grove LED bar. + upm::GroveLEDBar* bar = new upm::GroveLEDBar(8, 9); while (shouldRun) { // count up from green to red - for (int i=1; i<=10; i++) + for (int i=0; i<=10; i++) { bar->setBarLevel(i, true); - usleep(50000); + usleep(100000); } sleep(1); // count down from red to green - for (int i=1; i<=10; i++) + for (int i=0; i<=10; i++) { bar->setBarLevel(i, false); - usleep(50000); + usleep(100000); } sleep(1); } @@ -71,7 +70,7 @@ int main () cout << "Exiting..." << endl; // turn off the LED's - bar->setBarLevel(0, true); + bar->setBarLevel(0); delete bar; return 0; diff --git a/src/my9221/CMakeLists.txt b/src/my9221/CMakeLists.txt index 714fe861..dbf8ba68 100644 --- a/src/my9221/CMakeLists.txt +++ b/src/my9221/CMakeLists.txt @@ -1,5 +1,5 @@ set (libname "my9221") -set (libdescription "upm ledbar") -set (module_src ${libname}.cxx) -set (module_h ${libname}.h) +set (libdescription "upm my9221") +set (module_src ${libname}.cxx groveledbar.cxx grovecircularled.cxx) +set (module_h ${libname}.h groveledbar.h grovecircularled.h) upm_module_init() diff --git a/src/my9221/TODO b/src/my9221/TODO new file mode 100644 index 00000000..5ad078fb --- /dev/null +++ b/src/my9221/TODO @@ -0,0 +1,14 @@ +- split up bar and circular methods from my9221 into own libraries + +- add a getLED to match setLED + +- for bar, allow spec (via some method) to a specific bar + +- examples for my9221, keep existing ones for bar and circular + +- warning message if mmap gpio fails and more that 1 instance + +- make sure ctor throws exceptions on gpio setup errors, as well as + ensure at least one instance specified. + +- reg map of commandWord bits and provide accessor methods (set/get) diff --git a/src/my9221/grovecircularled.cxx b/src/my9221/grovecircularled.cxx new file mode 100644 index 00000000..7c89cd61 --- /dev/null +++ b/src/my9221/grovecircularled.cxx @@ -0,0 +1,94 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar driver) + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 Intel Corporation. + * + * (grovecircularled driver) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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 +#include +#include + +#include "grovecircularled.h" + +using namespace upm; +using namespace std; + +GroveCircularLED::GroveCircularLED (uint8_t dataPin, uint8_t clockPin) + : MY9221(dataPin, clockPin, 2) +{ + // auto refresh by default + setAutoRefresh(true); + clearAll(); +} + +GroveCircularLED::~GroveCircularLED() +{ +} + +void GroveCircularLED::setSpinner(uint8_t position) +{ + if (position > 23) + position = 23; + + for (uint8_t i=0; i<(LEDS_PER_INSTANCE * m_instances); i++) + m_bitStates[i] = (i == position) ? m_highIntensity : m_lowIntensity; + + if (m_autoRefresh) + refresh(); + + return; +} + +void GroveCircularLED::setLevel(uint8_t level, bool direction) +{ + if (level > 23) + level = 23; + + if (!direction) + { + for (int i=0; i<(LEDS_PER_INSTANCE * m_instances); i++) + m_bitStates[i] = (i < level) ? m_highIntensity : m_lowIntensity; + } + else + { + for (int i=0; i<(LEDS_PER_INSTANCE * m_instances); i++) + m_bitStates[i] = (((LEDS_PER_INSTANCE * m_instances) - i) <= level) + ? m_highIntensity : m_lowIntensity; + } + + if (m_autoRefresh) + refresh(); + + return; +} diff --git a/src/my9221/grovecircularled.h b/src/my9221/grovecircularled.h new file mode 100644 index 00000000..51bc2da1 --- /dev/null +++ b/src/my9221/grovecircularled.h @@ -0,0 +1,96 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar) + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 Intel Corporation. + * + * (grovecircularled) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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. + */ +#pragma once + +#include +#include +#include +#include "my9221.h" + +namespace upm { + + /** + * @library my9221 + * @sensor grovecircularled + * @comname Grove Circular LED + * @type display + * @man seeed + * @web http://www.seeedstudio.com/wiki/Grove_-_Circular_LED + * @con gpio + * + * @brief API for the Grove Circular LED module + * + * This is a circular LED ring based on the MY9221 chip. It is often used + * with a rotary encoder and has 24 controllable LEDs. + * + * @image html grovecircularled.jpg + * @snippet grovecircularled.cxx Interesting + */ + + class GroveCircularLED : public MY9221 { + public: + /** + * Instantiates an GroveCircularLED object + * + * @param dataPin Data pin + * @param clockPin Clock pin + */ + GroveCircularLED(uint8_t dataPin, uint8_t clockPin); + + /** + * GroveCircularLED destructor + */ + ~GroveCircularLED(); + + /** + * Sets the spinner (turns off all LEDs but selected one) + * + * @param position Selected position for the spinner (0-23) + */ + void setSpinner(uint8_t position); + + /** + * Sets the lighting status + * + * @param level Selected level for the circular LED (0-23) + * @param direction Up or down; up is true and default + */ + void setLevel(uint8_t level, bool direction=true); + + protected: + private: + }; + +} diff --git a/src/my9221/groveledbar.cxx b/src/my9221/groveledbar.cxx new file mode 100644 index 00000000..0146a84f --- /dev/null +++ b/src/my9221/groveledbar.cxx @@ -0,0 +1,88 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar driver) + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 Intel Corporation. + * + * (grovecircularled driver) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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 +#include +#include + +#include "groveledbar.h" + +using namespace upm; +using namespace std; + +GroveLEDBar::GroveLEDBar (uint8_t dataPin, uint8_t clockPin, int instances) + : MY9221(dataPin, clockPin, instances) +{ + // auto refresh by default + setAutoRefresh(true); + clearAll(); +} + +GroveLEDBar::~GroveLEDBar() +{ +} + +void GroveLEDBar::setBarLevel(uint8_t level, bool greenToRed, int barNumber) +{ + if (level > 10) + level = 10; + + if (barNumber >= m_instances) + barNumber = m_instances - 1; + + int start = barNumber * LEDS_PER_INSTANCE; + int end = start + LEDS_PER_INSTANCE; + + if (!greenToRed) + { + for (int i=start; i + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar) + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 Intel Corporation. + * + * (grovecircularled) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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. + */ +#pragma once + +#include +#include +#include + +#include "my9221.h" + +namespace upm { + + /** + * @library my9221 + * @sensor groveledbar + * @comname Grove LED Bar + * @altname MY9221 LED Bar + * @type display + * @man seeed + * @web http://www.seeedstudio.com/wiki/Grove_-_LED_Bar + * @con gpio + * @kit eak + * + * @brief API for Grove LED Bars base on the MY9221 + * + * This is a 10-segment LED bar, with 8 green segments, 1 yellow + * segment, and one red segment. They can be daisy chained together + * so that this module can control multiple LED bars. + * + * @image html my9221.jpg + * @snippet groveledbar.cxx Interesting + */ + + class GroveLEDBar : public MY9221 { + public: + + /** + * Instantiates an GroveLEDBar object + * + * @param dataPin Data pin + * @param clockPin Clock pin + * @param instances Number of daisy-chained Grove LED Bars, default 1 + */ + GroveLEDBar(uint8_t dataPin, uint8_t clockPin, int instances=1); + + /** + * GroveLEDBar destructor + */ + ~GroveLEDBar(); + + /** + * Sets the bar level + * + * @param level Selected level for the bar (0 - 10). 0 is off + * @param greenToRed true if you start the level on the first + * green LED, false otherwise + * @param barNumber If you have multiple LED bars chained + * together, this argument selects a specific bar starting at 0. + * The default is 0. + */ + void setBarLevel(uint8_t level, bool greenToRed=true, int barNumber=0); + + protected: + private: + }; + +} diff --git a/src/my9221/my9221.cxx b/src/my9221/my9221.cxx index 81ca508e..a5df3fb5 100644 --- a/src/my9221/my9221.cxx +++ b/src/my9221/my9221.cxx @@ -1,7 +1,18 @@ /* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar driver) * Author: Yevgeniy Kiveisha * Copyright (c) 2014 Intel Corporation. * + * (grovecircularled driver) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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 @@ -31,76 +42,150 @@ #include "my9221.h" using namespace upm; +using namespace std; -MY9221::MY9221 (uint8_t di, uint8_t dcki) - : m_clkPinCtx(dcki), m_dataPinCtx(di) { - mraa::Result error = mraa::SUCCESS; - - // set direction (out) - error = m_clkPinCtx.dir(mraa::DIR_OUT); - if (error != mraa::SUCCESS) { - mraa::printError(error); +MY9221::MY9221 (uint8_t dataPin, uint8_t clockPin, int instances) + : m_gpioData(dataPin), m_gpioClk(clockPin), m_bitStates(0) +{ + if (instances < 1) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": instances must be at least 1"); } - // set direction (out) - error = m_dataPinCtx.dir(mraa::DIR_OUT); - if (error != mraa::SUCCESS) { - mraa::printError(error); - } + // set directions + m_gpioClk.dir(mraa::DIR_OUT); + m_gpioData.dir(mraa::DIR_OUT); + + // we warn if these fail, since it may not be possible to handle + // more than one instance + + if (m_gpioClk.useMmap(true) != mraa::SUCCESS) + cerr << __FUNCTION__ + << ": Warning: mmap of Clk pin failed, correct operation " + << "may be affected." + << endl; + + if (m_gpioData.useMmap(true) != mraa::SUCCESS) + cerr << __FUNCTION__ + << ": Warning: mmap of Data pin failed, correct operation " + << "may be affected." + << endl; + + setLowIntensityValue(0x00); // full off + setHighIntensityValue(0xff); // full brightness + + m_commandWord = 0x0000; // all defaults + m_instances = instances; + + m_bitStates = new uint16_t[instances * LEDS_PER_INSTANCE]; + + setAutoRefresh(true); + clearAll(); } -mraa::Result -MY9221::setBarLevel (uint8_t level, bool direction) { - if (level > 10) { - return mraa::ERROR_INVALID_PARAMETER; - } +MY9221::~MY9221() +{ + clearAll(); - send16bitBlock (CMDMODE); - if (direction) { - level += 3; - for(uint8_t block_idx = 12; block_idx > 0; block_idx--) { - uint32_t state = (block_idx < level) ? BIT_HIGH : BIT_LOW; - send16bitBlock (state); - } - } else { - for(uint8_t block_idx = 0; block_idx < 12; block_idx++) { - uint32_t state = (block_idx < level) ? BIT_HIGH : BIT_LOW; - send16bitBlock (state); + if (!m_autoRefresh) + refresh(); + + delete m_bitStates; +} + +void MY9221::setLED(int led, bool on) +{ + int maxLed = (LEDS_PER_INSTANCE * m_instances) - 1; + + if (led > maxLed) + led = maxLed; + if (led < 0) + led = 0; + + m_bitStates[led] = (on) ? m_highIntensity : m_lowIntensity; + + if (m_autoRefresh) + refresh(); +} + +void MY9221::setLowIntensityValue(int intensity) +{ + m_lowIntensity = (intensity & 0xff); +} + +void MY9221::setHighIntensityValue(int intensity) +{ + m_highIntensity = (intensity & 0xff); +} + +void MY9221::setAll() +{ + for (int i=0; i<(m_instances * LEDS_PER_INSTANCE); i++) + m_bitStates[i] = m_highIntensity; + + if (m_autoRefresh) + refresh(); +} + +void MY9221::clearAll() +{ + for (int i=0; i<(m_instances * LEDS_PER_INSTANCE); i++) + m_bitStates[i] = m_lowIntensity; + + if (m_autoRefresh) + refresh(); +} + +void MY9221::refresh() +{ + for (int i=0; i<(m_instances * LEDS_PER_INSTANCE); i++) + { + if (i % 12 == 0) + { + send16bitBlock(m_commandWord); } + send16bitBlock(m_bitStates[i]); } - return lockData (); + + lockData(); } -mraa::Result -MY9221::lockData () { - mraa::Result error = mraa::SUCCESS; - error = m_dataPinCtx.write(LOW); - usleep(100); +void MY9221::lockData() +{ + m_gpioData.write(0); + usleep(220); - for(int idx = 0; idx < 4; idx++) { - error = m_dataPinCtx.write(HIGH); - error = m_dataPinCtx.write(LOW); + for(int idx = 0; idx < 4; idx++) + { + m_gpioData.write(1); + m_gpioData.write(0); } - return error; + + // in reality, we only need > 200ns + (m_instances * 10ns), so the + // following should be good for up to m_instances < 80), if the + // datasheet is to be believed :) + usleep(1); + + return; } -mraa::Result -MY9221::send16bitBlock (short data) { - mraa::Result error = mraa::SUCCESS; - for (uint8_t bit_idx = 0; bit_idx < MAX_BIT_PER_BLOCK; bit_idx++) { - uint32_t state = (data & 0x8000) ? HIGH : LOW; - error = m_dataPinCtx.write(state); - state = m_clkPinCtx.read(); +void MY9221::send16bitBlock(uint16_t data) +{ + for (uint8_t bit_idx = 0; bit_idx < 16; bit_idx++) + { + uint32_t state = (data & 0x8000) ? 1 : 0; + m_gpioData.write(state); + state = m_gpioClk.read(); - if (state) { - state = LOW; - } else { - state = HIGH; - } - - error = m_clkPinCtx.write(state); - - data <<= 1; + if (state) + state = 0; + else + state = 1; + + m_gpioClk.write(state); + + data <<= 1; } - return error; + return; } diff --git a/src/my9221/my9221.h b/src/my9221/my9221.h index ec18a49b..5eebb392 100644 --- a/src/my9221/my9221.h +++ b/src/my9221/my9221.h @@ -1,7 +1,18 @@ /* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * These modules were rewritten, based on original work by: + * + * (original my9221/groveledbar) * Author: Yevgeniy Kiveisha * Copyright (c) 2014 Intel Corporation. * + * (grovecircularled) + * Author: Jun Kato and Yevgeniy Kiveisha + * Contributions: Jon Trulson + * Copyright (c) 2014 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 @@ -24,77 +35,118 @@ #pragma once #include -#include #include - #include -#define MAX_BIT_PER_BLOCK 16 -#define CMDMODE 0x0000 -#define BIT_HIGH 0x00ff -#define BIT_LOW 0x0000 - -#define HIGH 1 -#define LOW 0 - namespace upm { -/** - * @brief MY9221 LED Bar library - * @defgroup my9221 libupm-my9221 - * @ingroup seeed display gpio eak - */ -/** - * @library my9221 - * @sensor my9221 - * @comname Grove LED Bar - * @altname MY9221 LED Bar - * @type display - * @man seeed - * @web http://www.seeedstudio.com/wiki/Grove_-_LED_Bar - * @con gpio - * @kit eak - * - * @brief API for MY9221-based LED Bars - * - * This module defines the MY9221 interface for libmy9221 - * - * @image html my9221.jpg - * @snippet my9221-ledbar.cxx Interesting - * @snippet my9221-updown.cxx Interesting - */ -class MY9221 { - public: - /** - * Instantiates an MY9221 object - * - * @param di Data pin - * @param dcki Clock pin - */ - MY9221 (uint8_t di, uint8_t dcki); + /** + * @brief MY9221 LED Controller library + * @defgroup my9221 libupm-my9221 + * @ingroup seeed display gpio eak + */ + class MY9221 { + public: - /** - * Sets the bar level - * - * @param level Selected level for the bar (1 - 10) - * @param direction Up or down; up is true and default - */ - mraa::Result setBarLevel (uint8_t level, bool direction=true); + // 12 LED channels per chip (instance) + static const int LEDS_PER_INSTANCE = 12; - /** - * Returns the name of the component - */ - std::string name() - { - return m_name; - } - private: - mraa::Result lockData (); - mraa::Result send16bitBlock (short data); + /** + * Instantiates an MY9221 object + * + * @param dataPin Data pin + * @param clockPin Clock pin + * @param instances Number of daisy-chained my9221s, default 1 + */ + MY9221(uint8_t dataPin, uint8_t clockPin, int instances=1); - std::string m_name; - mraa::Gpio m_clkPinCtx; - mraa::Gpio m_dataPinCtx; -}; + /** + * MY9221 destructor + */ + ~MY9221(); + + /** + * Enable or disable auto refresh. When auto refresh is enabled, + * update the LED display as soon as the internal state changes. + * When false, the display(s) will not be updated until the + * refresh() method is called. + * + * @param enable true to enable auto refresh, false otherwise + */ + void setAutoRefresh(bool enable) + { + m_autoRefresh = enable; + } + + /** + * Set an LED to a specific on (high intensity) or off (low + * intensity) value. + * + * @param led The LED whose state you wish to change + * @param on true to turn on the LED, false to turn the LED off + */ + void setLED(int led, bool on); + + /** + * Set the greyscale intensity of an LED in the OFF state. The + * intensity is a value from 0 (fully off) to 255 (fully on). + * This will take effect on any future LED set or clear + * operations. + * + * @param intensity a value from 0 (fully off) to 255 (fully on) + */ + void setLowIntensityValue(int intensity); + + /** + * Set the greyscale intensity of an LED in the ON state. The + * intensity is a value from 0 (fully off) to 255 (fully on). + * This will take effect on any future LED set or clear + * operations. + * + * @param intensity a value from 0 (fully off) to 255 (fully on) + */ + void setHighIntensityValue(int intensity); + + /** + * Set all of the LEDS to the ON (high intensity value) state. + */ + void setAll(); + + /** + * Set all of the LEDS to the OFF (low intensity value) state. + */ + void clearAll(); + + /** + * Set the LED states to match the internal stored states. This + * is useful when auto refresh (setAutoRefresh()) is false to + * update the display. + */ + void refresh(); + + protected: + virtual void lockData(); + virtual void send16bitBlock(uint16_t data); + + bool m_autoRefresh; + // we're only doing 8-bit greyscale, so the high order bits are + // always 0 + uint16_t m_lowIntensity; + uint16_t m_highIntensity; + + unsigned int m_instances; + + // an array of uint16_t's representing our bit states (on/off) + // intensities. Only the low 8 bits are used, but in the future + // 16bit support can work here as well. + uint16_t *m_bitStates; + + uint16_t m_commandWord; + + mraa::Gpio m_gpioClk; + mraa::Gpio m_gpioData; + + private: + }; }