my9221: rewrite to include new functionality and serve as a base class

This driver has been rewritten to support some new functionality, be
more generic and fix up some old bugs.  Multiple MY9221's can now be
chained together and are supported by the MY9221 base class.

In addition, the Grove LED Bar and Grove Circular LED drivers have
been incoporated into the my9221 library, using the new MY9221 class
as their base class.  Examples have been fixed to work with the new
library, and renamed where needed.

The current grovecircularled driver has been removed as it is now a
part of the my9221 library.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Jon Trulson 2015-12-03 18:21:54 -07:00 committed by Mihai Tudor Panu
parent 71b0791239
commit cbb289438e
11 changed files with 683 additions and 156 deletions

View File

@ -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;

View File

@ -27,35 +27,34 @@
#include "my9221.h"
#include <signal.h>
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)
{
signal(SIGINT, sig_handler);
//! [Interesting]
upm::MY9221 *bar = new upm::MY9221(8, 9);
signal(SIGINT, sig_handler);
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]
std::cout << "exiting application" << std::endl;
std::cout << "Existing..." << std::endl;
delete bar;

View File

@ -25,7 +25,7 @@
#include <unistd.h>
#include <iostream>
#include <signal.h>
#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;

View File

@ -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()

14
src/my9221/TODO Normal file
View File

@ -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)

View File

@ -0,0 +1,94 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar driver)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled driver)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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 <iostream>
#include <string>
#include <stdexcept>
#include <unistd.h>
#include <stdlib.h>
#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;
}

View File

@ -0,0 +1,96 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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 <string>
#include <mraa/common.hpp>
#include <mraa/gpio.hpp>
#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:
};
}

View File

@ -0,0 +1,88 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar driver)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled driver)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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 <iostream>
#include <string>
#include <stdexcept>
#include <unistd.h>
#include <stdlib.h>
#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<end; i++)
m_bitStates[i] = (i < (level + start)) ?
m_highIntensity : m_lowIntensity;
}
else
{
for (int i=start; i<end; i++)
m_bitStates[i] = ( ((start + LEDS_PER_INSTANCE) - i) <=
(level + 2 + start)) ?
m_highIntensity : m_lowIntensity;
}
if (m_autoRefresh)
refresh();
return;
}

99
src/my9221/groveledbar.h Normal file
View File

@ -0,0 +1,99 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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 <string>
#include <mraa/common.hpp>
#include <mraa/gpio.hpp>
#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:
};
}

View File

@ -1,7 +1,18 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar driver)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled driver)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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();
if (!m_autoRefresh)
refresh();
delete m_bitStates;
}
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);
}
}
return lockData ();
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();
}
mraa::Result
MY9221::lockData () {
mraa::Result error = mraa::SUCCESS;
error = m_dataPinCtx.write(LOW);
usleep(100);
for(int idx = 0; idx < 4; idx++) {
error = m_dataPinCtx.write(HIGH);
error = m_dataPinCtx.write(LOW);
}
return error;
void MY9221::setLowIntensityValue(int intensity)
{
m_lowIntensity = (intensity & 0xff);
}
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();
if (state) {
state = LOW;
} else {
state = HIGH;
void MY9221::setHighIntensityValue(int intensity)
{
m_highIntensity = (intensity & 0xff);
}
error = m_clkPinCtx.write(state);
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]);
}
lockData();
}
void MY9221::lockData()
{
m_gpioData.write(0);
usleep(220);
for(int idx = 0; idx < 4; idx++)
{
m_gpioData.write(1);
m_gpioData.write(0);
}
// 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;
}
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 = 0;
else
state = 1;
m_gpioClk.write(state);
data <<= 1;
}
return error;
return;
}

View File

@ -1,7 +1,18 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2016 Intel Corporation.
*
* These modules were rewritten, based on original work by:
*
* (original my9221/groveledbar)
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* (grovecircularled)
* Author: Jun Kato and Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* 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 <string>
#include <mraa/aio.hpp>
#include <mraa/common.hpp>
#include <mraa/gpio.hpp>
#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
* @brief MY9221 LED Controller 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:
// 12 LED channels per chip (instance)
static const int LEDS_PER_INSTANCE = 12;
/**
* Instantiates an MY9221 object
*
* @param di Data pin
* @param dcki Clock pin
* @param dataPin Data pin
* @param clockPin Clock pin
* @param instances Number of daisy-chained my9221s, default 1
*/
MY9221 (uint8_t di, uint8_t dcki);
MY9221(uint8_t dataPin, uint8_t clockPin, int instances=1);
/**
* Sets the bar level
* 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 level Selected level for the bar (1 - 10)
* @param direction Up or down; up is true and default
* @param enable true to enable auto refresh, false otherwise
*/
mraa::Result setBarLevel (uint8_t level, bool direction=true);
void setAutoRefresh(bool enable)
{
m_autoRefresh = enable;
}
/**
* Returns the name of the component
* 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
*/
std::string name()
{
return m_name;
}
private:
mraa::Result lockData ();
mraa::Result send16bitBlock (short data);
void setLED(int led, bool on);
std::string m_name;
mraa::Gpio m_clkPinCtx;
mraa::Gpio m_dataPinCtx;
/**
* 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:
};
}