lpd8806: Added new module - digital led strip (NOT TESTED)
[contrib/upm.git] / src / lpd8806 / lpd8806.cxx
1 /*
2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <iostream>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <cstring>
29
30 #include "lpd8806.h"
31
32 using namespace upm;
33
34 struct LPD8806Exception : public std::exception {
35     std::string message;
36     LPD8806Exception (std::string msg) : message (msg) { }
37     ~LPD8806Exception () throw () { }
38     const char* what() const throw () { return message.c_str(); }
39 };
40
41 LPD8806::LPD8806 (uint16_t pixelCount, uint8_t csn) {
42     mraa_result_t error = MRAA_SUCCESS;
43     m_name = "LPD8806";
44
45     m_pixels = NULL;
46
47     m_csnPinCtx = mraa_gpio_init (csn);
48     if (m_csnPinCtx == NULL) {
49         throw LPD8806Exception ("GPIO failed to initilize");
50     }
51
52     error = mraa_gpio_dir (m_csnPinCtx, MRAA_GPIO_OUT);
53     if (error != MRAA_SUCCESS) {
54         throw LPD8806Exception ("GPIO failed to initilize");
55     }
56
57     CSOff ();
58
59     m_spi = mraa_spi_init (0);
60     if (m_spi == NULL) {
61         throw LPD8806Exception ("SPI failed to initilize");
62     }
63
64     // set spi mode to mode2 (CPOL = 0, CPHA = 0)
65     mraa_spi_mode (m_spi, MRAA_SPI_MODE0);
66
67     CSOn ();
68     // issue initial latch/reset to strip:
69     for (uint16_t i = ((pixelCount + 31) / 32); i > 0; i--) {
70         mraa_spi_write (m_spi, 0);
71     }
72     CSOff ();
73
74     m_pixelsCount = pixelCount;
75
76     uint8_t  latchBytes;
77     uint16_t dataBytes, totalBytes;
78     uint16_t numBytes = 0;
79
80     dataBytes  = m_pixelsCount * 3;
81     latchBytes = (m_pixelsCount + 31) / 32;
82     totalBytes = dataBytes + latchBytes;
83     if ((m_pixels = (uint8_t *) malloc(totalBytes))) {
84         numBytes = totalBytes;
85         memset ( m_pixels           , 0x80, dataBytes);  // Init to RGB 'off' state
86         memset (&m_pixels[dataBytes], 0   , latchBytes); // Clear latch bytes
87     }
88 }
89
90 LPD8806::~LPD8806() {
91     mraa_result_t error = MRAA_SUCCESS;
92
93     if (m_pixels) {
94         free(m_pixels);
95     }
96     
97     error = mraa_spi_stop(m_spi);
98     if (error != MRAA_SUCCESS) {
99         mraa_result_print(error);
100     }
101     error = mraa_gpio_close (m_csnPinCtx);
102     if (error != MRAA_SUCCESS) {
103         mraa_result_print(error);
104     }
105 }
106
107 void
108 LPD8806::setPixelColor (uint16_t pixelOffset, uint8_t r, uint8_t g, uint8_t b) {
109     if (pixelOffset < m_pixelsCount) { // Arrays are 0-indexed, thus NOT '<='
110         uint8_t *ptr = &m_pixels[pixelOffset * 3];
111         *ptr++ = g | 0x80; // Strip color order is GRB,
112         *ptr++ = r | 0x80; // not the more common RGB,
113         *ptr++ = b | 0x80; // so the order here is intentional; don't "fix"
114     }
115 }
116
117 void
118 LPD8806::show (void) {
119     uint8_t  *ptr   = m_pixels;
120     uint16_t byte   = (m_pixelsCount * 3) + ((m_pixelsCount + 31) / 32);
121     
122     while (byte--) {
123         mraa_spi_write (m_spi, *ptr++);
124     }
125 }
126
127 uint16_t
128 LPD8806::getStripLength (void) {
129     return m_pixelsCount;
130 }
131
132 /*
133  * **************
134  *  private area
135  * **************
136  */
137
138 mraa_result_t
139 LPD8806::CSOn () {
140     return mraa_gpio_write (m_csnPinCtx, HIGH);
141 }
142
143 mraa_result_t
144 LPD8806::CSOff () {
145     return mraa_gpio_write (m_csnPinCtx, LOW);
146 }