static const char *TAG = "random"; #include #include #include "presets.hpp" #include "utils.hpp" static Color rand_color() { static const Color colors[] = { {255, 0, 0}, { 78, 25, 0}, {255, 160, 0}, { 0, 255, 0}, { 0, 0, 255}, { 38, 10, 42}, }; return colors[esp_random() % 6]; } class RandomPattern : public Pattern { private: struct State : Pattern::State { State(int _len, int gap) : last_us(0), step(0), offset(0), n_colors((_len + gap) / (gap + 1)), colors(new Color[n_colors]) { for (Color *color = colors, *end = colors + n_colors; color < end; ++color) { *color = rand_color(); } } ~State() { delete[] colors; } int64_t last_us; int step; int offset; int n_colors; Color *colors; }; public: RandomPattern(int _delay_ms, int _gap) : delay_us(_delay_ms * 1000), gap(_gap) {} State* start(int len) const { return new State(len, gap); } void step(Color colors[], int len, Pattern::State *_state) const { State *state = (State*)_state; int64_t now_us = time_us(); int64_t elapsed_us = now_us - state->last_us; bool should_step = (state->last_us == 0) || (elapsed_us >= delay_us && delay_us > 0); if (should_step) { state->last_us = (elapsed_us >= delay_us + 100000 ? now_us : state->last_us + delay_us); int step = state->step; int offset = state->offset; Color *inc = state->colors + offset; Color *outc = colors; if ((gap + 1 - step) % (gap + 1) == 0) *inc = rand_color(); for (int i = 0; i < len; i++) { if ((i - step + gap + 1) % (gap + 1) == 0) { *outc = *inc--; if (inc < state->colors) inc += state->n_colors; } else { *outc = {0, 0, 0}; } ++outc; } step++; if (step > gap) { step -= gap + 1; ++offset; if (offset >= state->n_colors) offset -= state->n_colors; state->offset = offset; } state->step = step; } } private: int delay_us; int gap; }; Pattern* json_random_pattern(cJSON *pattern, const Presets::ColorMap &colors) { int delay_ms = 500; int gap = 1; if (pattern->type != cJSON_Object) { ESP_LOGE(TAG, "Not an object: %s", pattern->string); return NULL; } cJSON *jdelay = cJSON_GetObjectItem(pattern, "delay"); if (jdelay) { if (jdelay->type != cJSON_Number) { ESP_LOGE(TAG, "Not a number: %s", jdelay->string); } else { delay_ms = jdelay->valuedouble * 1000.; } } cJSON *jgap = cJSON_GetObjectItem(pattern, "gap"); if (jgap) { if (jgap->type != cJSON_Number) { ESP_LOGE(TAG, "Not a number: %s", jgap->string); } else { gap = jgap->valueint; } } return new RandomPattern(delay_ms, gap); }