You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
7.4 KiB

#include "circular_strip.h"
#include "application.h"
#include <esp_log.h>
#define TAG "CircularStrip"
#define BLINK_INFINITE -1
CircularStrip::CircularStrip(gpio_num_t gpio, uint8_t max_leds) : max_leds_(max_leds) {
// If the gpio is not connected, you should use NoLed class
assert(gpio != GPIO_NUM_NC);
colors_.resize(max_leds_);
led_strip_config_t strip_config = {};
strip_config.strip_gpio_num = gpio;
strip_config.max_leds = max_leds_;
strip_config.led_pixel_format = LED_PIXEL_FORMAT_GRB;
strip_config.led_model = LED_MODEL_WS2812;
led_strip_rmt_config_t rmt_config = {};
rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_));
led_strip_clear(led_strip_);
esp_timer_create_args_t strip_timer_args = {
.callback = [](void *arg) {
auto strip = static_cast<CircularStrip*>(arg);
std::lock_guard<std::mutex> lock(strip->mutex_);
if (strip->strip_callback_ != nullptr) {
strip->strip_callback_();
}
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
.name = "strip_timer",
.skip_unhandled_events = false,
};
ESP_ERROR_CHECK(esp_timer_create(&strip_timer_args, &strip_timer_));
}
CircularStrip::~CircularStrip() {
esp_timer_stop(strip_timer_);
if (led_strip_ != nullptr) {
led_strip_del(led_strip_);
}
}
void CircularStrip::SetAllColor(StripColor color) {
std::lock_guard<std::mutex> lock(mutex_);
esp_timer_stop(strip_timer_);
for (int i = 0; i < max_leds_; i++) {
colors_[i] = color;
led_strip_set_pixel(led_strip_, i, color.red, color.green, color.blue);
}
led_strip_refresh(led_strip_);
}
void CircularStrip::SetSingleColor(uint8_t index, StripColor color) {
std::lock_guard<std::mutex> lock(mutex_);
esp_timer_stop(strip_timer_);
colors_[index] = color;
led_strip_set_pixel(led_strip_, index, color.red, color.green, color.blue);
led_strip_refresh(led_strip_);
}
void CircularStrip::Blink(StripColor color, int interval_ms) {
for (int i = 0; i < max_leds_; i++) {
colors_[i] = color;
}
StartStripTask(interval_ms, [this]() {
static bool on = true;
if (on) {
for (int i = 0; i < max_leds_; i++) {
led_strip_set_pixel(led_strip_, i, colors_[i].red, colors_[i].green, colors_[i].blue);
}
led_strip_refresh(led_strip_);
} else {
led_strip_clear(led_strip_);
}
on = !on;
});
}
void CircularStrip::FadeOut(int interval_ms) {
StartStripTask(interval_ms, [this]() {
bool all_off = true;
for (int i = 0; i < max_leds_; i++) {
colors_[i].red /= 2;
colors_[i].green /= 2;
colors_[i].blue /= 2;
if (colors_[i].red != 0 || colors_[i].green != 0 || colors_[i].blue != 0) {
all_off = false;
}
led_strip_set_pixel(led_strip_, i, colors_[i].red, colors_[i].green, colors_[i].blue);
}
if (all_off) {
led_strip_clear(led_strip_);
esp_timer_stop(strip_timer_);
} else {
led_strip_refresh(led_strip_);
}
});
}
void CircularStrip::Breathe(StripColor low, StripColor high, int interval_ms) {
StartStripTask(interval_ms, [this, low, high]() {
static bool increase = true;
static StripColor color = low;
if (increase) {
if (color.red < high.red) {
color.red++;
}
if (color.green < high.green) {
color.green++;
}
if (color.blue < high.blue) {
color.blue++;
}
if (color.red == high.red && color.green == high.green && color.blue == high.blue) {
increase = false;
}
} else {
if (color.red > low.red) {
color.red--;
}
if (color.green > low.green) {
color.green--;
}
if (color.blue > low.blue) {
color.blue--;
}
if (color.red == low.red && color.green == low.green && color.blue == low.blue) {
increase = true;
}
}
for (int i = 0; i < max_leds_; i++) {
led_strip_set_pixel(led_strip_, i, color.red, color.green, color.blue);
}
led_strip_refresh(led_strip_);
});
}
void CircularStrip::Scroll(StripColor low, StripColor high, int length, int interval_ms) {
for (int i = 0; i < max_leds_; i++) {
colors_[i] = low;
}
StartStripTask(interval_ms, [this, low, high, length]() {
static int offset = 0;
for (int i = 0; i < max_leds_; i++) {
colors_[i] = low;
}
for (int j = 0; j < length; j++) {
int i = (offset + j) % max_leds_;
colors_[i] = high;
}
for (int i = 0; i < max_leds_; i++) {
led_strip_set_pixel(led_strip_, i, colors_[i].red, colors_[i].green, colors_[i].blue);
}
led_strip_refresh(led_strip_);
offset = (offset + 1) % max_leds_;
});
}
void CircularStrip::StartStripTask(int interval_ms, std::function<void()> cb) {
if (led_strip_ == nullptr) {
return;
}
std::lock_guard<std::mutex> lock(mutex_);
esp_timer_stop(strip_timer_);
strip_callback_ = cb;
esp_timer_start_periodic(strip_timer_, interval_ms * 1000);
}
void CircularStrip::SetBrightness(uint8_t default_brightness, uint8_t low_brightness) {
default_brightness_ = default_brightness;
low_brightness_ = low_brightness;
OnStateChanged();
}
void CircularStrip::OnStateChanged() {
auto& app = Application::GetInstance();
auto device_state = app.GetDeviceState();
switch (device_state) {
case kDeviceStateStarting: {
StripColor low = { 0, 0, 0 };
StripColor high = { low_brightness_, low_brightness_, default_brightness_ };
Scroll(low, high, 3, 100);
break;
}
case kDeviceStateWifiConfiguring: {
StripColor color = { low_brightness_, low_brightness_, default_brightness_ };
Blink(color, 500);
break;
}
case kDeviceStateIdle:
FadeOut(50);
break;
case kDeviceStateConnecting: {
StripColor color = { low_brightness_, low_brightness_, default_brightness_ };
SetAllColor(color);
break;
}
case kDeviceStateListening: {
StripColor color = { default_brightness_, low_brightness_, low_brightness_ };
SetAllColor(color);
break;
}
case kDeviceStateSpeaking: {
StripColor color = { low_brightness_, default_brightness_, low_brightness_ };
SetAllColor(color);
break;
}
case kDeviceStateUpgrading: {
StripColor color = { low_brightness_, default_brightness_, low_brightness_ };
Blink(color, 100);
break;
}
case kDeviceStateActivating: {
StripColor color = { low_brightness_, default_brightness_, low_brightness_ };
Blink(color, 500);
break;
}
default:
ESP_LOGW(TAG, "Unknown led strip event: %d", device_state);
return;
}
}