diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 1063fed3..d7667abf 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -124,6 +124,7 @@ add_executable (ad8232-example ad8232.cxx) add_executable (grovescam-example grovescam.cxx) add_executable (m24lr64e-example m24lr64e.cxx) add_executable (grovecircularled-example grovecircularled.cxx) +add_executable (rgbringcoder-example rgbringcoder.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -226,6 +227,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/ad8232) include_directories (${PROJECT_SOURCE_DIR}/src/grovescam) include_directories (${PROJECT_SOURCE_DIR}/src/m24lr64e) include_directories (${PROJECT_SOURCE_DIR}/src/grovecircularled) +include_directories (${PROJECT_SOURCE_DIR}/src/rgbringcoder) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -351,4 +353,4 @@ target_link_libraries (ad8232-example ad8232 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (grovescam-example grovescam ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (m24lr64e-example m24lr64e ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (grovecircularled-example grovecircularled ${CMAKE_THREAD_LIBS_INIT}) - +target_link_libraries (rgbringcoder-example rgbringcoder ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/c++/rgbringcoder.cxx b/examples/c++/rgbringcoder.cxx new file mode 100644 index 00000000..52644cdc --- /dev/null +++ b/examples/c++/rgbringcoder.cxx @@ -0,0 +1,110 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 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 "rgbringcoder.h" +#include + +using namespace std; + +int shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + + //! [Interesting] + + // There are a lot of pins to hook up. These pins are valid for the + // Edison board, but may need to be adjusted for other platforms. + + // In order: + // enable - 4 + // latch - 10 + // clear - 11 + // clock - 2 + // data - 9 + // switch - 7 + + // red pwm - 3 + // green pwm - 5 + // blue pwm - 6 + + // encA - 12 + // encB - 13 + + upm::RGBRingCoder *ringCoder = + new upm::RGBRingCoder(4, 10, 11, 2, 9, 7, 12, 13, 3, 5, 6); + + uint16_t spin = 0x0001; + bool oldState = false; + int oldPos = 0; + + // Lets go green + ringCoder->setRGBLED(0.99, 0.01, 0.99); + + while (shouldRun) + { + // you spin me round... + if (spin == 0) + spin = 0x0001; + + ringCoder->setRingLEDS(spin); + spin <<= 1; + + // check button state + bool bstate = ringCoder->getButtonState(); + if (bstate != oldState) + { + cout << "Button state changed from " << oldState << " to " + << bstate << endl; + oldState = bstate; + } + + // check encoder position + int epos = ringCoder->getEncoderPosition(); + if (epos != oldPos) + { + cout << "Encoder position changed from " << oldPos << " to " + << epos << endl; + oldPos = epos; + } + + usleep(100000); + } + + //! [Interesting] + + delete ringCoder; + + return 0; +} diff --git a/examples/javascript/rgbringcoder.js b/examples/javascript/rgbringcoder.js new file mode 100644 index 00000000..6fb22761 --- /dev/null +++ b/examples/javascript/rgbringcoder.js @@ -0,0 +1,98 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* + * Author: Jon Trulson + * Copyright (c) 2015 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. + */ + +var ringcoderObj = require('jsupm_rgbringcoder'); + +// There are a lot of pins to hook up. These pins are valid for the +// Edison board, but may need to be adjusted for other platforms. + +// In order: +// enable - 4 +// latch - 10 +// clear - 11 +// clock - 2 +// data - 9 +// switch - 7 + +// red pwm - 3 +// green pwm - 5 +// blue pwm - 6 + +// encA - 12 +// encB - 13 +var ringCoder = new ringcoderObj.RGBRingCoder(4, 10, 11, 2, 9, 7, 12, 13, 3, + 5, 6); + +var spin = 0x0001; +var oldState = false; +var oldPos = 0; + +// Lets go green +ringCoder.setRGBLED(0.99, 0.01, 0.99); + +setInterval(function() +{ + // you spin me round... + if ((spin & 0xffff) == 0) + spin = 0x0001; + + ringCoder.setRingLEDS(spin); + spin <<= 1; + + // check button state + var bstate = ringCoder.getButtonState(); + if (bstate != oldState) + { + console.log("Button state changed from " + oldState + " to " + + bstate); + oldState = bstate; + } + + // check encoder position + var epos = ringCoder.getEncoderPosition(); + if (epos != oldPos) + { + console.log("Encoder position changed from " + oldPos + " to " + + epos); + oldPos = epos; + } +}, 100); + + +// exit on ^C +process.on('SIGINT', function() +{ + ringCoder = null; + ringcoderObj.cleanUp(); + ringcoderObj = null; + console.log("Exiting."); + process.exit(0); +}); + + + + diff --git a/examples/python/rgbringcoder.py b/examples/python/rgbringcoder.py new file mode 100644 index 00000000..5c0b1fb1 --- /dev/null +++ b/examples/python/rgbringcoder.py @@ -0,0 +1,90 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2015 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. + +import time, sys, signal, atexit +import pyupm_rgbringcoder as upmRGBRingCoder + +# There are a lot of pins to hook up. These pins are valid for the +# Edison board, but may need to be adjusted for other platforms. + +# In order: +# enable - 4 +# latch - 10 +# clear - 11 +# clock - 2 +# data - 9 +# switch - 7 + +# red pwm - 3 +# green pwm - 5 +# blue pwm - 6 + +# encA - 12 +# encB - 13 +ringCoder = upmRGBRingCoder.RGBRingCoder(4, 10, 11, 2, 9, 7, 12, 13, 3, + 5, 6) + +## Exit handlers ## +# This stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit, +# including functions from ringCoder +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + + +spin = 0x0001; +oldState = False; +oldPos = 0; + +# Lets go green +ringCoder.setRGBLED(0.99, 0.01, 0.99); + +while(1): + # you spin me round... + if ((spin & 0xffff) == 0): + spin = 0x0001 + + ringCoder.setRingLEDS(spin) + spin <<= 1 + + # check button state + bstate = ringCoder.getButtonState() + if (bstate != oldState): + print "Button state changed from", oldState, " to ", bstate + oldState = bstate + + # check encoder position + epos = ringCoder.getEncoderPosition() + if (epos != oldPos): + print "Encoder position changed from", oldPos, "to", epos + oldPos = epos + + time.sleep(0.1) diff --git a/src/rgbringcoder/CMakeLists.txt b/src/rgbringcoder/CMakeLists.txt new file mode 100644 index 00000000..86d6ee42 --- /dev/null +++ b/src/rgbringcoder/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "rgbringcoder") +set (libdescription "upm Sparkfun RGB RingCoder") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/rgbringcoder/jsupm_rgbringcoder.i b/src/rgbringcoder/jsupm_rgbringcoder.i new file mode 100644 index 00000000..8f4f5f8d --- /dev/null +++ b/src/rgbringcoder/jsupm_rgbringcoder.i @@ -0,0 +1,9 @@ +%module jsupm_rgbringcoder +%include "../upm.i" +%include "stdint.i" + +%{ + #include "rgbringcoder.h" +%} + +%include "rgbringcoder.h" diff --git a/src/rgbringcoder/pyupm_rgbringcoder.i b/src/rgbringcoder/pyupm_rgbringcoder.i new file mode 100644 index 00000000..30a3e71c --- /dev/null +++ b/src/rgbringcoder/pyupm_rgbringcoder.i @@ -0,0 +1,9 @@ +%module pyupm_rgbringcoder +%include "../upm.i" + +%feature("autodoc", "3"); + +%include "rgbringcoder.h" +%{ + #include "rgbringcoder.h" +%} diff --git a/src/rgbringcoder/rgbringcoder.cxx b/src/rgbringcoder/rgbringcoder.cxx new file mode 100644 index 00000000..60372b62 --- /dev/null +++ b/src/rgbringcoder/rgbringcoder.cxx @@ -0,0 +1,187 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 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 "rgbringcoder.h" + +using namespace std; +using namespace upm; + +RGBRingCoder::RGBRingCoder(int en, int latch, int clear, int clk, int dat, + int sw, int encA, int encB, int red, + int green, int blue) : + m_gpioEn(en), m_gpioLatch(latch), m_gpioClear(clear), m_gpioClock(clk), + m_gpioData(dat), m_gpioSwitch(sw), m_gpioEncA(encA), m_gpioEncB(encB), + m_pwmRed(red), m_pwmGreen(green), m_pwmBlue(blue) +{ + m_counter = 0; + + // enable, set LOW + m_gpioEn.dir(mraa::DIR_OUT); + m_gpioEn.write(0); + + // latch + m_gpioLatch.dir(mraa::DIR_OUT); + m_gpioLatch.write(0); + + // clear, HIGH + m_gpioClear.dir(mraa::DIR_OUT); + m_gpioLatch.write(1); + + // clock + m_gpioClock.dir(mraa::DIR_OUT); + m_gpioClock.write(0); + + // data + m_gpioData.dir(mraa::DIR_OUT); + m_gpioData.write(0); + + // switch + m_gpioSwitch.dir(mraa::DIR_IN); + m_gpioSwitch.mode(mraa::MODE_HIZ); // no pullup + m_gpioSwitch.write(0); + + // ecoder A interrupt + m_gpioEncA.dir(mraa::DIR_IN); + m_gpioEncA.mode(mraa::MODE_PULLUP); + // EDGE_BOTH would be nice... + m_gpioEncA.isr(mraa::EDGE_RISING, &interruptHandler, this); + + // ecoder B interrupt + m_gpioEncB.dir(mraa::DIR_IN); + m_gpioEncB.mode(mraa::MODE_PULLUP); + // EDGE_BOTH would be nice... + m_gpioEncB.isr(mraa::EDGE_RISING, &interruptHandler, this); + + // RGB LED pwms, set to off + + // Red led + m_pwmRed.period_ms(1); + m_pwmRed.write(0.99); + m_pwmRed.enable(true); + + // Green led + m_pwmGreen.period_ms(1); + m_pwmGreen.write(0.99); + m_pwmGreen.enable(true); + + // Blue led + m_pwmBlue.period_ms(1); + m_pwmBlue.write(0.99); + m_pwmBlue.enable(true); + + // whew. +} + +RGBRingCoder::~RGBRingCoder() +{ + m_gpioEncA.isrExit(); + m_gpioEncB.isrExit(); + + // turn off the ring + setRingLEDS(0x0000); + + // Turn of RGB LEDS + setRGBLED(0.99, 0.99, 0.99); + usleep(100000); + + // turn off PWM's + m_pwmRed.enable(false); + m_pwmGreen.enable(false); + m_pwmBlue.enable(false); +} + +void RGBRingCoder::interruptHandler(void *ctx) +{ + upm::RGBRingCoder *This = (upm::RGBRingCoder *)ctx; + + // From the Sparkfun guys: + + // enc_states[] is a fancy way to keep track of which direction + // the encoder is turning. 2-bits of oldEncoderState are paired + // with 2-bits of newEncoderState to create 16 possible values. + // Each of the 16 values will produce either a CW turn (1), + // CCW turn (-1) or no movement (0). + + static int8_t enc_states[] = {0, -1, 1, 0, 1, 0, 0, -1, + -1, 0, 0, 1, 0, 1, -1, 0}; + static uint8_t oldEncoderState = 0; + static uint8_t newEncoderState = 0; + + // First, find the newEncoderState. This'll be a 2-bit value + // the msb is the state of the B pin. The lsb is the state + // of the A pin on the encoder. + newEncoderState = (This->m_gpioEncB.read()<<1) | + (This->m_gpioEncA.read()); + + // Now we pair oldEncoderState with new encoder state + // First we need to shift oldEncoder state left two bits. + // This'll put the last state in bits 2 and 3. + + oldEncoderState <<= 2; + + // Mask out everything in oldEncoderState except for the previous state + oldEncoderState &= 0x0c; + + // Now add the newEncoderState. oldEncoderState will now be of + // the form: 0b0000(old B)(old A)(new B)(new A) + oldEncoderState |= newEncoderState; + + // update our counter + This->m_counter += enc_states[oldEncoderState & 0x0f]; +} + +void RGBRingCoder::setRingLEDS(uint16_t bits) +{ + // First we need to set latch LOW + m_gpioLatch.write(0); + + // Now shift out the bits, msb first + for (int i=0; i<16; i++) + { + m_gpioData.write( ((bits & 0x8000) ? 1 : 0) ); + + // pulse the clock pin + m_gpioClock.write(1); + m_gpioClock.write(0); + + bits <<= 1; + } + + // latch it + m_gpioLatch.write(1); +} + +bool RGBRingCoder::getButtonState() +{ + return (m_gpioSwitch.read() ? true : false); +} + +void RGBRingCoder::setRGBLED(float r, float g, float b) +{ + m_pwmRed.write(r); + m_pwmGreen.write(g); + m_pwmBlue.write(b); +} diff --git a/src/rgbringcoder/rgbringcoder.h b/src/rgbringcoder/rgbringcoder.h new file mode 100644 index 00000000..815ffb26 --- /dev/null +++ b/src/rgbringcoder/rgbringcoder.h @@ -0,0 +1,151 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 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 +#include +#include + + +namespace upm { + /** + * @brief Sparkfun RGB RingCoder + * @defgroup rgbringcoder libupm-rgbringcoder + * @ingroup seeed gpio led + */ + + /** + * @library rgbringcoder + * @sensor rgbringcoder + * @comname Sparkfun RGB Ringcoder + * @type led + * @web https://www.sparkfun.com/products/11040 + * @man sparkfun + * @con pwm gpio + * + * @brief API for the Sparkfun RGB Ringcoder + * + * The RGB RingCoder is a breakout board, a circular LED containing + * 16 LEDs arranged in a ring, and a rotary encoder. The encoder + * contains an RGB LED as well as a push button function. + * + * The device will require 11 pins, 3 of which must be PWM capable + * (for the RGB LEDs). + * + * @snippet rgbringcoder.cxx Interesting + */ + + class RGBRingCoder { + public: + + /** + * RGBRingCoder constructor + * + * @param en enable gpio + * @param latch latch gpio + * @param clear clear gpio + * @param clk clock gpio + * @param dat data out gpio + * @param sw push button switch gpio + * @param encA encoder A gpio + * @param encB encoder B gpio + * @param red RGB red led pwm + * @param green RGB green led pwm + * @param blue RGB blue led pwm + */ + RGBRingCoder(int en, int latch, int clear, int clk, int dat, int sw, + int encA, int encB, int red, int green, int blue); + + /** + * RGBRingCoder Destructor + */ + ~RGBRingCoder(); + + /* + * set the state of the ring LEDs. This is a 16 bit value, where + * each bit corresponds to one of the ring LEDs. A 1 bit means + * that specific LED is on, and 0 bit means that specific LED is + * off. + * + * @param bits the bits representing the state of each LED + */ + void setRingLEDS(uint16_t bits); + + /* + * return the state of the button + * + * @return true if the button is pressed, false otherwise + */ + bool getButtonState(); + + /* + * get the current rotary encoder counter value + * + * @return the current counter value + */ + int getEncoderPosition() { return m_counter; }; + + /* + * set the encoder counter to 0 + */ + void clearEncoderPosition() { m_counter = 0; }; + + /* + * set the intensity of the red, grenn, and blue LEDs. Values can + * be between 0.0 and 1.0. Lower is brighter, higher is dimmer. + * + * @param r the red value, valid values are between 0.0 and 1.0 + * @param g the green value, valid values are between 0.0 and 1.0 + * @param b the blue value, valid values are between 0.0 and 1.0 + */ + void setRGBLED(float r, float g, float b); + + private: + + mraa::Gpio m_gpioEn; + + mraa::Gpio m_gpioLatch; + mraa::Gpio m_gpioClear; + mraa::Gpio m_gpioClock; + mraa::Gpio m_gpioData; + + mraa::Gpio m_gpioSwitch; + + mraa::Pwm m_pwmRed; + mraa::Pwm m_pwmGreen; + mraa::Pwm m_pwmBlue; + + mraa::Gpio m_gpioEncA; + mraa::Gpio m_gpioEncB; + + static void interruptHandler(void *ctx); + volatile int m_counter; + + }; +} + +