Guest User

New_FastLED.h

a guest
Aug 9th, 2023
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 36.90 KB | None | 0 0
  1. #ifndef __INC_FASTSPI_LED2_H
  2. #define __INC_FASTSPI_LED2_H
  3.  
  4. /// @file FastLED.h
  5. /// central include file for FastLED, defines the CFastLED class/object
  6.  
  7. #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
  8. #define FASTLED_HAS_PRAGMA_MESSAGE
  9. #endif
  10.  
  11. /// Current FastLED version number, as an integer.
  12. /// E.g. 3006000 for version "3.6.0", with:
  13. /// * 1 digit for the major version
  14. /// * 3 digits for the minor version
  15. /// * 3 digits for the patch version
  16. #define FASTLED_VERSION 3006000
  17. #ifndef FASTLED_INTERNAL
  18. #  ifdef  FASTLED_SHOW_VERSION
  19. #    ifdef FASTLED_HAS_PRAGMA_MESSAGE
  20. #      pragma message "FastLED version 3.006.000"
  21. #    else
  22. #      warning FastLED version 3.006.000  (Not really a warning, just telling you here.)
  23. #    endif
  24. #  endif
  25. #endif
  26.  
  27. #ifndef __PROG_TYPES_COMPAT__
  28. /// avr-libc define to expose __progmem__ typedefs.
  29. /// @note These typedefs are now deprecated!
  30. /// @see https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html
  31. #define __PROG_TYPES_COMPAT__
  32. #endif
  33.  
  34. #ifdef SmartMatrix_h
  35. #include <SmartMatrix.h>
  36. #endif
  37.  
  38. #ifdef DmxSimple_h
  39. #include <DmxSimple.h>
  40. #endif
  41.  
  42. #ifdef DmxSerial_h
  43. #include <DMXSerial.h>
  44. #endif
  45.  
  46. #include <stdint.h>
  47.  
  48. #include "cpp_compat.h"
  49.  
  50. #include "fastled_config.h"
  51. #include "led_sysdefs.h"
  52.  
  53. // Utility functions
  54. #include "fastled_delay.h"
  55. #include "bitswap.h"
  56.  
  57. #include "controller.h"
  58. #include "fastpin.h"
  59. #include "fastspi_types.h"
  60. #include "dmx.h"
  61.  
  62. #include "platforms.h"
  63. #include "fastled_progmem.h"
  64.  
  65. #include "lib8tion.h"
  66. #include "pixeltypes.h"
  67. #include "hsv2rgb.h"
  68. #include "colorutils.h"
  69. #include "pixelset.h"
  70. #include "colorpalettes.h"
  71.  
  72. #include "noise.h"
  73. #include "power_mgt.h"
  74.  
  75. #include "fastspi.h"
  76. #include "chipsets.h"
  77.  
  78. FASTLED_NAMESPACE_BEGIN
  79.  
  80. /// LED chipsets with SPI interface
  81. enum ESPIChipsets {
  82.     LPD6803,  ///< LPD6803 LED chipset
  83.     LPD8806,  ///< LPD8806 LED chipset
  84.     WS2801,   ///< WS2801 LED chipset
  85.     WS2803,   ///< WS2803 LED chipset
  86.     SM16716,  ///< SM16716 LED chipset
  87.     P9813,    ///< P9813 LED chipset
  88.     APA102,   ///< APA102 LED chipset
  89.     SK9822,   ///< SK9822 LED chipset
  90.     DOTSTAR   ///< APA102 LED chipset alias
  91. };
  92.  
  93. /// Smart Matrix Library controller type
  94. /// @see https://github.com/pixelmatix/SmartMatrix
  95. enum ESM { SMART_MATRIX };
  96.  
  97. /// Octo WS2811 LED Library controller types
  98. /// @see https://www.pjrc.com/teensy/td_libs_OctoWS2811.html
  99. /// @see https://github.com/PaulStoffregen/OctoWS2811
  100. enum OWS2811 { OCTOWS2811,OCTOWS2811_400, OCTOWS2813};
  101.  
  102. /// WS2812Serial Library controller type
  103. /// @see https://www.pjrc.com/non-blocking-ws2812-led-library/
  104. /// @see https://github.com/PaulStoffregen/WS2812Serial
  105. enum SWS2812 { WS2812SERIAL };
  106.  
  107. #ifdef HAS_PIXIE
  108. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class PIXIE : public PixieController<DATA_PIN, RGB_ORDER> {};
  109. #endif
  110.  
  111. #ifdef FASTLED_HAS_CLOCKLESS
  112. /// @addtogroup Chipsets
  113. /// @{
  114. /// @addtogroup ClocklessChipsets
  115. /// @{
  116.  
  117. /// LED controller for WS2812 LEDs with GRB color order
  118. /// @see WS2812Controller800Khz
  119. template<uint8_t DATA_PIN> class NEOPIXEL : public WS2812Controller800Khz<DATA_PIN, GRB> {};
  120. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SM16703 : public SM16703Controller<DATA_PIN, RGB_ORDER> {};                   ///< @copydoc SM16703Controller
  121. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1829 : public TM1829Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc TM1829Controller800Khz
  122. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1812 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< TM1812 controller class. @copydetails TM1809Controller800Khz
  123. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1809 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc TM1809Controller800Khz
  124. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1804 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< TM1804 controller class. @copydetails TM1809Controller800Khz
  125. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1803 : public TM1803Controller400Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc TM1803Controller400Khz
  126. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903 : public UCS1903Controller400Khz<DATA_PIN, RGB_ORDER> {};             ///< @copydoc UCS1903Controller400Khz
  127. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903B : public UCS1903BController800Khz<DATA_PIN, RGB_ORDER> {};           ///< @copydoc UCS1903BController800Khz
  128. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1904 : public UCS1904Controller800Khz<DATA_PIN, RGB_ORDER> {};             ///< @copydoc UCS1904Controller800Khz
  129. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS2903 : public UCS2903Controller<DATA_PIN, RGB_ORDER> {};                   ///< @copydoc UCS2903Controller
  130. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2815V5 : public WS2815V5Controller800Khz<DATA_PIN, RGB_ORDER> {};
  131. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc WS2812Controller800Khz
  132. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2852 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< WS2852 controller class. @copydetails WS2812Controller800Khz
  133. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812B : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};              ///< WS2812B controller class. @copydetails WS2812Controller800Khz
  134. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GS1903 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< GS1903 controller class. @copydetails WS2812Controller800Khz
  135. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6812 : public SK6812Controller<DATA_PIN, RGB_ORDER> {};                     ///< @copydoc SK6812Controller
  136. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6822 : public SK6822Controller<DATA_PIN, RGB_ORDER> {};                     ///< SK6822 controller class. @copydetails SK6822Controller
  137. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class APA106 : public SK6822Controller<DATA_PIN, RGB_ORDER> {};                     ///< APA106 controller class. @copydetails SK6822Controller
  138. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class PL9823 : public PL9823Controller<DATA_PIN, RGB_ORDER> {};                     ///< @copydoc PL9823Controller
  139. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2811 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc WS2811Controller800Khz
  140. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2813 : public WS2813Controller<DATA_PIN, RGB_ORDER> {};                     ///< @copydoc WS2813Controller
  141. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class APA104 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< APA104 controller class. @copydetails WS2811Controller800Khz
  142. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2811_400 : public WS2811Controller400Khz<DATA_PIN, RGB_ORDER> {};           ///< @copydoc WS2811Controller400Khz
  143. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GE8822 : public GE8822Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc GE8822Controller800Khz
  144. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GW6205 : public GW6205Controller800Khz<DATA_PIN, RGB_ORDER> {};               ///< @copydoc GW6205Controller800Khz
  145. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GW6205_400 : public GW6205Controller400Khz<DATA_PIN, RGB_ORDER> {};           ///< @copydoc GW6205Controller400Khz
  146. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class LPD1886 : public LPD1886Controller1250Khz<DATA_PIN, RGB_ORDER> {};            ///< @copydoc LPD1886Controller1250Khz
  147. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class LPD1886_8BIT : public LPD1886Controller1250Khz_8bit<DATA_PIN, RGB_ORDER> {};  ///< @copydoc LPD1886Controller1250Khz_8bit
  148. #if defined(DmxSimple_h) || defined(FASTLED_DOXYGEN)
  149. /// @copydoc DMXSimpleController
  150. template<uint8_t DATA_PIN, EOrder RGB_ORDER> class DMXSIMPLE : public DMXSimpleController<DATA_PIN, RGB_ORDER> {};
  151. #endif
  152. #if defined(DmxSerial_h) || defined(FASTLED_DOXYGEN)
  153. /// @copydoc DMXSerialController
  154. template<EOrder RGB_ORDER> class DMXSERIAL : public DMXSerialController<RGB_ORDER> {};
  155. #endif
  156. #endif
  157. /// @} ClocklessChipsets
  158. /// @} Chipsets
  159.  
  160.  
  161. /// Blockless output port enum
  162. enum EBlockChipsets {
  163. #ifdef PORTA_FIRST_PIN
  164.     WS2811_PORTA,
  165.     WS2813_PORTA,
  166.     WS2811_400_PORTA,
  167.     TM1803_PORTA,
  168.     UCS1903_PORTA,
  169. #endif
  170. #ifdef PORTB_FIRST_PIN
  171.     WS2811_PORTB,
  172.     WS2813_PORTB,
  173.     WS2811_400_PORTB,
  174.     TM1803_PORTB,
  175.     UCS1903_PORTB,
  176. #endif
  177. #ifdef PORTC_FIRST_PIN
  178.     WS2811_PORTC,
  179.     WS2813_PORTC,
  180.     WS2811_400_PORTC,
  181.     TM1803_PORTC,
  182.     UCS1903_PORTC,
  183. #endif
  184. #ifdef PORTD_FIRST_PIN
  185.     WS2811_PORTD,
  186.     WS2813_PORTD,
  187.     WS2811_400_PORTD,
  188.     TM1803_PORTD,
  189.     UCS1903_PORTD,
  190. #endif
  191. #ifdef HAS_PORTDC
  192.     WS2811_PORTDC,
  193.     WS2813_PORTDC,
  194.     WS2811_400_PORTDC,
  195.     TM1803_PORTDC,
  196.     UCS1903_PORTDC,
  197. #endif
  198. };
  199.  
  200. #if defined(LIB8_ATTINY)
  201. #define NUM_CONTROLLERS 2
  202. #else
  203. /// Unknown NUM_CONTROLLERS definition. Unused elsewhere in the library?
  204. /// @todo Remove?
  205. #define NUM_CONTROLLERS 8
  206. #endif
  207.  
  208. /// Typedef for a power consumption calculation function. Used within
  209. /// CFastLED for rescaling brightness before sending the LED data to
  210. /// the strip with CFastLED::show().
  211. /// @param scale the initial brightness scale value
  212. /// @param data max power data, in milliwatts
  213. /// @returns the brightness scale, limited to max power
  214. typedef uint8_t (*power_func)(uint8_t scale, uint32_t data);
  215.  
  216. /// High level controller interface for FastLED.
  217. /// This class manages controllers, global settings, and trackings such as brightness
  218. /// and refresh rates, and provides access functions for driving led data to controllers
  219. /// via the show() / showColor() / clear() methods.
  220. /// This is instantiated as a global object with the name FastLED.
  221. /// @nosubgrouping
  222. class CFastLED {
  223.     // int m_nControllers;
  224.     uint8_t  m_Scale;         ///< the current global brightness scale setting
  225.     uint16_t m_nFPS;          ///< tracking for current frames per second (FPS) value
  226.     uint32_t m_nMinMicros;    ///< minimum Β΅s between frames, used for capping frame rates
  227.     uint32_t m_nPowerData;    ///< max power use parameter
  228.     power_func m_pPowerFunc;  ///< function for overriding brightness when using FastLED.show();
  229.  
  230. public:
  231.     CFastLED();
  232.  
  233.  
  234.     /// Add a CLEDController instance to the world.  Exposed to the public to allow people to implement their own
  235.     /// CLEDController objects or instances.  There are two ways to call this method (as well as the other addLeds()
  236.     /// variations). The first is with 3 arguments, in which case the arguments are the controller, a pointer to
  237.     /// led data, and the number of leds used by this controller.  The second is with 4 arguments, in which case
  238.     /// the first two arguments are the same, the third argument is an offset into the CRGB data where this controller's
  239.     /// CRGB data begins, and the fourth argument is the number of leds for this controller object.
  240.     /// @param pLed the led controller being added
  241.     /// @param data base pointer to an array of CRGB data structures
  242.     /// @param nLedsOrOffset number of leds (3 argument version) or offset into the data array
  243.     /// @param nLedsIfOffset number of leds (4 argument version)
  244.     /// @returns a reference to the added controller
  245.     static CLEDController &addLeds(CLEDController *pLed, struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0);
  246.  
  247.     /// @name Adding SPI-based controllers
  248.     /// Add an SPI based CLEDController instance to the world.
  249.     ///
  250.     /// There are two ways to call this method (as well as the other addLeds()
  251.     /// variations).  The first is with 2 arguments, in which case the arguments are  a pointer to
  252.     /// led data, and the number of leds used by this controller.  The second is with 3 arguments, in which case
  253.     /// the first  argument is the same, the second argument is an offset into the CRGB data where this controller's
  254.     /// CRGB data begins, and the third argument is the number of leds for this controller object.
  255.     ///
  256.     /// @param data base pointer to an array of CRGB data structures
  257.     /// @param nLedsOrOffset number of leds (3 argument version) or offset into the data array
  258.     /// @param nLedsIfOffset number of leds (4 argument version)
  259.     /// @tparam CHIPSET the chipset type
  260.     /// @tparam DATA_PIN the optional data pin for the leds (if omitted, will default to the first hardware SPI MOSI pin)
  261.     /// @tparam CLOCK_PIN the optional clock pin for the leds (if omitted, will default to the first hardware SPI clock pin)
  262.     /// @tparam RGB_ORDER the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
  263.     /// @tparam SPI_DATA_RATE the data rate to drive the SPI clock at, defined using DATA_RATE_MHZ or DATA_RATE_KHZ macros
  264.     /// @returns a reference to the added controller
  265.     /// @{
  266.  
  267.     /// Add an SPI based CLEDController instance to the world.
  268.     template<ESPIChipsets CHIPSET,  uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER, uint32_t SPI_DATA_RATE > CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  269.         switch(CHIPSET) {
  270.             case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  271.             case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  272.             case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  273.             case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  274.             case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  275.             case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  276.             case DOTSTAR:
  277.             case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  278.             case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  279.         }
  280.     }
  281.  
  282.     /// Add an SPI based CLEDController instance to the world.
  283.     template<ESPIChipsets CHIPSET,  uint8_t DATA_PIN, uint8_t CLOCK_PIN > static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  284.         switch(CHIPSET) {
  285.             case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  286.             case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  287.             case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  288.             case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  289.             case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  290.             case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  291.             case DOTSTAR:
  292.             case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  293.             case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  294.         }
  295.     }
  296.  
  297.     /// Add an SPI based CLEDController instance to the world.
  298.     template<ESPIChipsets CHIPSET,  uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER > static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  299.         switch(CHIPSET) {
  300.             case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  301.             case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  302.             case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  303.             case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  304.             case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  305.             case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  306.             case DOTSTAR:
  307.             case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  308.             case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
  309.         }
  310.     }
  311.  
  312. #ifdef SPI_DATA
  313.     template<ESPIChipsets CHIPSET> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  314.         return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB>(data, nLedsOrOffset, nLedsIfOffset);
  315.     }
  316.  
  317.     template<ESPIChipsets CHIPSET, EOrder RGB_ORDER> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  318.         return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB_ORDER>(data, nLedsOrOffset, nLedsIfOffset);
  319.     }
  320.  
  321.     template<ESPIChipsets CHIPSET, EOrder RGB_ORDER, uint32_t SPI_DATA_RATE> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  322.         return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB_ORDER, SPI_DATA_RATE>(data, nLedsOrOffset, nLedsIfOffset);
  323.     }
  324.  
  325. #endif
  326.     /// @} Adding SPI based controllers
  327.  
  328. #ifdef FASTLED_HAS_CLOCKLESS
  329.     /// @name Adding 3-wire led controllers
  330.     /// Add a clockless (aka 3-wire, also DMX) based CLEDController instance to the world.
  331.     ///
  332.     /// There are two ways to call this method (as well as the other addLeds()
  333.     /// variations). The first is with 2 arguments, in which case the arguments are  a pointer to
  334.     /// led data, and the number of leds used by this controller.  The second is with 3 arguments, in which case
  335.     /// the first  argument is the same, the second argument is an offset into the CRGB data where this controller's
  336.     /// CRGB data begins, and the third argument is the number of leds for this controller object.
  337.     ///
  338.     /// This method also takes 2 to 3 template parameters for identifying the specific chipset, data pin,
  339.     /// RGB ordering, and SPI data rate
  340.     ///
  341.     /// @param data base pointer to an array of CRGB data structures
  342.     /// @param nLedsOrOffset number of leds (3 argument version) or offset into the data array
  343.     /// @param nLedsIfOffset number of leds (4 argument version)
  344.     /// @tparam CHIPSET the chipset type (required)
  345.     /// @tparam DATA_PIN the data pin for the leds (required)
  346.     /// @tparam RGB_ORDER the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
  347.     /// @returns a reference to the added controller
  348.     /// @{
  349.  
  350.     /// Add a clockless based CLEDController instance to the world.
  351.     template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER>
  352.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  353.         static CHIPSET<DATA_PIN, RGB_ORDER> c;
  354.         return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
  355.     }
  356.  
  357.     /// Add a clockless based CLEDController instance to the world.
  358.     template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN>
  359.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  360.         static CHIPSET<DATA_PIN, RGB> c;
  361.         return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
  362.     }
  363.  
  364.     /// Add a clockless based CLEDController instance to the world.
  365.     template<template<uint8_t DATA_PIN> class CHIPSET, uint8_t DATA_PIN>
  366.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  367.         static CHIPSET<DATA_PIN> c;
  368.         return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
  369.     }
  370.  
  371. #if defined(__FASTLED_HAS_FIBCC) && (__FASTLED_HAS_FIBCC == 1)
  372.     template<uint8_t NUM_LANES, template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER=RGB>
  373.     static CLEDController &addLeds(struct CRGB *data, int nLeds) {
  374.         static __FIBCC<CHIPSET, DATA_PIN, NUM_LANES, RGB_ORDER> c;
  375.         return addLeds(&c, data, nLeds);
  376.     }
  377. #endif
  378.  
  379.     #ifdef FASTSPI_USE_DMX_SIMPLE
  380.     template<EClocklessChipsets CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER=RGB>
  381.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
  382.     {
  383.         switch(CHIPSET) {
  384.             case DMX: { static DMXController<DATA_PIN> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
  385.         }
  386.     }
  387.     #endif
  388.     /// @} Adding 3-wire led controllers
  389. #endif
  390.  
  391.     /// @name Adding 3rd party library controllers
  392.     /// Add a 3rd party library based CLEDController instance to the world.
  393.     ///
  394.     /// There are two ways to call this method (as well as the other addLeds()
  395.     /// variations).  The first is with 2 arguments, in which case the arguments are  a pointer to
  396.     /// led data, and the number of leds used by this controller.  The second is with 3 arguments, in which case
  397.     /// the first  argument is the same, the second argument is an offset into the CRGB data where this controller's
  398.     /// CRGB data begins, and the third argument is the number of leds for this controller object. This class includes the SmartMatrix
  399.     /// and OctoWS2811 based controllers
  400.     ///
  401.     /// This method also takes 1 to 2 template parameters for identifying the specific chipset and
  402.     /// RGB ordering.
  403.     ///
  404.     /// @param data base pointer to an array of CRGB data structures
  405.     /// @param nLedsOrOffset number of leds (3 argument version) or offset into the data array
  406.     /// @param nLedsIfOffset number of leds (4 argument version)
  407.     /// @tparam CHIPSET the chipset type (required)
  408.     /// @tparam RGB_ORDER the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
  409.     /// @returns a reference to the added controller
  410.     /// @{
  411.  
  412.     /// Add a 3rd party library based CLEDController instance to the world.
  413.     template<template<EOrder RGB_ORDER> class CHIPSET, EOrder RGB_ORDER>
  414.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  415.         static CHIPSET<RGB_ORDER> c;
  416.         return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
  417.     }
  418.  
  419.     /// Add a 3rd party library based CLEDController instance to the world.
  420.     template<template<EOrder RGB_ORDER> class CHIPSET>
  421.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  422.         static CHIPSET<RGB> c;
  423.         return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
  424.     }
  425.  
  426. #ifdef USE_OCTOWS2811
  427.     /// Add a OCTOWS2811 based CLEDController instance to the world.
  428.     /// @see https://www.pjrc.com/teensy/td_libs_OctoWS2811.html
  429.     /// @see https://github.com/PaulStoffregen/OctoWS2811
  430.     template<OWS2811 CHIPSET, EOrder RGB_ORDER>
  431.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
  432.     {
  433.         switch(CHIPSET) {
  434.             case OCTOWS2811: { static COctoWS2811Controller<RGB_ORDER,WS2811_800kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
  435.             case OCTOWS2811_400: { static COctoWS2811Controller<RGB_ORDER,WS2811_400kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
  436. #ifdef WS2813_800kHz
  437.       case OCTOWS2813: { static COctoWS2811Controller<RGB_ORDER,WS2813_800kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
  438. #endif
  439.         }
  440.     }
  441.  
  442.     /// Add a OCTOWS2811 library based CLEDController instance to the world.
  443.     /// @see https://www.pjrc.com/teensy/td_libs_OctoWS2811.html
  444.     /// @see https://github.com/PaulStoffregen/OctoWS2811
  445.     template<OWS2811 CHIPSET>
  446.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
  447.     {
  448.         return addLeds<CHIPSET,GRB>(data,nLedsOrOffset,nLedsIfOffset);
  449.     }
  450.  
  451. #endif
  452.  
  453. #ifdef USE_WS2812SERIAL
  454.     /// Add a WS2812Serial library based CLEDController instance to the world.
  455.     /// @see https://www.pjrc.com/non-blocking-ws2812-led-library/
  456.     /// @see https://github.com/PaulStoffregen/WS2812Serial
  457.     template<SWS2812 CHIPSET, int DATA_PIN, EOrder RGB_ORDER>
  458.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
  459.     {
  460.         static CWS2812SerialController<DATA_PIN,RGB_ORDER> controller;
  461.         return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset);
  462.     }
  463. #endif
  464.  
  465. #ifdef SmartMatrix_h
  466.     /// Add a SmartMatrix library based CLEDController instance to the world.
  467.     /// @see https://github.com/pixelmatix/SmartMatrix
  468.     template<ESM CHIPSET>
  469.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
  470.     {
  471.         switch(CHIPSET) {
  472.             case SMART_MATRIX: { static CSmartMatrixController controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
  473.         }
  474.     }
  475. #endif
  476.     /// @} Adding 3rd party library controllers
  477.  
  478.  
  479. #ifdef FASTLED_HAS_BLOCKLESS
  480.  
  481.     /// @name Adding parallel output controllers
  482.     /// Add a block based CLEDController instance to the world.
  483.     ///
  484.     /// There are two ways to call this method (as well as the other addLeds()
  485.     /// variations).  The first is with 2 arguments, in which case the arguments are  a pointer to
  486.     /// led data, and the number of leds used by this controller.  The second is with 3 arguments, in which case
  487.     /// the first  argument is the same, the second argument is an offset into the CRGB data where this controller's
  488.     /// CRGB data begins, and the third argument is the number of leds for this controller object.
  489.     ///
  490.     /// This method also takes a 2 to 3 template parameters for identifying the specific chipset and rgb ordering
  491.     /// RGB ordering, and SPI data rate
  492.     ///
  493.     /// @param data base pointer to an array of CRGB data structures
  494.     /// @param nLedsOrOffset number of leds (3 argument version) or offset into the data array
  495.     /// @param nLedsIfOffset number of leds (4 argument version)
  496.     /// @tparam CHIPSET the chipset/port type (required)
  497.     /// @tparam NUM_LANES how many parallel lanes of output to write
  498.     /// @tparam RGB_ORDER the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
  499.     /// @returns a reference to the added controller
  500.     /// @{
  501.  
  502.     /// Add a block based parallel output CLEDController instance to the world.
  503.     template<EBlockChipsets CHIPSET, int NUM_LANES, EOrder RGB_ORDER>
  504.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  505.         switch(CHIPSET) {
  506.         #ifdef PORTA_FIRST_PIN
  507.                 case WS2811_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  508.                 case WS2811_400_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  509.         case WS2813_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
  510.                 case TM1803_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  511.                 case UCS1903_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  512.         #endif
  513.         #ifdef PORTB_FIRST_PIN
  514.                 case WS2811_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  515.                 case WS2811_400_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  516.         case WS2813_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
  517.                 case TM1803_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  518.                 case UCS1903_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  519.         #endif
  520.         #ifdef PORTC_FIRST_PIN
  521.                 case WS2811_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  522.                 case WS2811_400_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  523.         case WS2813_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
  524.                 case TM1803_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  525.                 case UCS1903_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  526.         #endif
  527.         #ifdef PORTD_FIRST_PIN
  528.                 case WS2811_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  529.                 case WS2811_400_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  530.         case WS2813_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
  531.                 case TM1803_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  532.                 case UCS1903_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  533.         #endif
  534.         #ifdef HAS_PORTDC
  535.                 case WS2811_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES,NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  536.                 case WS2811_400_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES,NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  537.         case WS2813_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
  538.                 case TM1803_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  539.                 case UCS1903_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
  540.         #endif
  541.         }
  542.     }
  543.  
  544.     /// Add a block based parallel output CLEDController instance to the world.
  545.     template<EBlockChipsets CHIPSET, int NUM_LANES>
  546.     static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
  547.         return addLeds<CHIPSET,NUM_LANES,GRB>(data,nLedsOrOffset,nLedsIfOffset);
  548.     }
  549.     /// @} Adding parallel output controllers
  550. #endif
  551.  
  552.     /// Set the global brightness scaling
  553.     /// @param scale a 0-255 value for how much to scale all leds before writing them out
  554.     void setBrightness(uint8_t scale) { m_Scale = scale; }
  555.  
  556.     /// Get the current global brightness setting
  557.     /// @returns the current global brightness value
  558.     uint8_t getBrightness() { return m_Scale; }
  559.  
  560.     /// Set the maximum power to be used, given in volts and milliamps.
  561.     /// @param volts how many volts the leds are being driven at (usually 5)
  562.     /// @param milliamps the maximum milliamps of power draw you want
  563.     inline void setMaxPowerInVoltsAndMilliamps(uint8_t volts, uint32_t milliamps) { setMaxPowerInMilliWatts(volts * milliamps); }
  564.  
  565.     /// Set the maximum power to be used, given in milliwatts
  566.     /// @param milliwatts the max power draw desired, in milliwatts
  567.     inline void setMaxPowerInMilliWatts(uint32_t milliwatts) { m_pPowerFunc = &calculate_max_brightness_for_power_mW; m_nPowerData = milliwatts; }
  568.  
  569.     /// Update all our controllers with the current led colors, using the passed in brightness
  570.     /// @param scale the brightness value to use in place of the stored value
  571.     void show(uint8_t scale);
  572.  
  573.     /// Update all our controllers with the current led colors
  574.     void show() { show(m_Scale); }
  575.  
  576.     /// Clear the leds, wiping the local array of data. Optionally you can also
  577.     /// send the cleared data to the LEDs.
  578.     /// @param writeData whether or not to write out to the leds as well
  579.     void clear(bool writeData = false);
  580.  
  581.     /// Clear out the local data array
  582.     void clearData();
  583.  
  584.     /// Set all leds on all controllers to the given color/scale.
  585.     /// @param color what color to set the leds to
  586.     /// @param scale what brightness scale to show at
  587.     void showColor(const struct CRGB & color, uint8_t scale);
  588.  
  589.     /// Set all leds on all controllers to the given color
  590.     /// @param color what color to set the leds to
  591.     void showColor(const struct CRGB & color) { showColor(color, m_Scale); }
  592.  
  593.     /// Delay for the given number of milliseconds.  Provided to allow the library to be used on platforms
  594.     /// that don't have a delay function (to allow code to be more portable).
  595.     /// @note This will call show() constantly to drive the dithering engine (and will call show() at least once).
  596.     /// @param ms the number of milliseconds to pause for
  597.     void delay(unsigned long ms);
  598.  
  599.     /// Set a global color temperature.  Sets the color temperature for all added led strips,
  600.     /// overriding whatever previous color temperature those controllers may have had.
  601.     /// @param temp A CRGB structure describing the color temperature
  602.     void setTemperature(const struct CRGB & temp);
  603.  
  604.     /// Set a global color correction.  Sets the color correction for all added led strips,
  605.     /// overriding whatever previous color correction those controllers may have had.
  606.     /// @param correction A CRGB structure describin the color correction.
  607.     void setCorrection(const struct CRGB & correction);
  608.  
  609.     /// Set the dithering mode.  Sets the dithering mode for all added led strips, overriding
  610.     /// whatever previous dithering option those controllers may have had.
  611.     /// @param ditherMode what type of dithering to use, either BINARY_DITHER or DISABLE_DITHER
  612.     void setDither(uint8_t ditherMode = BINARY_DITHER);
  613.  
  614.     /// Set the maximum refresh rate.  This is global for all leds.  Attempts to
  615.     /// call show() faster than this rate will simply wait.
  616.     /// @note The refresh rate defaults to the slowest refresh rate of all the leds added through addLeds().
  617.     /// If you wish to set/override this rate, be sure to call setMaxRefreshRate() _after_
  618.     /// adding all of your leds.
  619.     /// @param refresh maximum refresh rate in hz
  620.     /// @param constrain constrain refresh rate to the slowest speed yet set
  621.     void setMaxRefreshRate(uint16_t refresh, bool constrain=false);
  622.  
  623.     /// For debugging, this will keep track of time between calls to countFPS(). Every
  624.     /// `nFrames` calls, it will update an internal counter for the current FPS.
  625.     /// @todo Make this a rolling counter
  626.     /// @param nFrames how many frames to time for determining FPS
  627.     void countFPS(int nFrames=25);
  628.  
  629.     /// Get the number of frames/second being written out
  630.     /// @returns the most recently computed FPS value
  631.     uint16_t getFPS() { return m_nFPS; }
  632.  
  633.     /// Get how many controllers have been registered
  634.     /// @returns the number of controllers (strips) that have been added with addLeds()
  635.     int count();
  636.  
  637.     /// Get a reference to a registered controller
  638.     /// @returns a reference to the Nth controller
  639.     CLEDController & operator[](int x);
  640.  
  641.     /// Get the number of leds in the first controller
  642.     /// @returns the number of LEDs in the first controller
  643.     int size() { return (*this)[0].size(); }
  644.  
  645.     /// Get a pointer to led data for the first controller
  646.     /// @returns pointer to the CRGB buffer for the first controller
  647.     CRGB *leds() { return (*this)[0].leds(); }
  648. };
  649.  
  650. /// Alias of the FastLED instance for legacy purposes
  651. #define FastSPI_LED FastLED
  652. /// Alias of the FastLED instance for legacy purposes
  653. #define FastSPI_LED2 FastLED
  654. #ifndef LEDS
  655. /// Alias of the FastLED instance for legacy purposes
  656. #define LEDS FastLED
  657. #endif
  658.  
  659. /// Global LED strip management instance
  660. extern CFastLED FastLED;
  661.  
  662. /// If no pin/port mappings are found, sends a warning message to the user
  663. /// during compilation.
  664. /// @see fastpin.h
  665. #ifndef HAS_HARDWARE_PIN_SUPPORT
  666. #warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info."
  667. #define NO_HARDWARE_PIN_SUPPORT
  668. #endif
  669.  
  670.  
  671. FASTLED_NAMESPACE_END
  672.  
  673. #endif
  674.  
Advertisement
Add Comment
Please, Sign In to add comment