esp32-sk6812/src/main.cpp

243 lines
5.7 KiB
C++

#include <array>
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <SPIFFS.h>
#include "WebServer.h"
#include "Fader.h"
#include "UDPProto.h"
#include "Config.h"
#include <esp32_digital_led_lib.h>
#include <esp32_digital_led_funcs.h>
const uint32_t FRAME_INTERVAL_US = 16666;
const uint32_t NUM_STRIPS = 8;
const uint32_t NUM_LEDS = 16;
const uint32_t FLIP_STRIPS_MASK = 0x000000AA;
std::array<strand_t, 1> STRANDS { // Avoid using any of the strapping pins on the ESP32, anything >=32, 16, 17... not much left.
strand_t {.rmtChannel = 0, .gpioNum = 4, .ledType = LED_SK6812W_V1, .brightLimit = 32, .numPixels = NUM_LEDS * NUM_STRIPS},
};
bool led_on = false;
size_t led_idx;
size_t frame;
WiFiMulti wiFiMulti;
Fader ledFader(NUM_STRIPS, NUM_LEDS, 1, FLIP_STRIPS_MASK);
UDPProto udpProto(&ledFader);
bool initLEDs()
{
/****************************************************************************
If you have multiple strands connected, but not all are in use, the
GPIO power-on defaults for the unused strand data lines will typically be
high-impedance. Unless you are pulling the data lines high or low via a
resistor, this will lead to noise on those unused but connected channels
and unwanted driving of those unallocated strands.
This optional gpioSetup() code helps avoid that problem programmatically.
****************************************************************************/
digitalLeds_initDriver();
for (int i = 0; i < STRANDS.size(); i++) {
gpioSetup(STRANDS[i].gpioNum, OUTPUT, LOW);
}
strand_t *strands[STRANDS.size()];
for (int i = 0; i < STRANDS.size(); i++)
{
strands[i] = &STRANDS[i];
}
int rc = digitalLeds_addStrands(strands, STRANDS.size());
if (rc)
{
Serial.print("Init rc = ");
Serial.println(rc);
return false;
}
for (int i = 0; i < STRANDS.size(); i++)
{
strand_t *pStrand = strands[i];
Serial.print("Strand ");
Serial.print(i);
Serial.print(" = ");
Serial.print((uint32_t)(pStrand->pixels), HEX);
Serial.println();
#if DEBUG_ESP32_DIGITAL_LED_LIB
dumpDebugBuffer(-2, digitalLeds_debugBuffer);
#endif
}
led_idx = 0;
frame = 0;
return true;
}
static void ledTask( void * parameter )
{
/* loop forever */
for(;;){
uint32_t start_time = micros();
if(WiFi.status() == WL_CONNECTED) {
udpProto.loop();
}
led_idx++;
if(led_idx >= STRANDS[0].numPixels) {
led_idx = 0;
}
strand_t *strands[STRANDS.size()];
for (int i = 0; i < STRANDS.size(); i++)
{
strands[i] = &STRANDS[i];
}
ledFader.update();
if(ledFader.something_changed()) {
const std::vector<Fader::Color> &colors = ledFader.get_color_values();
for (size_t i = 0; i < STRANDS[0].numPixels; i++) {
const Fader::Color &c = colors[i];
STRANDS[0].pixels[i] = pixelFromRGBW(c.r, c.g, c.b, c.w);
}
}
digitalLeds_drawPixels(strands, 1);
frame++;
uint32_t now = micros();
uint32_t duration = now - start_time;
if(frame % 50 == 0) {
uint32_t load = 100 * duration / FRAME_INTERVAL_US;
Serial.print("CPU Load: ");
Serial.print(load);
Serial.println(" %");
}
if(duration < FRAME_INTERVAL_US) {
delayMicroseconds(FRAME_INTERVAL_US - duration);
}
}
/* delete a task when finish,
this will never happen because this is infinity loop */
vTaskDelete( NULL );
}
void wifi_setup(void)
{
Serial.println("Trying to connect...");
for(size_t tries = 0; tries < 10; tries++)
{
if(wiFiMulti.run() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
break;
}
led_on = !led_on;
digitalWrite(2, led_on);
delay(100);
Serial.print(".");
}
if(WiFi.status() != WL_CONNECTED) {
Serial.println("Connection failed, setting up access point...");
IPAddress apIP(192, 168, 42, 1);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP("🕯️💡☀️", "Licht234");
WiFi.enableAP(true);
}
}
void setup()
{
pinMode(2, OUTPUT); // On-Board LED
Serial.begin(115200);
delay(10);
if(!initLEDs()) {
Serial.println("LED setup failed!");
while(true) {
delay(100);
}
}
if(!SPIFFS.begin()) {
Serial.println("SPIFFS setup failed!");
while(true) {
delay(100);
}
}
// load configuration (especially crypto data)
Config::instance().load();
digitalWrite(2, HIGH);
Serial.println();
Serial.println();
ledFader.set_color(Fader::Color{64,0,0,0});
ledFader.fade_color(Fader::Color{0,64,0,0});
xTaskCreate(
ledTask, /* Task function. */
"LED Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
NULL); /* Task handle to keep track of created task */
// Connect the WiFi network (or start an AP if that doesn't work)
for (auto &net : Config::instance().getWLANList())
{
Serial.print("Adding network ");
Serial.println(net.ssid.c_str());
wiFiMulti.addAP(net.ssid.c_str(), net.password.c_str());
}
wifi_setup();
// start the UDP server
udpProto.start(2703);
// start the web server
WebServer::instance().setFader(&ledFader);
WebServer::instance().start();
}
void loop() {
led_on = !led_on;
digitalWrite(2, led_on);
delay(500);
// reconnect WiFi when connection is lost
if(WiFi.status() == WL_CONNECTION_LOST) {
Serial.println("WLAN disconnected. Restarting setup.");
wifi_setup();
}
}