diff --git a/src/apa102/CMakeLists.txt b/src/apa102/CMakeLists.txt index 27335be2..a2846286 100644 --- a/src/apa102/CMakeLists.txt +++ b/src/apa102/CMakeLists.txt @@ -1,5 +1,8 @@ -set (libname "apa102") -set (libdescription "upm apa102 led strip spi output module") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init() +upm_mixed_module_init (NAME apa102 + DESCRIPTION "UPM driver for DFRobot HKA5 PM2.5 particle sensor" + C_HDR apa102.h + C_SRC apa102.c + CPP_HDR apa102.hpp + CPP_SRC apa102.cxx + FTI_SRC apa102_fti.c + REQUIRES upmc-utilities mraa) \ No newline at end of file diff --git a/src/apa102/apa102.c b/src/apa102/apa102.c new file mode 100644 index 00000000..10967728 --- /dev/null +++ b/src/apa102/apa102.c @@ -0,0 +1,132 @@ +/* + * Author: Mihai Tudor Panu + * Copyright (c) 2016 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 "apa102.h" + +apa102_context apa102_init(int ledcount, int bus, int cs) { + + apa102_context dev = (apa102_context)malloc(sizeof(struct _apa102_context)); + + if(!dev) + return NULL; + + dev->leds = ledcount; + + // Try to allocate and zero out buffer + uint16_t endframelength = (dev->leds + 15) / 16; + dev->framelength = 4 * (1 + dev->leds) + endframelength; + if ((dev->buffer = (uint8_t*)malloc(dev->framelength))) { + memset(dev->buffer, 0x00, dev->framelength - endframelength); + memset(&dev->buffer[dev->framelength - endframelength], 0xFF, endframelength); + int i; + for (i = 1; i <= dev->leds; i++) { + dev->buffer[i * 4] = 224; + } + } else { + printf("%s: Failed to allocate LED buffer.\n", __FUNCTION__); + apa102_close(dev); + return NULL; + } + + dev->spi = NULL; + dev->cs = NULL; + + // Initialize MRAA contexts + if (!(dev->spi = mraa_spi_init(bus))) { + printf("%s: mraa_spi_init(bus) failed.\n", __FUNCTION__); + apa102_close(dev); + return NULL; + } + + if (cs >= 0) { + if (!(dev->cs = mraa_gpio_init(cs))) { + printf("%s: mraa_gpio_init(cs) failed.\n", __FUNCTION__); + apa102_close(dev); + return NULL; + } + mraa_gpio_dir(dev->cs, MRAA_GPIO_OUT); + } +} + +void apa102_close(apa102_context dev) { + assert(dev != NULL); + + if (dev->spi) + mraa_spi_stop(dev->spi); + if (dev->cs) + mraa_gpio_close(dev->cs); + if(dev->buffer) + free(dev->buffer); + free(dev); +} + +upm_result_t apa102_set_led(apa102_context dev, uint16_t index, uint8_t brightness, uint8_t r, uint8_t g, uint8_t b) { + return apa102_set_leds(dev, index, index, brightness, r, g, b); +} + +upm_result_t apa102_set_led_brightness(apa102_context dev, uint16_t index, uint8_t brightness) { + return apa102_set_leds_brightness(dev, index, index, brightness); +} + +upm_result_t apa102_set_leds(apa102_context dev, uint16_t s_index, uint16_t e_index, uint8_t brightness, uint8_t r, uint8_t g, uint8_t b) { + assert(dev != NULL); + int i; + uint16_t s_idx = (s_index + 1) * 4; + uint16_t e_idx = (e_index + 1) * 4; + + for (i = s_idx; i <= e_idx; i += 4) { + dev->buffer[i] = brightness | 224; + dev->buffer[i + 1] = b; + dev->buffer[i + 2] = g; + dev->buffer[i + 3] = r; + } + return UPM_SUCCESS; +} + +upm_result_t apa102_set_leds_brightness(apa102_context dev, uint16_t s_index, uint16_t e_index, uint8_t brightness) { + assert(dev != NULL); + int i; + uint16_t s_idx = (s_index + 1) * 4; + uint16_t e_idx = (e_index + 1) * 4; + + for (i = s_idx; i <= e_idx; i += 4) { + dev->buffer[i] = brightness | 224; + } + return UPM_SUCCESS; +} + +upm_result_t apa102_refresh(apa102_context dev) { + assert(dev != NULL); + if(!dev->cs) { + mraa_spi_write_buf(dev->spi, dev->buffer, dev->framelength); + } else { + mraa_gpio_write(dev->cs, 1); + mraa_spi_write_buf(dev->spi, dev->buffer, dev->framelength); + mraa_gpio_write(dev->cs, 0); + } + return UPM_SUCCESS; +} \ No newline at end of file diff --git a/src/apa102/apa102.h b/src/apa102/apa102.h new file mode 100644 index 00000000..1288bbfd --- /dev/null +++ b/src/apa102/apa102.h @@ -0,0 +1,134 @@ +/* + * Author: Mihai Tudor Panu + * Copyright (c) 2016 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 "upm.h" +#include "mraa/gpio.h" +#include "mraa/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief API for controlling APA102/DotStar RGB LED Strips + * + * APA102 LED Strips provide individually controllable LEDs through a SPI interface. + * For each LED, brightness (0-31) and RGB (0-255) values can be set. + * + * @snippet apa102.c Interesting + */ + +/** + * Device context + */ +typedef struct _apa102_context { + mraa_spi_context spi; + + // optional chip select + mraa_gpio_context cs; + + uint8_t* buffer; + int leds; + int framelength; +} *apa102_context; + + +/** + * Instantiates a new APA102 LED Strip + * + * @param ledcount Number of LEDs on the strip + * @param bus SPI bus to use + * @param cs Pin to use for chip select. -1 if not used. + * @return an initialized apa102 context on success, NULL on error. + */ +apa102_context apa102_init(int ledcount, int bus, int cs); + +/** + * APA102 close function + * + * @param dev The apa102_context to close + */ +void apa102_close(apa102_context dev); + +/** + * Sets the color and brightness for one LED in the buffer + * + * @param dev The apa102_context to use + * @param index Index of the LED (0 based) + * @param brightness Brightness value (0-31) + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @return upm_result_t UPM success/error code + */ +upm_result_t apa102_set_led(apa102_context dev, uint16_t index, uint8_t brightness, uint8_t r, uint8_t g, uint8_t b); + +/** + * Sets the brightness for one LED in the buffer + * + * @param dev The apa102_context to use + * @param index Index of the LED (0 based) + * @param brightness Brightness value (0-31) + * @return upm_result_t UPM success/error code + */ +upm_result_t apa102_set_led_brightness(apa102_context dev, uint16_t index, uint8_t brightness); + +/** + * Sets the color and brightness for multiple LEDs in the buffer + * + * @param dev The apa102_context to use + * @param s_index The start Index of the LED range (0 based) + * @param e_index The end Index of the LED range (0 based) + * @param brightness Brightness value (0-31) + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @return upm_result_t UPM success/error code + */ +upm_result_t apa102_set_leds(apa102_context dev, uint16_t s_index, uint16_t e_index, uint8_t brightness, uint8_t r, uint8_t g, uint8_t b); + +/** + * Sets the brightness for multiple LEDs in the buffer + * + * @param dev The apa102_context to use + * @param s_index The start Index of the LED range (0 based) + * @param e_index The end Index of the LED range (0 based) + * @param brightness Brightness value (0-31) + * @return upm_result_t UPM success/error code + */ +upm_result_t apa102_set_leds_brightness(apa102_context dev, uint16_t s_index, uint16_t e_index, uint8_t brightness); + +/** + * Writes the buffer to the SPI bus thus updating the LED Strip + * + * @param dev The apa102_context to use + * @return upm_result_t UPM success/error code + */ +upm_result_t apa102_refresh(apa102_context dev); + +#ifdef __cplusplus +} +#endif diff --git a/src/apa102/apa102_fti.c b/src/apa102/apa102_fti.c new file mode 100644 index 00000000..73e11d84 --- /dev/null +++ b/src/apa102/apa102_fti.c @@ -0,0 +1,67 @@ +/* + * Author: Mihai Tudor Panu + * Copyright (c) 2016 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 "apa102.h" +#include "upm_fti.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_apa102_name[] = "APA102"; +const char upm_apa102_description[] = "APA102/Dotstar LED Strip"; +const upm_protocol_t upm_apa102_protocol[] = {UPM_SPI, UPM_GPIO}; +const upm_sensor_t upm_apa102_category[] = {}; + +// forward declarations +const void* upm_apa102_get_ft(upm_sensor_t sensor_type); +void* upm_apa102_init_name(); +void upm_apa102_close(void *dev); + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = &upm_apa102_init_name, + .upm_sensor_close = &upm_apa102_close, +}; + +const void* upm_apa102_get_ft(upm_sensor_t sensor_type) +{ + switch(sensor_type) + { + case UPM_SENSOR: + return &ft; + default: + return NULL; + } +} + +void* upm_apa102_init_name() +{ + return NULL; +} + +void upm_apa102_close(void *dev) +{ + apa102_close((apa102_context)dev); +}