该库实现了比Adafruit_NeoPixel
库更丰富的显示效果,且该库的实现是建立在Adafruit_NeoPixel
库的基础上实现的。这里的移植是基于STM32 Keil MDK实现的(其他平台未测试)。
Adafruit_NeoPixel_
的前缀,既便于识别又不会和其他文件函数产生重名冲突。WS2812FX库对应的WS2812FX.cpp
文件中有1600多行代码。贸然直接复制过来修改的话会有太多的工作量。我们根据具体的内容将代码分为两部分移植—基础函数和功能函数。
binary.h
文件(直接从arduino库中复制出来)。未移植自定义显示效果部分的函数;屏蔽掉了显示效果名称部分的定义(节省部分flash空间)
WS2812FX.h
#ifndef __WS2812FX_H
#define __WS2812FX_H
#define WS2812FX_VERSION 0x00000001
/*
移植该库需要建立在移植好Adafruit_NeoPixel库的基础上来实现
1.keil MDK编译器不支持二进制表示,而该库用到了二进制表示,需要用到binary.h文件
2.为了减少库文件本身内容的修改,定义了一些方便移植的宏。
3.当前版本移植匆忙未完全测试
4.该库需要实现获取系统运行时间的函数,这里直接利用了HAL库提供的HAL_GetTick函数。
*/
#include <stdint.h>
#include <stdbool.h>
#include "stm32f4xx.h"
#include "binary.h"
/* 为方便移植定义的宏 */
typedef char __FlashStringHelper;
#define millis HAL_GetTick
#define PROGMEM
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define constrain(amt,low,high) ((amt)<=(low)?(low):((amt)>=(high)?(high):(amt)))
typedef bool boolean;
#define FSH(x) (__FlashStringHelper*)(x)
//#include <Adafruit_NeoPixel.h>
#define DEFAULT_BRIGHTNESS (uint8_t)50
#define DEFAULT_MODE (uint8_t)0
#define DEFAULT_SPEED (uint16_t)1000
#define DEFAULT_COLOR (uint32_t)0xFF0000
#define DEFAULT_COLORS { RED, GREEN, BLUE }
#define COLORS(...) (const uint32_t[]){__VA_ARGS__}
#if defined(ESP8266) || defined(ESP32)
//#pragma message("Compiling for ESP")
#define SPEED_MIN (uint16_t)2
#else
//#pragma message("Compiling for Arduino")
#define SPEED_MIN (uint16_t)10
#endif
#define SPEED_MAX (uint16_t)65535
#define BRIGHTNESS_MIN (uint8_t)0
#define BRIGHTNESS_MAX (uint8_t)255
/* each segment uses 36 bytes of SRAM memory, so if you're compile fails
because of insufficient flash memory, decreasing MAX_NUM_SEGMENTS may help */
#define MAX_NUM_SEGMENTS 10
#define MAX_NUM_ACTIVE_SEGMENTS 10
#define INACTIVE_SEGMENT 255 /* max uint_8 */
#define MAX_NUM_COLORS 3 /* number of colors per segment */
#define MAX_CUSTOM_MODES 8
// some common colors
#define RED (uint32_t)0xFF0000
#define GREEN (uint32_t)0x00FF00
#define BLUE (uint32_t)0x0000FF
#define WHITE (uint32_t)0xFFFFFF
#define BLACK (uint32_t)0x000000
#define YELLOW (uint32_t)0xFFFF00
#define CYAN (uint32_t)0x00FFFF
#define MAGENTA (uint32_t)0xFF00FF
#define PURPLE (uint32_t)0x400080
#define ORANGE (uint32_t)0xFF3000
#define PINK (uint32_t)0xFF1493
#define GRAY (uint32_t)0x101010
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
#define DIM(c) (uint32_t)((c >> 2) & 0x3f3f3f3f) // color at 25% intensity
#define DARK(c) (uint32_t)((c >> 4) & 0x0f0f0f0f) // color at 6% intensity
// segment options
// bit 7: reverse animation
// bits 4-6: fade rate (0-7)
// bit 3: gamma correction
// bits 1-2: size
// bits 0: TBD
#define NO_OPTIONS (uint8_t)B00000000
#define REVERSE (uint8_t)B10000000
#define IS_REVERSE ((_seg->options & REVERSE) == REVERSE)
#define FADE_XFAST (uint8_t)B00010000
#define FADE_FAST (uint8_t)B00100000
#define FADE_MEDIUM (uint8_t)B00110000
#define FADE_SLOW (uint8_t)B01000000
#define FADE_XSLOW (uint8_t)B01010000
#define FADE_XXSLOW (uint8_t)B01100000
#define FADE_GLACIAL (uint8_t)B01110000
#define FADE_RATE ((_seg->options >> 4) & 7)
#define GAMMA (uint8_t)B00001000
#define IS_GAMMA ((_seg->options & GAMMA) == GAMMA)
#define SIZE_SMALL (uint8_t)B00000000
#define SIZE_MEDIUM (uint8_t)B00000010
#define SIZE_LARGE (uint8_t)B00000100
#define SIZE_XLARGE (uint8_t)B00000110
#define SIZE_OPTION ((_seg->options >> 1) & 3)
// segment runtime options (aux_param2)
#define FRAME ((uint8_t)B10000000)
#define SET_FRAME (_seg_rt->aux_param2 |= FRAME)
#define CLR_FRAME (_seg_rt->aux_param2 &= ~FRAME)
#define CYCLE ((uint8_t)B01000000)
#define SET_CYCLE (_seg_rt->aux_param2 |= CYCLE)
#define CLR_CYCLE (_seg_rt->aux_param2 &= ~CYCLE)
#define CLR_FRAME_CYCLE (_seg_rt->aux_param2 &= ~(FRAME | CYCLE))
#define MODE_COUNT 63 //(sizeof(_names)/sizeof(_names[0]))
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
#define FX_MODE_BREATH 2
#define FX_MODE_COLOR_WIPE 3
#define FX_MODE_COLOR_WIPE_INV 4
#define FX_MODE_COLOR_WIPE_REV 5
#define FX_MODE_COLOR_WIPE_REV_INV 6
#define FX_MODE_COLOR_WIPE_RANDOM 7
#define FX_MODE_RANDOM_COLOR 8
#define FX_MODE_SINGLE_DYNAMIC 9
#define FX_MODE_MULTI_DYNAMIC 10
#define FX_MODE_RAINBOW 11
#define FX_MODE_RAINBOW_CYCLE 12
#define FX_MODE_SCAN 13
#define FX_MODE_DUAL_SCAN 14
#define FX_MODE_FADE 15
#define FX_MODE_THEATER_CHASE 16
#define FX_MODE_THEATER_CHASE_RAINBOW 17
#define FX_MODE_RUNNING_LIGHTS 18
#define FX_MODE_TWINKLE 19
#define FX_MODE_TWINKLE_RANDOM 20
#define FX_MODE_TWINKLE_FADE 21
#define FX_MODE_TWINKLE_FADE_RANDOM 22
#define FX_MODE_SPARKLE 23
#define FX_MODE_FLASH_SPARKLE 24
#define FX_MODE_HYPER_SPARKLE 25
#define FX_MODE_STROBE 26
#define FX_MODE_STROBE_RAINBOW 27
#define FX_MODE_MULTI_STROBE 28
#define FX_MODE_BLINK_RAINBOW 29
#define FX_MODE_CHASE_WHITE 30
#define FX_MODE_CHASE_COLOR 31
#define FX_MODE_CHASE_RANDOM 32
#define FX_MODE_CHASE_RAINBOW 33
#define FX_MODE_CHASE_FLASH 34
#define FX_MODE_CHASE_FLASH_RANDOM 35
#define FX_MODE_CHASE_RAINBOW_WHITE 36
#define FX_MODE_CHASE_BLACKOUT 37
#define FX_MODE_CHASE_BLACKOUT_RAINBOW 38
#define FX_MODE_COLOR_SWEEP_RANDOM 39
#define FX_MODE_RUNNING_COLOR 40
#define FX_MODE_RUNNING_RED_BLUE 41
#define FX_MODE_RUNNING_RANDOM 42
#define FX_MODE_LARSON_SCANNER 43
#define FX_MODE_COMET 44
#define FX_MODE_FIREWORKS 45
#define FX_MODE_FIREWORKS_RANDOM 46
#define FX_MODE_MERRY_CHRISTMAS 47
#define FX_MODE_FIRE_FLICKER 48
#define FX_MODE_FIRE_FLICKER_SOFT 49
#define FX_MODE_FIRE_FLICKER_INTENSE 50
#define FX_MODE_CIRCUS_COMBUSTUS 51
#define FX_MODE_HALLOWEEN 52
#define FX_MODE_BICOLOR_CHASE 53
#define FX_MODE_TRICOLOR_CHASE 54
#define FX_MODE_CUSTOM 55 // keep this for backward compatiblity
#define FX_MODE_CUSTOM_0 55 // custom modes need to go at the end
#define FX_MODE_CUSTOM_1 56
#define FX_MODE_CUSTOM_2 57
#define FX_MODE_CUSTOM_3 58
#define FX_MODE_CUSTOM_4 59
#define FX_MODE_CUSTOM_5 60
#define FX_MODE_CUSTOM_6 61
#define FX_MODE_CUSTOM_7 62
typedef uint16_t (*mode_ptr)(void);
// segment parameters
typedef struct Segment { // 20 bytes
uint16_t start;
uint16_t stop;
uint16_t speed;
uint8_t mode;
uint8_t options;
uint32_t colors[MAX_NUM_COLORS];
} Segment;
// segment runtime parameters
typedef struct Segment_runtime { // 16 bytes
unsigned long next_time;
uint32_t counter_mode_step;
uint32_t counter_mode_call;
uint8_t aux_param; // auxilary param (usually stores a color_wheel index)
uint8_t aux_param2; // auxilary param (usually stores bitwise options)
uint16_t aux_param3; // auxilary param (usually stores a segment index)
} Segment_runtime;
void
// timer(void),
WS2812FX_init(uint16_t num_leds, uint8_t type),
WS2812FX_service(void),
WS2812FX_start(void),
WS2812FX_stop(void),
WS2812FX_pause(void),
WS2812FX_resume(void),
WS2812FX_strip_off(void),
WS2812FX_fade_out(void),
WS2812FX_fade_out_targetColor(uint32_t),
WS2812FX_setMode(uint8_t m),
WS2812FX_setMode_seg(uint8_t seg, uint8_t m),
WS2812FX_setOptions(uint8_t seg, uint8_t o),
WS2812FX_setCustomMode(uint16_t (*p)()),
WS2812FX_setCustomShow(void (*p)()),
WS2812FX_setSpeed(uint16_t s),
WS2812FX_setSpeed_seg(uint8_t seg, uint16_t s),
WS2812FX_increaseSpeed(uint8_t s),
WS2812FX_decreaseSpeed(uint8_t s),
WS2812FX_setColor_rgb(uint8_t r, uint8_t g, uint8_t b),
WS2812FX_setColor_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w),
WS2812FX_setColor(uint32_t c),
WS2812FX_setColor_seg(uint8_t seg, uint32_t c),
WS2812FX_setColors(uint8_t seg, uint32_t* c),
WS2812FX_setBrightness(uint8_t b),
WS2812FX_increaseBrightness(uint8_t s),
WS2812FX_decreaseBrightness(uint8_t s),
WS2812FX_setLength(uint16_t b),
WS2812FX_increaseLength(uint16_t s),
WS2812FX_decreaseLength(uint16_t s),
WS2812FX_trigger(void),
WS2812FX_setCycle(void),
WS2812FX_setNumSegments(uint8_t n),
WS2812FX_setSegment_colorReverse(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse),
WS2812FX_setSegment_colorOptions(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options),
WS2812FX_setSegment_colorsReverse(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, bool reverse),
WS2812FX_setSegment_colorsOptions(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, uint8_t options),
WS2812FX_setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options),
WS2812FX_setIdleSegment_colors(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, uint8_t options),
WS2812FX_addActiveSegment(uint8_t seg),
WS2812FX_removeActiveSegment(uint8_t seg),
WS2812FX_swapActiveSegment(uint8_t oldSeg, uint8_t newSeg),
WS2812FX_resetSegments(void),
WS2812FX_resetSegmentRuntimes(void),
WS2812FX_resetSegmentRuntime(uint8_t),
WS2812FX_setPixelColor(uint16_t n, uint32_t c),
WS2812FX_setPixelColor_rgb(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
WS2812FX_setPixelColor_rgbw(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
WS2812FX_copyPixels(uint16_t d, uint16_t s, uint16_t c),
WS2812FX_setPixels(uint16_t, uint8_t*),
WS2812FX_show(void);
boolean
WS2812FX_isRunning(void),
WS2812FX_isTriggered(void),
WS2812FX_isFrame(void),
WS2812FX_isFrame_seg(uint8_t),
WS2812FX_isCycle(void),
WS2812FX_isCycle_seg(uint8_t),
WS2812FX_isActiveSegment(uint8_t seg);
uint8_t
WS2812FX_random8(void),
WS2812FX_random8_lim(uint8_t),
WS2812FX_getMode(void),
WS2812FX_getMode_seg(uint8_t),
WS2812FX_getModeCount(void),
// WS2812FX_setCustomMode(const __FlashStringHelper* name, uint16_t (*p)()),
// WS2812FX_setCustomMode(uint8_t i, const __FlashStringHelper* name, uint16_t (*p)()),
WS2812FX_getNumSegments(void),
WS2812FX_get_random_wheel_index(uint8_t),
WS2812FX_getOptions(uint8_t),
WS2812FX_getNumBytesPerPixel(void);
uint16_t
WS2812FX_random16(void),
WS2812FX_random16_lim(uint16_t),
WS2812FX_getSpeed(void),
WS2812FX_getSpeed_seg(uint8_t),
WS2812FX_getLength(void),
WS2812FX_getNumBytes(void);
uint32_t
WS2812FX_color_wheel(uint8_t),
WS2812FX_getColor(void),
WS2812FX_getColor_seg(uint8_t),
WS2812FX_intensitySum(void);
uint32_t* getColors(uint8_t);
uint32_t* intensitySums(void);
uint8_t* getActiveSegments(void);
const __FlashStringHelper* getModeName(uint8_t m);
Segment* getSegment(void);
Segment* getSegment_seg(uint8_t);
Segment* getSegments(void);
Segment_runtime* getSegmentRuntime(void);
Segment_runtime* getSegmentRuntime_seg(uint8_t);
Segment_runtime* getSegmentRuntimes(void);
// mode helper functions
uint16_t
WS2812FX_blink(uint32_t, uint32_t, bool strobe),
WS2812FX_color_wipe(uint32_t, uint32_t, bool),
WS2812FX_twinkle(uint32_t, uint32_t),
WS2812FX_twinkle_fade(uint32_t),
WS2812FX_sparkle(uint32_t, uint32_t),
WS2812FX_chase(uint32_t, uint32_t, uint32_t),
WS2812FX_chase_flash(uint32_t, uint32_t),
WS2812FX_running(uint32_t, uint32_t),
WS2812FX_fireworks(uint32_t),
WS2812FX_fire_flicker(int),
WS2812FX_tricolor_chase(uint32_t, uint32_t, uint32_t),
WS2812FX_scan(uint32_t, uint32_t, bool);
uint32_t
WS2812FX_color_blend(uint32_t, uint32_t, uint8_t);
// builtin modes
uint16_t
WS2812FX_mode_static(void),
WS2812FX_mode_blink(void),
WS2812FX_mode_blink_rainbow(void),
WS2812FX_mode_strobe(void),
WS2812FX_mode_strobe_rainbow(void),
WS2812FX_mode_color_wipe(void),
WS2812FX_mode_color_wipe_inv(void),
WS2812FX_mode_color_wipe_rev(void),
WS2812FX_mode_color_wipe_rev_inv(void),
WS2812FX_mode_color_wipe_random(void),
WS2812FX_mode_color_sweep_random(void),
WS2812FX_mode_random_color(void),
WS2812FX_mode_single_dynamic(void),
WS2812FX_mode_multi_dynamic(void),
WS2812FX_mode_breath(void),
WS2812FX_mode_fade(void),
WS2812FX_mode_scan(void),
WS2812FX_mode_dual_scan(void),
WS2812FX_mode_theater_chase(void),
WS2812FX_mode_theater_chase_rainbow(void),
WS2812FX_mode_rainbow(void),
WS2812FX_mode_rainbow_cycle(void),
WS2812FX_mode_running_lights(void),
WS2812FX_mode_twinkle(void),
WS2812FX_mode_twinkle_random(void),
WS2812FX_mode_twinkle_fade(void),
WS2812FX_mode_twinkle_fade_random(void),
WS2812FX_mode_sparkle(void),
WS2812FX_mode_flash_sparkle(void),
WS2812FX_mode_hyper_sparkle(void),
WS2812FX_mode_multi_strobe(void),
WS2812FX_mode_chase_white(void),
WS2812FX_mode_chase_color(void),
WS2812FX_mode_chase_random(void),
WS2812FX_mode_chase_rainbow(void),
WS2812FX_mode_chase_flash(void),
WS2812FX_mode_chase_flash_random(void),
WS2812FX_mode_chase_rainbow_white(void),
WS2812FX_mode_chase_blackout(void),
WS2812FX_mode_chase_blackout_rainbow(void),
WS2812FX_mode_running_color(void),
WS2812FX_mode_running_red_blue(void),
WS2812FX_mode_running_random(void),
WS2812FX_mode_larson_scanner(void),
WS2812FX_mode_comet(void),
WS2812FX_mode_fireworks(void),
WS2812FX_mode_fireworks_random(void),
WS2812FX_mode_merry_christmas(void),
WS2812FX_mode_halloween(void),
WS2812FX_mode_fire_flicker(void),
WS2812FX_mode_fire_flicker_soft(void),
WS2812FX_mode_fire_flicker_intense(void),
WS2812FX_mode_circus_combustus(void),
WS2812FX_mode_bicolor_chase(void),
WS2812FX_mode_tricolor_chase(void),
WS2812FX_mode_custom_0(void),
WS2812FX_mode_custom_1(void),
WS2812FX_mode_custom_2(void),
WS2812FX_mode_custom_3(void),
WS2812FX_mode_custom_4(void),
WS2812FX_mode_custom_5(void),
WS2812FX_mode_custom_6(void),
WS2812FX_mode_custom_7(void);
#endif /* __BSP_WS2812FX_H */
WS2812FX.c
#include "WS2812FX.h"
#include <stdbool.h>
#include "bsp_delay.h"
#include "Adafruit_NeoPixel.h"
#include <stdlib.h>
#include <string.h>
// create GLOBAL names to allow WS2812FX to compile with sketches and other libs
// that store strings in PROGMEM (get rid of the "section type conflict with __c"
// errors once and for all. Amen.)
//const char name_0[] PROGMEM = "Static";
//const char name_1[] PROGMEM = "Blink";
//const char name_2[] PROGMEM = "Breath";
//const char name_3[] PROGMEM = "Color Wipe";
//const char name_4[] PROGMEM = "Color Wipe Inverse";
//const char name_5[] PROGMEM = "Color Wipe Reverse";
//const char name_6[] PROGMEM = "Color Wipe Reverse Inverse";
//const char name_7[] PROGMEM = "Color Wipe Random";
//const char name_8[] PROGMEM = "Random Color";
//const char name_9[] PROGMEM = "Single Dynamic";
//const char name_10[] PROGMEM = "Multi Dynamic";
//const char name_11[] PROGMEM = "Rainbow";
//const char name_12[] PROGMEM = "Rainbow Cycle";
//const char name_13[] PROGMEM = "Scan";
//const char name_14[] PROGMEM = "Dual Scan";
//const char name_15[] PROGMEM = "Fade";
//const char name_16[] PROGMEM = "Theater Chase";
//const char name_17[] PROGMEM = "Theater Chase Rainbow";
//const char name_18[] PROGMEM = "Running Lights";
//const char name_19[] PROGMEM = "Twinkle";
//const char name_20[] PROGMEM = "Twinkle Random";
//const char name_21[] PROGMEM = "Twinkle Fade";
//const char name_22[] PROGMEM = "Twinkle Fade Random";
//const char name_23[] PROGMEM = "Sparkle";
//const char name_24[] PROGMEM = "Flash Sparkle";
//const char name_25[] PROGMEM = "Hyper Sparkle";
//const char name_26[] PROGMEM = "Strobe";
//const char name_27[] PROGMEM = "Strobe Rainbow";
//const char name_28[] PROGMEM = "Multi Strobe";
//const char name_29[] PROGMEM = "Blink Rainbow";
//const char name_30[] PROGMEM = "Chase White";
//const char name_31[] PROGMEM = "Chase Color";
//const char name_32[] PROGMEM = "Chase Random";
//const char name_33[] PROGMEM = "Chase Rainbow";
//const char name_34[] PROGMEM = "Chase Flash";
//const char name_35[] PROGMEM = "Chase Flash Random";
//const char name_36[] PROGMEM = "Chase Rainbow White";
//const char name_37[] PROGMEM = "Chase Blackout";
//const char name_38[] PROGMEM = "Chase Blackout Rainbow";
//const char name_39[] PROGMEM = "Color Sweep Random";
//const char name_40[] PROGMEM = "Running Color";
//const char name_41[] PROGMEM = "Running Red Blue";
//const char name_42[] PROGMEM = "Running Random";
//const char name_43[] PROGMEM = "Larson Scanner";
//const char name_44[] PROGMEM = "Comet";
//const char name_45[] PROGMEM = "Fireworks";
//const char name_46[] PROGMEM = "Fireworks Random";
//const char name_47[] PROGMEM = "Merry Christmas";
//const char name_48[] PROGMEM = "Fire Flicker";
//const char name_49[] PROGMEM = "Fire Flicker (soft)";
//const char name_50[] PROGMEM = "Fire Flicker (intense)";
//const char name_51[] PROGMEM = "Circus Combustus";
//const char name_52[] PROGMEM = "Halloween";
//const char name_53[] PROGMEM = "Bicolor Chase";
//const char name_54[] PROGMEM = "Tricolor Chase";
//const char name_55[] PROGMEM = "Custom 0"; // custom modes need to go at the end
//const char name_56[] PROGMEM = "Custom 1";
//const char name_57[] PROGMEM = "Custom 2";
//const char name_58[] PROGMEM = "Custom 3";
//const char name_59[] PROGMEM = "Custom 4";
//const char name_60[] PROGMEM = "Custom 5";
//const char name_61[] PROGMEM = "Custom 6";
//const char name_62[] PROGMEM = "Custom 7";
//static const __FlashStringHelper* _names[] = {
// FSH(name_0),
// FSH(name_1),
// FSH(name_2),
// FSH(name_3),
// FSH(name_4),
// FSH(name_5),
// FSH(name_6),
// FSH(name_7),
// FSH(name_8),
// FSH(name_9),
// FSH(name_10),
// FSH(name_11),
// FSH(name_12),
// FSH(name_13),
// FSH(name_14),
// FSH(name_15),
// FSH(name_16),
// FSH(name_17),
// FSH(name_18),
// FSH(name_19),
// FSH(name_20),
// FSH(name_21),
// FSH(name_22),
// FSH(name_23),
// FSH(name_24),
// FSH(name_25),
// FSH(name_26),
// FSH(name_27),
// FSH(name_28),
// FSH(name_29),
// FSH(name_30),
// FSH(name_31),
// FSH(name_32),
// FSH(name_33),
// FSH(name_34),
// FSH(name_35),
// FSH(name_36),
// FSH(name_37),
// FSH(name_38),
// FSH(name_39),
// FSH(name_40),
// FSH(name_41),
// FSH(name_42),
// FSH(name_43),
// FSH(name_44),
// FSH(name_45),
// FSH(name_46),
// FSH(name_47),
// FSH(name_48),
// FSH(name_49),
// FSH(name_50),
// FSH(name_51),
// FSH(name_52),
// FSH(name_53),
// FSH(name_54),
// FSH(name_55),
// FSH(name_56),
// FSH(name_57),
// FSH(name_58),
// FSH(name_59),
// FSH(name_60),
// FSH(name_61),
// FSH(name_62)
//};
static uint16_t _rand16seed;
static void (*customShow)(void) = NULL;
static bool _running, _triggered;
static Segment* _segments; // array of segments (20 bytes per element)
static Segment_runtime* _segment_runtimes; // array of segment runtimes (16 bytes per element)
static uint8_t* _active_segments; // array of active segments (1 bytes per element)
static uint8_t _segments_len = 0; // size of _segments array
static uint8_t _active_segments_len = 0; // size of _segments_runtime and _active_segments arrays
static uint8_t _num_segments = 0; // number of configured segments in the _segments array
static Segment* _seg; // currently active segment (20 bytes)
static Segment_runtime* _seg_rt; // currently active segment runtime (16 bytes)
static uint16_t _seg_len; // num LEDs in the currently active segment
// define static array of member function pointers.
// function pointers MUST be in the same order as the corresponding name in the _name array.
static mode_ptr _modes[MODE_COUNT] = {
&WS2812FX_mode_static,
&WS2812FX_mode_blink,
&WS2812FX_mode_breath,
&WS2812FX_mode_color_wipe,
&WS2812FX_mode_color_wipe_inv,
&WS2812FX_mode_color_wipe_rev,
&WS2812FX_mode_color_wipe_rev_inv,
&WS2812FX_mode_color_wipe_random,
&WS2812FX_mode_random_color,
&WS2812FX_mode_single_dynamic,
&WS2812FX_mode_multi_dynamic,
&WS2812FX_mode_rainbow,
&WS2812FX_mode_rainbow_cycle,
&WS2812FX_mode_scan,
&WS2812FX_mode_dual_scan,
&WS2812FX_mode_fade,
&WS2812FX_mode_theater_chase,
&WS2812FX_mode_theater_chase_rainbow,
&WS2812FX_mode_running_lights,
&WS2812FX_mode_twinkle,
&WS2812FX_mode_twinkle_random,
&WS2812FX_mode_twinkle_fade,
&WS2812FX_mode_twinkle_fade_random,
&WS2812FX_mode_sparkle,
&WS2812FX_mode_flash_sparkle,
&WS2812FX_mode_hyper_sparkle,
&WS2812FX_mode_strobe,
&WS2812FX_mode_strobe_rainbow,
&WS2812FX_mode_multi_strobe,
&WS2812FX_mode_blink_rainbow,
&WS2812FX_mode_chase_white,
&WS2812FX_mode_chase_color,
&WS2812FX_mode_chase_random,
&WS2812FX_mode_chase_rainbow,
&WS2812FX_mode_chase_flash,
&WS2812FX_mode_chase_flash_random,
&WS2812FX_mode_chase_rainbow_white,
&WS2812FX_mode_chase_blackout,
&WS2812FX_mode_chase_blackout_rainbow,
&WS2812FX_mode_color_sweep_random,
&WS2812FX_mode_running_color,
&WS2812FX_mode_running_red_blue,
&WS2812FX_mode_running_random,
&WS2812FX_mode_larson_scanner,
&WS2812FX_mode_comet,
&WS2812FX_mode_fireworks,
&WS2812FX_mode_fireworks_random,
&WS2812FX_mode_merry_christmas,
&WS2812FX_mode_fire_flicker,
&WS2812FX_mode_fire_flicker_soft,
&WS2812FX_mode_fire_flicker_intense,
&WS2812FX_mode_circus_combustus,
&WS2812FX_mode_halloween,
&WS2812FX_mode_bicolor_chase,
&WS2812FX_mode_tricolor_chase,
// &WS2812FX_mode_custom_0,
// &WS2812FX_mode_custom_1,
// &WS2812FX_mode_custom_2,
// &WS2812FX_mode_custom_3,
// &WS2812FX_mode_custom_4,
// &WS2812FX_mode_custom_5,
// &WS2812FX_mode_custom_6,
// &WS2812FX_mode_custom_7
};
void WS2812FX_init(uint16_t num_leds, uint8_t type) {
Adafruit_NeoPixel_init(num_leds, type); //该函数要放在起始位置,放在后面可能会导致内存申请失败
_running = false;
_segments_len = MAX_NUM_SEGMENTS;
_active_segments_len = MAX_NUM_ACTIVE_SEGMENTS;
// create all the segment arrays and init to zeros
_segments = (Segment *)malloc(_segments_len * sizeof(Segment));
_active_segments = (uint8_t *)malloc(_active_segments_len * sizeof(uint8_t));
_segment_runtimes = (Segment_runtime *)malloc(_active_segments_len * sizeof(uint8_t));
WS2812FX_resetSegments();
WS2812FX_setSegment_colorOptions(0, 0, num_leds - 1, DEFAULT_MODE, DEFAULT_COLOR, DEFAULT_SPEED, NO_OPTIONS);
WS2812FX_resetSegmentRuntimes();
Adafruit_NeoPixel_setBrightness(DEFAULT_BRIGHTNESS + 1);
}
// void WS2812FX::timer() {
// for (int j=0; j < 1000; j++) {
// uint16_t delay = (this->*_modes[_seg->mode])();
// }
// }
void WS2812FX_service() {
if(_running || _triggered) {
unsigned long now = millis(); // Be aware, millis() rolls over every 49 days
bool doShow = false;
for(uint8_t i=0; i < _active_segments_len; i++) {
if(_active_segments[i] != INACTIVE_SEGMENT) {
_seg = &_segments[_active_segments[i]];
_seg_len = (uint16_t)(_seg->stop - _seg->start + 1);
_seg_rt = &_segment_runtimes[i];
CLR_FRAME_CYCLE;
if(now > _seg_rt->next_time || _triggered) {
SET_FRAME;
doShow = true;
uint16_t delay = (*_modes[_seg->mode])();
_seg_rt->next_time = now + max(delay, SPEED_MIN);
_seg_rt->counter_mode_call++;
}
}
}
if(doShow) {
// delay(1); // for ESP32 (see https://forums.adafruit.com/viewtopic.php?f=47&t=117327)
WS2812FX_show();
}
_triggered = false;
}
}
// overload setPixelColor() functions so we can use gamma correction
// (see https://learn.adafruit.com/led-tricks-gamma-correction/the-issue)
void WS2812FX_setPixelColor(uint16_t n, uint32_t c) {
uint8_t w = (c >> 24) & 0xFF;
uint8_t r = (c >> 16) & 0xFF;
uint8_t g = (c >> 8) & 0xFF;
uint8_t b = c & 0xFF;
WS2812FX_setPixelColor_rgbw(n, r, g, b, w);
}
void WS2812FX_setPixelColor_rgb(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
WS2812FX_setPixelColor_rgbw(n, r, g, b, 0);
}
void WS2812FX_setPixelColor_rgbw(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
if(IS_GAMMA) {
Adafruit_NeoPixel_setPixelColor_rgbw(n, Adafruit_NeoPixel_gamma8(r), Adafruit_NeoPixel_gamma8(g), Adafruit_NeoPixel_gamma8(b), Adafruit_NeoPixel_gamma8(w));
} else {
Adafruit_NeoPixel_setPixelColor_rgbw(n, r, g, b, w);
}
}
void WS2812FX_copyPixels(uint16_t dest, uint16_t src, uint16_t count) {
uint8_t *pixels = Adafruit_NeoPixel_getPixels();
uint8_t bytesPerPixel = WS2812FX_getNumBytesPerPixel(); // 3=RGB, 4=RGBW
memmove(pixels + (dest * bytesPerPixel), pixels + (src * bytesPerPixel), count * bytesPerPixel);
}
// change the underlying Adafruit_NeoPixel pixels pointer (use with care)
//void WS2812FX_setPixels(uint16_t num_leds, uint8_t* ptr) {
// free(Adafruit_NeoPixel::pixels); // free existing data (if any)
// Adafruit_NeoPixel::pixels = ptr;
// Adafruit_NeoPixel::numLEDs = num_leds;
// Adafruit_NeoPixel::numBytes = num_leds * ((wOffset == rOffset) ? 3 : 4);
//}
// overload show() functions so we can use custom show()
void WS2812FX_show(void) {
customShow == NULL ? Adafruit_NeoPixel_show() : customShow();
}
void WS2812FX_start() {
WS2812FX_resetSegmentRuntimes();
_running = true;
}
void WS2812FX_stop() {
_running = false;
WS2812FX_strip_off();
}
void WS2812FX_pause() {
_running = false;
}
void WS2812FX_resume() {
_running = true;
}
void WS2812FX_trigger() {
_triggered = true;
}
void WS2812FX_setMode(uint8_t m) {
WS2812FX_setMode_seg(0, m);
}
void WS2812FX_setMode_seg(uint8_t seg, uint8_t m) {
WS2812FX_resetSegmentRuntime(seg);
_segments[seg].mode = constrain(m, 0, MODE_COUNT - 1);
}
void WS2812FX_setOptions(uint8_t seg, uint8_t o) {
_segments[seg].options = o;
}
void WS2812FX_setSpeed(uint16_t s) {
WS2812FX_setSpeed_seg(0, s);
}
void WS2812FX_setSpeed_seg(uint8_t seg, uint16_t s) {
_segments[seg].speed = constrain(s, SPEED_MIN, SPEED_MAX);
}
void WS2812FX_increaseSpeed(uint8_t s) {
uint16_t newSpeed = constrain(_seg->speed + s, SPEED_MIN, SPEED_MAX);
WS2812FX_setSpeed(newSpeed);
}
void WS2812FX_decreaseSpeed(uint8_t s) {
uint16_t newSpeed = constrain(_seg->speed - s, SPEED_MIN, SPEED_MAX);
WS2812FX_setSpeed(newSpeed);
}
void WS2812FX_setColor_rgb(uint8_t r, uint8_t g, uint8_t b) {
WS2812FX_setColor(((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
}
void WS2812FX_setColor_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
WS2812FX_setColor((((uint32_t)w << 24)| ((uint32_t)r << 16) | ((uint32_t)g << 8)| ((uint32_t)b)));
}
void WS2812FX_setColor(uint32_t c) {
WS2812FX_setColor_seg(0, c);
}
void WS2812FX_setColor_seg(uint8_t seg, uint32_t c) {
_segments[seg].colors[0] = c;
}
void WS2812FX_setColors(uint8_t seg, uint32_t* c) {
for(uint8_t i=0; i<MAX_NUM_COLORS; i++) {
_segments[seg].colors[i] = c[i];
}
}
void WS2812FX_setBrightness(uint8_t b) {
b = constrain(b, BRIGHTNESS_MIN, BRIGHTNESS_MAX);
Adafruit_NeoPixel_setBrightness(b);
WS2812FX_show();
}
void WS2812FX_increaseBrightness(uint8_t s) {
s = constrain(Adafruit_NeoPixel_getBrightness() + s, BRIGHTNESS_MIN, BRIGHTNESS_MAX);
WS2812FX_setBrightness(s);
}
void WS2812FX_decreaseBrightness(uint8_t s) {
s = constrain(Adafruit_NeoPixel_getBrightness() - s, BRIGHTNESS_MIN, BRIGHTNESS_MAX);
WS2812FX_setBrightness(s);
}
//void WS2812FX::setLength(uint16_t b) {
// resetSegmentRuntimes();
// if (b < 1) b = 1;
// // Decrease numLEDs to maximum available memory
// do {
// Adafruit_NeoPixel::updateLength(b);
// b--;
// } while(!Adafruit_NeoPixel::numLEDs && b > 1);
// _segments[0].start = 0;
// _segments[0].stop = Adafruit_NeoPixel::numLEDs - 1;
//}
//void WS2812FX_increaseLength(uint16_t s) {
// uint16_t seglen = _segments[0].stop - _segments[0].start + 1;
// setLength(seglen + s);
//}
//void WS2812FX_decreaseLength(uint16_t s) {
// uint16_t seglen = _segments[0].stop - _segments[0].start + 1;
// fill(BLACK, _segments[0].start, seglen);
// show();
// if (s < seglen) setLength(seglen - s);
//}
boolean WS2812FX_isRunning() {
return _running;
}
boolean WS2812FX_isTriggered() {
return _triggered;
}
boolean WS2812FX_isFrame() {
return WS2812FX_isFrame_seg(0);
}
boolean WS2812FX_isFrame_seg(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr == NULL) return false; // segment not active
return (_segment_runtimes[ptr - _active_segments].aux_param2 & FRAME);
}
boolean WS2812FX_isCycle() {
return WS2812FX_isCycle_seg(0);
}
boolean WS2812FX_isCycle_seg(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr == NULL) return false; // segment not active
return (_segment_runtimes[ptr - _active_segments].aux_param2 & CYCLE);
}
void WS2812FX_setCycle() {
SET_CYCLE;
}
uint8_t WS2812FX_getMode(void) {
return WS2812FX_getMode_seg(0);
}
uint8_t WS2812FX_getMode_seg(uint8_t seg) {
return _segments[seg].mode;
}
uint16_t WS2812FX_getSpeed(void) {
return WS2812FX_getSpeed_seg(0);
}
uint16_t WS2812FX_getSpeed_seg(uint8_t seg) {
return _segments[seg].speed;
}
uint8_t WS2812FX_getOptions(uint8_t seg) {
return _segments[seg].options;
}
uint16_t WS2812FX_getLength(void) {
return Adafruit_NeoPixel_numPixels();
}
uint16_t WS2812FX_getNumBytes(void) {
return Adafruit_NeoPixel_getNumBytes();
}
uint8_t WS2812FX_getNumBytesPerPixel(void) {
return Adafruit_NeoPixel_getNumBytesPerPixel();
}
uint8_t WS2812FX_getModeCount(void) {
return MODE_COUNT;
}
uint8_t WS2812FX_getNumSegments(void) {
return _num_segments;
}
void WS2812FX_setNumSegments(uint8_t n) {
_num_segments = n;
}
uint32_t WS2812FX_getColor(void) {
return WS2812FX_getColor_seg(0);
}
uint32_t WS2812FX_getColor_seg(uint8_t seg) {
return _segments[seg].colors[0];
}
uint32_t* WS2812FX_getColors(uint8_t seg) {
return _segments[seg].colors;
}
Segment* WS2812FX_getSegment(void) {
return _seg;
}
Segment* WS2812FX_getSegment_seg(uint8_t seg) {
return &_segments[seg];
}
Segment* WS2812FX_getSegments(void) {
return _segments;
}
Segment_runtime* WS2812FX_getSegmentRuntime(void) {
return _seg_rt;
}
Segment_runtime* WS2812FX_getSegmentRuntime_seg(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr == NULL) return NULL; // segment not active
return &_segment_runtimes[ptr - _active_segments];
}
Segment_runtime* WS2812FX_getSegmentRuntimes(void) {
return _segment_runtimes;
}
uint8_t* WS2812FX_getActiveSegments(void) {
return _active_segments;
}
//const __FlashStringHelper* WS2812FX_getModeName(uint8_t m) {
// if(m < MODE_COUNT) {
// return _names[m];
// } else {
// return "";//F("");
// }
//}
void WS2812FX_setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options) {
uint32_t colors[] = {color, 0, 0};
WS2812FX_setIdleSegment_colors(n, start, stop, mode, colors, speed, options);
}
void WS2812FX_setIdleSegment_colors(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, uint8_t options) {
WS2812FX_setSegment_colorsOptions(n, start, stop, mode, colors, speed, options);
if(n < _active_segments_len) WS2812FX_removeActiveSegment(n);;
}
void WS2812FX_setSegment_colorReverse(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse) {
uint32_t colors[] = {color, 0, 0};
WS2812FX_setSegment_colorsOptions(n, start, stop, mode, colors, speed, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
}
void WS2812FX_setSegment_colorsReverse(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, bool reverse) {
WS2812FX_setSegment_colorsOptions(n, start, stop, mode, colors, speed, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
}
void WS2812FX_setSegment_colorOptions(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options) {
uint32_t colors[] = {color, 0, 0};
WS2812FX_setSegment_colorsOptions(n, start, stop, mode, colors, speed, options);
}
void WS2812FX_setSegment_colorsOptions(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t colors[], uint16_t speed, uint8_t options) {
if(n < _segments_len) {
if(n + 1 > _num_segments) _num_segments = n + 1;
_segments[n].start = start;
_segments[n].stop = stop;
_segments[n].mode = mode;
_segments[n].speed = speed;
_segments[n].options = options;
WS2812FX_setColors(n, (uint32_t*)colors);
if(n < _active_segments_len) WS2812FX_addActiveSegment(n);
}
}
void WS2812FX_addActiveSegment(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr != NULL) return; // segment already active
for(uint8_t i=0; i<_active_segments_len; i++) {
if(_active_segments[i] == INACTIVE_SEGMENT) {
_active_segments[i] = seg;
WS2812FX_resetSegmentRuntime(seg);
break;
}
}
}
void WS2812FX_removeActiveSegment(uint8_t seg) {
for(uint8_t i=0; i<_active_segments_len; i++) {
if(_active_segments[i] == seg) {
_active_segments[i] = INACTIVE_SEGMENT;
}
}
}
void WS2812FX_swapActiveSegment(uint8_t oldSeg, uint8_t newSeg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, newSeg, _active_segments_len);
if(ptr != NULL) return; // if newSeg is already active, don't swap
for(uint8_t i=0; i<_active_segments_len; i++) {
if(_active_segments[i] == oldSeg) {
_active_segments[i] = newSeg;
// reset all runtime parameters EXCEPT next_time,
// allowing the current animation frame to complete
Segment_runtime seg_rt = _segment_runtimes[i];
seg_rt.counter_mode_step = 0;
seg_rt.counter_mode_call = 0;
seg_rt.aux_param = 0;
seg_rt.aux_param2 = 0;
seg_rt.aux_param3 = 0;
break;
}
}
}
boolean WS2812FX_isActiveSegment(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr != NULL) return true;
return false;
}
void WS2812FX_resetSegments() {
WS2812FX_resetSegmentRuntimes();
memset(_segments, 0, _segments_len * sizeof(Segment));
memset(_active_segments, INACTIVE_SEGMENT, _active_segments_len);
_num_segments = 0;
}
void WS2812FX_resetSegmentRuntimes() {
memset(_segment_runtimes, 0, _active_segments_len * sizeof(Segment_runtime));
}
void WS2812FX_resetSegmentRuntime(uint8_t seg) {
uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
if(ptr == NULL) return; // segment not active
memset(&_segment_runtimes[ptr - _active_segments], 0, sizeof(Segment_runtime));
}
/*
* Turns everything off. Doh.
*/
void WS2812FX_strip_off() {
Adafruit_NeoPixel_clear();
WS2812FX_show();
}
/*
* Put a value 0 to 255 in to get a color value.
* The colours are a transition r -> g -> b -> back to r
* Inspired by the Adafruit examples.
*/
uint32_t WS2812FX_color_wheel(uint8_t pos) {
pos = 255 - pos;
if(pos < 85) {
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
} else if(pos < 170) {
pos -= 85;
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
} else {
pos -= 170;
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
}
}
/*
* Returns a new, random wheel index with a minimum distance of 42 from pos.
*/
uint8_t WS2812FX_get_random_wheel_index(uint8_t pos) {
uint8_t r = 0;
uint8_t x = 0;
uint8_t y = 0;
uint8_t d = 0;
while(d < 42) {
r = WS2812FX_random8();
x = abs(pos - r);
y = 255 - x;
d = min(x, y);
}
return r;
}
// fast 8-bit random number generator shamelessly borrowed from FastLED
uint8_t WS2812FX_random8() {
_rand16seed = (_rand16seed * 2053) + 13849;
return (uint8_t)((_rand16seed + (_rand16seed >> 8)) & 0xFF);
}
// note random8(lim) generates numbers in the range 0 to (lim -1)
uint8_t WS2812FX_random8_lim(uint8_t lim) {
uint8_t r = WS2812FX_random8();
r = ((uint16_t)r * lim) >> 8;
return r;
}
uint16_t WS2812FX_random16() {
return (uint16_t)WS2812FX_random8() * 256 + WS2812FX_random8();
}
// note random16(lim) generates numbers in the range 0 to (lim - 1)
uint16_t WS2812FX_random16_lim(uint16_t lim) {
uint16_t r = WS2812FX_random16();
r = ((uint32_t)r * lim) >> 16;
return r;
}
// Return the sum of all LED intensities (can be used for
// rudimentary power calculations)
//uint32_t WS2812FX_intensitySum() {
// uint8_t *pixels = getPixels();
// uint32_t sum = 0;
// for(uint16_t i=0; i <numBytes; i++) {
// sum+= pixels[i];
// }
// return sum;
//}
// Return the sum of each color's intensity. Note, the order of
// intensities in the returned array depends on the type of WS2812
// LEDs you have. NEO_GRB LEDs will return an array with entries
// in a different order then NEO_RGB LEDs.
//uint32_t* WS2812FX_intensitySums() {
// static uint32_t intensities[] = { 0, 0, 0, 0 };
// memset(intensities, 0, sizeof(intensities));
// uint8_t *pixels = getPixels();
// uint8_t bytesPerPixel = getNumBytesPerPixel(); // 3=RGB, 4=RGBW
// for(uint16_t i=0; i <numBytes; i += bytesPerPixel) {
// intensities[0] += pixels[i];
// intensities[1] += pixels[i + 1];
// intensities[2] += pixels[i + 2];
// if(bytesPerPixel == 4) intensities[3] += pixels[i + 3]; // for RGBW LEDs
// }
// return intensities;
//}
/* #####################################################
#
# Mode Functions
#
##################################################### */
/*
* No blinking. Just plain old static light.
*/
uint16_t WS2812FX_mode_static(void) {
Adafruit_NeoPixel_fill(_seg->colors[0], _seg->start, _seg_len);
SET_CYCLE;
return _seg->speed;
}
/*
* Blink/strobe function
* Alternate between color1 and color2
* if(strobe == true) then create a strobe effect
*/
uint16_t WS2812FX_blink(uint32_t color1, uint32_t color2, bool strobe) {
if(_seg_rt->counter_mode_call & 1) {
uint32_t color = (IS_REVERSE) ? color1 : color2; // off
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
SET_CYCLE;
return strobe ? _seg->speed - 20 : (_seg->speed / 2);
} else {
uint32_t color = (IS_REVERSE) ? color2 : color1; // on
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
return strobe ? 20 : (_seg->speed / 2);
}
}
/*
* Normal blinking. 50% on/off time.
*/
uint16_t WS2812FX_mode_blink(void) {
return WS2812FX_blink(_seg->colors[0], _seg->colors[1], false);
}
/*
* Classic Blink effect. Cycling through the rainbow.
*/
uint16_t WS2812FX_mode_blink_rainbow(void) {
return WS2812FX_blink(WS2812FX_color_wheel(_seg_rt->counter_mode_call & 0xFF), _seg->colors[1], false);
}
/*
* Classic Strobe effect.
*/
uint16_t WS2812FX_mode_strobe(void) {
return WS2812FX_blink(_seg->colors[0], _seg->colors[1], true);
}
/*
* Classic Strobe effect. Cycling through the rainbow.
*/
uint16_t WS2812FX_mode_strobe_rainbow(void) {
return WS2812FX_blink(WS2812FX_color_wheel(_seg_rt->counter_mode_call & 0xFF), _seg->colors[1], true);
}
/*
* Color wipe function
* LEDs are turned on (color1) in sequence, then turned off (color2) in sequence.
* if (bool rev == true) then LEDs are turned off in reverse order
*/
uint16_t WS2812FX_color_wipe(uint32_t color1, uint32_t color2, bool rev) {
if(_seg_rt->counter_mode_step < _seg_len) {
uint32_t led_offset = _seg_rt->counter_mode_step;
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - led_offset, color1);
} else {
WS2812FX_setPixelColor(_seg->start + led_offset, color1);
}
} else {
uint32_t led_offset = _seg_rt->counter_mode_step - _seg_len;
if((IS_REVERSE && !rev) || (!IS_REVERSE && rev)) {
WS2812FX_setPixelColor(_seg->stop - led_offset, color2);
} else {
WS2812FX_setPixelColor(_seg->start + led_offset, color2);
}
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % (_seg_len * 2);
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / (_seg_len * 2));
}
/*
* Lights all LEDs one after another.
*/
uint16_t WS2812FX_mode_color_wipe(void) {
return WS2812FX_color_wipe(_seg->colors[0], _seg->colors[1], false);
}
uint16_t WS2812FX_mode_color_wipe_inv(void) {
return WS2812FX_color_wipe(_seg->colors[1], _seg->colors[0], false);
}
uint16_t WS2812FX_mode_color_wipe_rev(void) {
return WS2812FX_color_wipe(_seg->colors[0], _seg->colors[1], true);
}
uint16_t WS2812FX_mode_color_wipe_rev_inv(void) {
return WS2812FX_color_wipe(_seg->colors[1], _seg->colors[0], true);
}
/*
* Turns all LEDs after each other to a random color.
* Then starts over with another color.
*/
uint16_t WS2812FX_mode_color_wipe_random(void) {
if(_seg_rt->counter_mode_step % _seg_len == 0) { // aux_param will store our random color wheel index
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param);
}
uint32_t color = WS2812FX_color_wheel(_seg_rt->aux_param);
return WS2812FX_color_wipe(color, color, false) * 2;
}
/*
* Random color introduced alternating from start and end of strip.
*/
uint16_t WS2812FX_mode_color_sweep_random(void) {
if(_seg_rt->counter_mode_step % _seg_len == 0) { // aux_param will store our random color wheel index
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param);
}
uint32_t color = WS2812FX_color_wheel(_seg_rt->aux_param);
return WS2812FX_color_wipe(color, color, true) * 2;
}
/*
* Lights all LEDs in one random color up. Then switches them
* to the next random color.
*/
uint16_t WS2812FX_mode_random_color(void) {
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param); // aux_param will store our random color wheel index
uint32_t color = WS2812FX_color_wheel(_seg_rt->aux_param);
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
SET_CYCLE;
return _seg->speed;
}
/*
* Lights every LED in a random color. Changes one random LED after the other
* to another random color.
*/
uint16_t WS2812FX_mode_single_dynamic(void) {
if(_seg_rt->counter_mode_call == 0) {
for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
WS2812FX_setPixelColor(i, WS2812FX_color_wheel(WS2812FX_random8()));
}
}
WS2812FX_setPixelColor(_seg->start + WS2812FX_random16_lim(_seg_len), WS2812FX_color_wheel(WS2812FX_random8()));
SET_CYCLE;
return _seg->speed;
}
/*
* Lights every LED in a random color. Changes all LED at the same time
* to new random colors.
*/
uint16_t WS2812FX_mode_multi_dynamic(void) {
for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
WS2812FX_setPixelColor(i, WS2812FX_color_wheel(WS2812FX_random8()));
}
SET_CYCLE;
return _seg->speed;
}
/*
* Does the "standby-breathing" of well known i-Devices. Fixed Speed.
* Use mode "fade" if you like to have something similar with a different speed.
*/
uint16_t WS2812FX_mode_breath(void) {
int lum = _seg_rt->counter_mode_step;
if(lum > 255) lum = 511 - lum; // lum = 15 -> 255 -> 15
uint16_t delay;
if(lum == 15) delay = 970; // 970 pause before each breath
else if(lum <= 25) delay = 38; // 19
else if(lum <= 50) delay = 36; // 18
else if(lum <= 75) delay = 28; // 14
else if(lum <= 100) delay = 20; // 10
else if(lum <= 125) delay = 14; // 7
else if(lum <= 150) delay = 11; // 5
else delay = 10; // 4
uint32_t color = WS2812FX_color_blend(_seg->colors[1], _seg->colors[0], lum);
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
_seg_rt->counter_mode_step += 2;
if(_seg_rt->counter_mode_step > (512-15)) {
_seg_rt->counter_mode_step = 15;
SET_CYCLE;
}
return delay;
}
/*
* Fades the LEDs between two colors
*/
uint16_t WS2812FX_mode_fade(void) {
int lum = _seg_rt->counter_mode_step;
if(lum > 255) lum = 511 - lum; // lum = 0 -> 255 -> 0
uint32_t color = WS2812FX_color_blend(_seg->colors[1], _seg->colors[0], lum);
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
_seg_rt->counter_mode_step += 4;
if(_seg_rt->counter_mode_step > 511) {
_seg_rt->counter_mode_step = 0;
SET_CYCLE;
}
return (_seg->speed / 128);
}
/*
* scan function - runs a block of pixels back and forth.
*/
uint16_t WS2812FX_scan(uint32_t color1, uint32_t color2, bool dual) {
int8_t dir = _seg_rt->aux_param ? -1 : 1;
uint8_t size = 1 << SIZE_OPTION;
Adafruit_NeoPixel_fill(color2, _seg->start, _seg_len);
for(uint8_t i = 0; i < size; i++) {
if(IS_REVERSE || dual) {
WS2812FX_setPixelColor(_seg->stop - _seg_rt->counter_mode_step - i, color1);
}
if(!IS_REVERSE || dual) {
WS2812FX_setPixelColor(_seg->start + _seg_rt->counter_mode_step + i, color1);
}
}
_seg_rt->counter_mode_step += dir;
if(_seg_rt->counter_mode_step == 0) {
_seg_rt->aux_param = 0;
SET_CYCLE;
}
if(_seg_rt->counter_mode_step >= (uint16_t)(_seg_len - size)) _seg_rt->aux_param = 1;
return (_seg->speed / (_seg_len * 2));
}
/*
* Runs a block of pixels back and forth.
*/
uint16_t WS2812FX_mode_scan(void) {
return WS2812FX_scan(_seg->colors[0], _seg->colors[1], false);
}
/*
* Runs two blocks of pixels back and forth in opposite directions.
*/
uint16_t WS2812FX_mode_dual_scan(void) {
return WS2812FX_scan(_seg->colors[0], _seg->colors[1], true);
}
/*
* Cycles all LEDs at once through a rainbow.
*/
uint16_t WS2812FX_mode_rainbow(void) {
uint32_t color = WS2812FX_color_wheel(_seg_rt->counter_mode_step);
Adafruit_NeoPixel_fill(color, _seg->start, _seg_len);
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / 256);
}
/*
* Cycles a rainbow over the entire string of LEDs.
*/
uint16_t WS2812FX_mode_rainbow_cycle(void) {
for(uint16_t i=0; i < _seg_len; i++) {
uint32_t color = WS2812FX_color_wheel(((i * 256 / _seg_len) + _seg_rt->counter_mode_step) & 0xFF);
WS2812FX_setPixelColor(_seg->start + i, color);
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / 256);
}
/*
* Tricolor chase function
*/
uint16_t WS2812FX_tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) {
uint8_t sizeCnt = 1 << SIZE_OPTION;
uint8_t sizeCnt2 = sizeCnt + sizeCnt;
uint8_t sizeCnt3 = sizeCnt2 + sizeCnt;
uint16_t index = _seg_rt->counter_mode_step % sizeCnt3;
for(uint16_t i=0; i < _seg_len; i++, index++) {
index = index % sizeCnt3;
uint32_t color = color3;
if(index < sizeCnt) color = color1;
else if(index < sizeCnt2) color = color2;
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->start + i, color);
} else {
WS2812FX_setPixelColor(_seg->stop - i, color);
}
}
_seg_rt->counter_mode_step++;
if(_seg_rt->counter_mode_step % _seg_len == 0) SET_CYCLE;
return (_seg->speed / _seg_len);
}
/*
* Tricolor chase mode
*/
uint16_t WS2812FX_mode_tricolor_chase(void) {
return WS2812FX_tricolor_chase(_seg->colors[0], _seg->colors[1], _seg->colors[2]);
}
/*
* Alternating white/red/black pixels running.
*/
uint16_t WS2812FX_mode_circus_combustus(void) {
return WS2812FX_tricolor_chase(RED, WHITE, BLACK);
}
/*
* Theatre-style crawling lights.
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX_mode_theater_chase(void) {
return WS2812FX_tricolor_chase(_seg->colors[0], _seg->colors[1], _seg->colors[1]);
}
/*
* Theatre-style crawling lights with rainbow effect.
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX_mode_theater_chase_rainbow(void) {
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
uint32_t color = WS2812FX_color_wheel(_seg_rt->counter_mode_step);
return WS2812FX_tricolor_chase(color, _seg->colors[1], _seg->colors[1]);
}
/*
* Running lights effect with smooth sine transition.
*/
uint16_t WS2812FX_mode_running_lights(void) {
uint8_t size = 1 << SIZE_OPTION;
uint8_t sineIncr = max(1, (256 / _seg_len) * size);
for(uint16_t i=0; i < _seg_len; i++) {
int lum = (int)Adafruit_NeoPixel_sine8(((i + _seg_rt->counter_mode_step) * sineIncr));
uint32_t color = WS2812FX_color_blend(_seg->colors[0], _seg->colors[1], lum);
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->start + i, color);
} else {
WS2812FX_setPixelColor(_seg->stop - i, color);
}
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % 256;
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / _seg_len);
}
/*
* twinkle function
*/
uint16_t WS2812FX_twinkle(uint32_t color1, uint32_t color2) {
if(_seg_rt->counter_mode_step == 0) {
Adafruit_NeoPixel_fill(color2, _seg->start, _seg_len);
uint16_t min_leds = (_seg_len / 4) + 1; // make sure, at least one LED is on
_seg_rt->counter_mode_step = WS2812FX_random16_lim(min_leds * 2);//random(min_leds, min_leds * 2);
SET_CYCLE;
}
WS2812FX_setPixelColor(_seg->start + WS2812FX_random16_lim(_seg_len), color1);
_seg_rt->counter_mode_step--;
return (_seg->speed / _seg_len);
}
/*
* Blink several LEDs on, reset, repeat.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX_mode_twinkle(void) {
return WS2812FX_twinkle(_seg->colors[0], _seg->colors[1]);
}
/*
* Blink several LEDs in random colors on, reset, repeat.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX_mode_twinkle_random(void) {
return WS2812FX_twinkle(WS2812FX_color_wheel(WS2812FX_random8()), _seg->colors[1]);
}
/*
* fade out functions
*/
void WS2812FX_fade_out() {
/*return*/ WS2812FX_fade_out_targetColor(_seg->colors[1]);
}
void WS2812FX_fade_out_targetColor(uint32_t targetColor) {
static const uint8_t rateMapH[] = {0, 1, 1, 1, 2, 3, 4, 6};
static const uint8_t rateMapL[] = {0, 2, 3, 8, 8, 8, 8, 8};
uint8_t rate = FADE_RATE;
uint8_t rateH = rateMapH[rate];
uint8_t rateL = rateMapL[rate];
uint32_t color = targetColor;
int w2 = (color >> 24) & 0xff;
int r2 = (color >> 16) & 0xff;
int g2 = (color >> 8) & 0xff;
int b2 = color & 0xff;
for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
color = Adafruit_NeoPixel_getPixelColor(i); // current color
if(rate == 0) { // old fade-to-black algorithm
WS2812FX_setPixelColor(i, (color >> 1) & 0x7F7F7F7F);
} else { // new fade-to-color algorithm
int w1 = (color >> 24) & 0xff;
int r1 = (color >> 16) & 0xff;
int g1 = (color >> 8) & 0xff;
int b1 = color & 0xff;
// calculate the color differences between the current and target colors
int wdelta = w2 - w1;
int rdelta = r2 - r1;
int gdelta = g2 - g1;
int bdelta = b2 - b1;
// if the current and target colors are almost the same, jump right to the target
// color, otherwise calculate an intermediate color. (fixes rounding issues)
wdelta = abs(wdelta) < 3 ? wdelta : (wdelta >> rateH) + (wdelta >> rateL);
rdelta = abs(rdelta) < 3 ? rdelta : (rdelta >> rateH) + (rdelta >> rateL);
gdelta = abs(gdelta) < 3 ? gdelta : (gdelta >> rateH) + (gdelta >> rateL);
bdelta = abs(bdelta) < 3 ? bdelta : (bdelta >> rateH) + (bdelta >> rateL);
WS2812FX_setPixelColor_rgbw(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
}
}
}
/*
* color blend function
*/
uint32_t WS2812FX_color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
if(blend == 0) return color1;
if(blend == 255) return color2;
uint8_t w1 = (color1 >> 24) & 0xff;
uint8_t r1 = (color1 >> 16) & 0xff;
uint8_t g1 = (color1 >> 8) & 0xff;
uint8_t b1 = color1 & 0xff;
uint8_t w2 = (color2 >> 24) & 0xff;
uint8_t r2 = (color2 >> 16) & 0xff;
uint8_t g2 = (color2 >> 8) & 0xff;
uint8_t b2 = color2 & 0xff;
uint32_t w3 = ((w2 * blend) + (w1 * (255U - blend))) / 256U;
uint32_t r3 = ((r2 * blend) + (r1 * (255U - blend))) / 256U;
uint32_t g3 = ((g2 * blend) + (g1 * (255U - blend))) / 256U;
uint32_t b3 = ((b2 * blend) + (b1 * (255U - blend))) / 256U;
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
}
/*
* twinkle_fade function
*/
uint16_t WS2812FX_twinkle_fade(uint32_t color) {
WS2812FX_fade_out();
if(WS2812FX_random8_lim(3) == 0) {
uint8_t size = 1 << SIZE_OPTION;
uint16_t index = _seg->start + WS2812FX_random16_lim(_seg_len - size);
Adafruit_NeoPixel_fill(color, index, size);
SET_CYCLE;
}
return (_seg->speed / 8);
}
/*
* Blink several LEDs on, fading out.
*/
uint16_t WS2812FX_mode_twinkle_fade(void) {
return WS2812FX_twinkle_fade(_seg->colors[0]);
}
/*
* Blink several LEDs in random colors on, fading out.
*/
uint16_t WS2812FX_mode_twinkle_fade_random(void) {
return WS2812FX_twinkle_fade(WS2812FX_color_wheel(WS2812FX_random8()));
}
/*
* Sparkle function
* color1 = background color
* color2 = sparkle color
*/
uint16_t WS2812FX_sparkle(uint32_t color1, uint32_t color2) {
if(_seg_rt->counter_mode_step == 0) {
Adafruit_NeoPixel_fill(color1, _seg->start, _seg_len);
}
uint8_t size = 1 << SIZE_OPTION;
Adafruit_NeoPixel_fill(color1, _seg->start + _seg_rt->aux_param3, size);
_seg_rt->aux_param3 = WS2812FX_random16_lim(_seg_len - size); // aux_param3 stores the random led index
Adafruit_NeoPixel_fill(color2, _seg->start + _seg_rt->aux_param3, size);
SET_CYCLE;
return (_seg->speed / 32);
}
/*
* Blinks one LED at a time.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX_mode_sparkle(void) {
return WS2812FX_sparkle(_seg->colors[1], _seg->colors[0]);
}
/*
* Lights all LEDs in the color. Flashes white pixels randomly.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX_mode_flash_sparkle(void) {
return WS2812FX_sparkle(_seg->colors[0], WHITE);
}
/*
* Like flash sparkle. With more flash.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX_mode_hyper_sparkle(void) {
Adafruit_NeoPixel_fill(_seg->colors[0], _seg->start, _seg_len);
uint8_t size = 1 << SIZE_OPTION;
for(uint8_t i=0; i<8; i++) {
Adafruit_NeoPixel_fill(WHITE, _seg->start + WS2812FX_random16_lim(_seg_len - size), size);
}
SET_CYCLE;
return (_seg->speed / 32);
}
/*
* Strobe effect with different strobe count and pause, controlled by speed.
*/
uint16_t WS2812FX_mode_multi_strobe(void) {
Adafruit_NeoPixel_fill(_seg->colors[1], _seg->start, _seg_len);
uint16_t delay = 200 + ((9 - (_seg->speed % 10)) * 100);
uint16_t count = 2 * ((_seg->speed / 100) + 1);
if(_seg_rt->counter_mode_step < count) {
if((_seg_rt->counter_mode_step & 1) == 0) {
Adafruit_NeoPixel_fill(_seg->colors[0], _seg->start, _seg_len);
delay = 20;
} else {
delay = 50;
}
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % (count + 1);
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return delay;
}
/*
* color chase function.
* color1 = background color
* color2 and color3 = colors of two adjacent leds
*/
uint16_t WS2812FX_chase(uint32_t color1, uint32_t color2, uint32_t color3) {
uint8_t size = 1 << SIZE_OPTION;
for(uint8_t i=0; i<size; i++) {
uint16_t a = (_seg_rt->counter_mode_step + i) % _seg_len;
uint16_t b = (a + size) % _seg_len;
uint16_t c = (b + size) % _seg_len;
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - a, color1);
WS2812FX_setPixelColor(_seg->stop - b, color2);
WS2812FX_setPixelColor(_seg->stop - c, color3);
} else {
WS2812FX_setPixelColor(_seg->start + a, color1);
WS2812FX_setPixelColor(_seg->start + b, color2);
WS2812FX_setPixelColor(_seg->start + c, color3);
}
}
if(_seg_rt->counter_mode_step + (size * 3) == _seg_len) SET_CYCLE;
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
return (_seg->speed / _seg_len);
}
/*
* Bicolor chase mode
*/
uint16_t WS2812FX_mode_bicolor_chase(void) {
return WS2812FX_chase(_seg->colors[0], _seg->colors[1], _seg->colors[2]);
}
/*
* White running on _color.
*/
uint16_t WS2812FX_mode_chase_color(void) {
return WS2812FX_chase(_seg->colors[0], WHITE, WHITE);
}
/*
* Black running on _color.
*/
uint16_t WS2812FX_mode_chase_blackout(void) {
return WS2812FX_chase(_seg->colors[0], BLACK, BLACK);
}
/*
* _color running on white.
*/
uint16_t WS2812FX_mode_chase_white(void) {
return WS2812FX_chase(WHITE, _seg->colors[0], _seg->colors[0]);
}
/*
* White running followed by random color.
*/
uint16_t WS2812FX_mode_chase_random(void) {
if(_seg_rt->counter_mode_step == 0) {
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param);
}
return WS2812FX_chase(WS2812FX_color_wheel(_seg_rt->aux_param), WHITE, WHITE);
}
/*
* Rainbow running on white.
*/
uint16_t WS2812FX_mode_chase_rainbow_white(void) {
uint16_t n = _seg_rt->counter_mode_step;
uint16_t m = (_seg_rt->counter_mode_step + 1) % _seg_len;
uint32_t color2 = WS2812FX_color_wheel(((n * 256 / _seg_len) + (_seg_rt->counter_mode_call & 0xFF)) & 0xFF);
uint32_t color3 = WS2812FX_color_wheel(((m * 256 / _seg_len) + (_seg_rt->counter_mode_call & 0xFF)) & 0xFF);
return WS2812FX_chase(WHITE, color2, color3);
}
/*
* White running on rainbow.
*/
uint16_t WS2812FX_mode_chase_rainbow(void) {
uint8_t color_sep = 256 / _seg_len;
uint8_t color_index = _seg_rt->counter_mode_call & 0xFF;
uint32_t color = WS2812FX_color_wheel(((_seg_rt->counter_mode_step * color_sep) + color_index) & 0xFF);
return WS2812FX_chase(color, WHITE, WHITE);
}
/*
* Black running on rainbow.
*/
uint16_t WS2812FX_mode_chase_blackout_rainbow(void) {
uint8_t color_sep = 256 / _seg_len;
uint8_t color_index = _seg_rt->counter_mode_call & 0xFF;
uint32_t color = WS2812FX_color_wheel(((_seg_rt->counter_mode_step * color_sep) + color_index) & 0xFF);
return WS2812FX_chase(color, BLACK, BLACK);
}
/*
* running white flashes function.
* color1 = background color
* color2 = flash color
*/
uint16_t WS2812FX_chase_flash(uint32_t color1, uint32_t color2) {
const static uint8_t flash_count = 4;
uint8_t flash_step = _seg_rt->counter_mode_call % ((flash_count * 2) + 1);
if(flash_step < (flash_count * 2)) {
uint32_t color = (flash_step % 2 == 0) ? color2 : color1;
uint16_t n = _seg_rt->counter_mode_step;
uint16_t m = (_seg_rt->counter_mode_step + 1) % _seg_len;
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - n, color);
WS2812FX_setPixelColor(_seg->stop - m, color);
} else {
WS2812FX_setPixelColor(_seg->start + n, color);
WS2812FX_setPixelColor(_seg->start + m, color);
}
return 30;
} else {
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
if(_seg_rt->counter_mode_step == 0) {
// update aux_param so mode_chase_flash_random() will select the next color
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param);
SET_CYCLE;
}
}
return (_seg->speed / _seg_len);
}
/*
* White flashes running on _color.
*/
uint16_t WS2812FX_mode_chase_flash(void) {
return WS2812FX_chase_flash(_seg->colors[0], WHITE);
}
/*
* White flashes running, followed by random color.
*/
uint16_t WS2812FX_mode_chase_flash_random(void) {
return WS2812FX_chase_flash(WS2812FX_color_wheel(_seg_rt->aux_param), WHITE);
}
/*
* Alternating pixels running function.
*/
uint16_t WS2812FX_running(uint32_t color1, uint32_t color2) {
uint8_t size = 2 << SIZE_OPTION;
uint32_t color = (_seg_rt->counter_mode_step & size) ? color1 : color2;
if(IS_REVERSE) {
WS2812FX_copyPixels(_seg->start, _seg->start + 1, _seg_len - 1);
WS2812FX_setPixelColor(_seg->stop, color);
} else {
WS2812FX_copyPixels(_seg->start + 1, _seg->start, _seg_len - 1);
WS2812FX_setPixelColor(_seg->start, color);
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / _seg_len);
}
/*
* Alternating color/white pixels running.
*/
uint16_t WS2812FX_mode_running_color(void) {
return WS2812FX_running(_seg->colors[0], _seg->colors[1]);
}
/*
* Alternating red/blue pixels running.
*/
uint16_t WS2812FX_mode_running_red_blue(void) {
return WS2812FX_running(RED, BLUE);
}
/*
* Alternating red/green pixels running.
*/
uint16_t WS2812FX_mode_merry_christmas(void) {
return WS2812FX_running(RED, GREEN);
}
/*
* Alternating orange/purple pixels running.
*/
uint16_t WS2812FX_mode_halloween(void) {
return WS2812FX_running(PURPLE, ORANGE);
}
/*
* Random colored pixels running.
*/
uint16_t WS2812FX_mode_running_random(void) {
uint8_t size = 2 << SIZE_OPTION;
if((_seg_rt->counter_mode_step) % size == 0) {
_seg_rt->aux_param = WS2812FX_get_random_wheel_index(_seg_rt->aux_param);
}
uint32_t color = WS2812FX_color_wheel(_seg_rt->aux_param);
return WS2812FX_running(color, color);
}
/*
* K.I.T.T.
*/
uint16_t WS2812FX_mode_larson_scanner(void) {
WS2812FX_fade_out();
if(_seg_rt->counter_mode_step < _seg_len) {
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - _seg_rt->counter_mode_step, _seg->colors[0]);
} else {
WS2812FX_setPixelColor(_seg->start + _seg_rt->counter_mode_step, _seg->colors[0]);
}
} else {
uint16_t index = (_seg_len * 2) - _seg_rt->counter_mode_step - 2;
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - index, _seg->colors[0]);
} else {
WS2812FX_setPixelColor(_seg->start + index, _seg->colors[0]);
}
}
_seg_rt->counter_mode_step++;
if(_seg_rt->counter_mode_step >= (uint16_t)((_seg_len * 2) - 2)) {
_seg_rt->counter_mode_step = 0;
SET_CYCLE;
}
return (_seg->speed / (_seg_len * 2));
}
/*
* Firing comets from one end.
*/
uint16_t WS2812FX_mode_comet(void) {
WS2812FX_fade_out();
if(IS_REVERSE) {
WS2812FX_setPixelColor(_seg->stop - _seg_rt->counter_mode_step, _seg->colors[0]);
} else {
WS2812FX_setPixelColor(_seg->start + _seg_rt->counter_mode_step, _seg->colors[0]);
}
_seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return (_seg->speed / _seg_len);
}
/*
* Fireworks function.
*/
uint16_t WS2812FX_fireworks(uint32_t color) {
WS2812FX_fade_out();
// for better performance, manipulate the Adafruit_NeoPixels pixels[] array directly
uint8_t *pixels = Adafruit_NeoPixel_getPixels();
uint8_t bytesPerPixel = Adafruit_NeoPixel_getNumBytesPerPixel(); // 3=RGB, 4=RGBW
uint16_t startPixel = _seg->start * bytesPerPixel + bytesPerPixel;
uint16_t stopPixel = _seg->stop * bytesPerPixel ;
for(uint16_t i=startPixel; i <stopPixel; i++) {
uint16_t tmpPixel = (pixels[i - bytesPerPixel] >> 2) +
pixels[i] +
(pixels[i + bytesPerPixel] >> 2);
pixels[i] = tmpPixel > 255 ? 255 : tmpPixel;
}
uint8_t size = 2 << SIZE_OPTION;
if(!_triggered) {
for(uint16_t i=0; i<max(1, _seg_len/20); i++) {
if(WS2812FX_random8_lim(10) == 0) {
uint16_t index = _seg->start + WS2812FX_random16_lim(_seg_len - size);
Adafruit_NeoPixel_fill(color, index, size);
SET_CYCLE;
}
}
} else {
for(uint16_t i=0; i<max(1, _seg_len/10); i++) {
uint16_t index = _seg->start + WS2812FX_random16_lim(_seg_len - size);
Adafruit_NeoPixel_fill(color, index, size);
SET_CYCLE;
}
}
return (_seg->speed / _seg_len);
}
/*
* Firework sparks.
*/
uint16_t WS2812FX_mode_fireworks(void) {
uint32_t color = BLACK;
do { // randomly choose a non-BLACK color from the colors array
color = _seg->colors[WS2812FX_random8_lim(MAX_NUM_COLORS)];
} while (color == BLACK);
return WS2812FX_fireworks(color);
}
/*
* Random colored firework sparks.
*/
uint16_t WS2812FX_mode_fireworks_random(void) {
return WS2812FX_fireworks(WS2812FX_color_wheel(WS2812FX_random8()));
}
/*
* Fire flicker function
*/
uint16_t WS2812FX_fire_flicker(int rev_intensity) {
uint8_t w = (_seg->colors[0] >> 24) & 0xFF;
uint8_t r = (_seg->colors[0] >> 16) & 0xFF;
uint8_t g = (_seg->colors[0] >> 8) & 0xFF;
uint8_t b = (_seg->colors[0] & 0xFF);
uint8_t lum = max(w, max(r, max(g, b))) / rev_intensity;
for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
int flicker = WS2812FX_random8_lim(lum);
WS2812FX_setPixelColor_rgbw(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0));
}
SET_CYCLE;
return (_seg->speed / _seg_len);
}
/*
* Random flickering.
*/
uint16_t WS2812FX_mode_fire_flicker(void) {
return WS2812FX_fire_flicker(3);
}
/*
* Random flickering, less intensity.
*/
uint16_t WS2812FX_mode_fire_flicker_soft(void) {
return WS2812FX_fire_flicker(6);
}
/*
* Random flickering, more intensity.
*/
uint16_t WS2812FX_mode_fire_flicker_intense(void) {
return WS2812FX_fire_flicker(1);
}
移植该库需要建立在移植好Adafruit_NeoPixel库的基础上进行,该库会用到很多Adafruit_NeoPixel库中的接口。
移植该库需要提供获取系统运行时间的函数。此处利用的是STM32HAL库提供的HAL_GetTick()函数。
#define millis HAL_GetTick
为减小rom内存的占用,这里屏蔽掉了各个模式名称的字符串存储。
对于twinkle()函数需要用到的random(min,max)函数尚未实现,暂且使用WS2812_random16_lim()函数替代。