Compare commits
9 Commits
5b70511570
...
1754f49b68
Author | SHA1 | Date | |
---|---|---|---|
1754f49b68 | |||
0b80b74be3 | |||
33c2417534 | |||
bf1666fb32 | |||
0d23e5ec6c | |||
a05931d7f9 | |||
a6cd94e416 | |||
2ddd77eb5c | |||
1122546853 |
@ -4,6 +4,8 @@
|
|||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
|
|
||||||
class Window {
|
class Window {
|
||||||
|
private:
|
||||||
|
void _circle_point(int x0, int y0, int x1, int y1, CRGB* color);
|
||||||
public:
|
public:
|
||||||
const uint8_t x, y;
|
const uint8_t x, y;
|
||||||
const uint8_t width, height;
|
const uint8_t width, height;
|
||||||
|
@ -42,6 +42,9 @@
|
|||||||
#define FPS 50
|
#define FPS 50
|
||||||
#define SHOW_TEXT_DELAY 100
|
#define SHOW_TEXT_DELAY 100
|
||||||
|
|
||||||
|
#define RECORDER_ENABLE
|
||||||
|
#define RECORDER_PORT 2122
|
||||||
|
|
||||||
#define MONITOR_LOOP_TIMES false
|
#define MONITOR_LOOP_TIMES false
|
||||||
#define MONITOR_LOOP_TIME_THRESHOLD 500
|
#define MONITOR_LOOP_TIME_THRESHOLD 500
|
||||||
#define MONITOR_LOOP_TIME_COUNT_MAX 10
|
#define MONITOR_LOOP_TIME_COUNT_MAX 10
|
||||||
|
@ -5,17 +5,11 @@
|
|||||||
|
|
||||||
class BigClockEffect : public Effect {
|
class BigClockEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
CRGB color_h = CRGB(0xFF0000);
|
CRGB _color_font = CRGB(0xAAAAAA);
|
||||||
CRGB color_m = CRGB(0x00FF00);
|
CRGB _color_seconds = CRGB(0xFF0000);
|
||||||
CRGB color_colon = CRGB(0xFFFF00);
|
|
||||||
|
|
||||||
void drawNumber(uint8_t number, int x, int y, CRGB color);
|
void _draw_seconds();
|
||||||
|
void _draw_border_pixel(uint8_t second, CRGB* color);
|
||||||
void drawText(char *text, int x, int y, CRGB color);
|
|
||||||
|
|
||||||
const unsigned char* font_char(const unsigned char* font, char c);
|
|
||||||
|
|
||||||
void drawSprite(const unsigned char* sprite, int xOffset, int yOffset, CRGB color);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void loop();
|
void loop();
|
||||||
|
@ -51,7 +51,6 @@ public:
|
|||||||
class MatrixEffect : public Effect {
|
class MatrixEffect : public Effect {
|
||||||
protected:
|
protected:
|
||||||
MatrixEffectColumn** _columns;
|
MatrixEffectColumn** _columns;
|
||||||
virtual void _init();
|
|
||||||
public:
|
public:
|
||||||
boolean can_be_shown_with_clock();
|
boolean can_be_shown_with_clock();
|
||||||
MatrixEffect();
|
MatrixEffect();
|
||||||
@ -60,11 +59,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class RainbowMatrixEffect : public MatrixEffect {
|
class RainbowMatrixEffect : public MatrixEffect {
|
||||||
private:
|
public:
|
||||||
void _init() override;
|
RainbowMatrixEffect();
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomMatrixEffect : public MatrixEffect {
|
class RandomMatrixEffect : public MatrixEffect {
|
||||||
private:
|
public:
|
||||||
void _init() override;
|
RandomMatrixEffect();
|
||||||
};
|
};
|
||||||
|
@ -7,8 +7,9 @@
|
|||||||
class TwirlEffect : public Effect {
|
class TwirlEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
uint8_t angleOffset = 0;
|
uint8_t angleOffset = 0;
|
||||||
double center_x = 8;
|
uint8_t _center_offset_angle = 0;
|
||||||
double center_y = 8;
|
double _real_center_x = LED_WIDTH / 2;
|
||||||
|
double _real_center_y = LED_HEIGHT / 2;
|
||||||
public:
|
public:
|
||||||
void loop();
|
void loop();
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef effects_H
|
#ifndef effects_H
|
||||||
#define effects_H
|
#define effects_H
|
||||||
|
|
||||||
#include <SimpleList.h>
|
|
||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "effect_clock.h"
|
#include "effect_clock.h"
|
||||||
|
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
|
|
||||||
extern Font font_numbers3x5;
|
extern Font font_numbers3x5;
|
||||||
|
extern Font font_numbers3x5_blocky;
|
||||||
extern Font font_numbers4x7;
|
extern Font font_numbers4x7;
|
||||||
|
21
include/recorder.h
Normal file
21
include/recorder.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "my_wifi.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
#ifdef RECORDER_ENABLE
|
||||||
|
class Recorder {
|
||||||
|
private:
|
||||||
|
WiFiUDP _udp;
|
||||||
|
AsyncServer* _server;
|
||||||
|
AsyncClient* _client = NULL;
|
||||||
|
uint16_t _client_port = 0;
|
||||||
|
size_t _buffer_len;
|
||||||
|
char* _buffer;
|
||||||
|
uint16_t _msgid;
|
||||||
|
public:
|
||||||
|
Recorder();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
#endif
|
@ -19,6 +19,7 @@ lib_deps =
|
|||||||
https://github.com/fabianonline/NTPClient.git
|
https://github.com/fabianonline/NTPClient.git
|
||||||
ESP8266WebServer
|
ESP8266WebServer
|
||||||
ErriezCRC32
|
ErriezCRC32
|
||||||
|
ESPAsyncTCP
|
||||||
|
|
||||||
[env:ota]
|
[env:ota]
|
||||||
upload_port = 10.10.2.78
|
upload_port = 10.10.2.78
|
||||||
|
@ -68,54 +68,52 @@ void Window::fadeToBlackBy(fract8 speed) {
|
|||||||
|
|
||||||
void Window::line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, CRGB* color) {
|
void Window::line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, CRGB* color) {
|
||||||
// Bresenham algorithm
|
// Bresenham algorithm
|
||||||
int16_t dx = abs(x2-x1);
|
int dx = x2-x1;
|
||||||
int16_t dy = abs(y2-y1);
|
int dy = y2-y1;
|
||||||
int8_t sx = x1<x2 ? 1 : -1;
|
|
||||||
int8_t sy = y1<y2 ? 1 : -1;
|
int x = x1;
|
||||||
int16_t err = dx + dy;
|
int y = y1;
|
||||||
int16_t e2;
|
|
||||||
|
int p = 2*dy - dx;
|
||||||
while (1) {
|
|
||||||
setPixel(x1, y1, color);
|
while (x < x2) {
|
||||||
if (x1==x2 && y1==y2) break;
|
if (p >= 0) {
|
||||||
e2 = 2*err;
|
setPixel(x, y, color);
|
||||||
if (e2 > dy) { err += dy; x1 += sx; }
|
y++;
|
||||||
if (e2 < dx) { err += dx; y1 += sy; }
|
p = p + 2*dy - 2*dx;
|
||||||
|
} else {
|
||||||
|
setPixel(x, y, color);
|
||||||
|
p = p + 2*dy;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::_circle_point(int x0, int y0, int x1, int y1, CRGB* color) {
|
||||||
|
setPixel(x0+x1, y0+y1, color);
|
||||||
|
setPixel(x0-x1, y0+y1, color);
|
||||||
|
setPixel(x0+x1, y0-y1, color);
|
||||||
|
setPixel(x0-x1, y0-y1, color);
|
||||||
|
setPixel(x0+y1, y0+x1, color);
|
||||||
|
setPixel(x0-y1, y0+x1, color);
|
||||||
|
setPixel(x0+y1, y0-x1, color);
|
||||||
|
setPixel(x0-y1, y0-x1, color);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::circle(uint8_t x0, uint8_t y0, uint8_t radius, CRGB* color) {
|
void Window::circle(uint8_t x0, uint8_t y0, uint8_t radius, CRGB* color) {
|
||||||
// Again, Bresenham
|
// Again, Bresenham
|
||||||
uint8_t f = 1 - radius;
|
int x=0, y=radius;
|
||||||
int16_t ddF_x = 0;
|
int d=3 - 2*radius;
|
||||||
int16_t ddF_y = -2 * radius;
|
_circle_point(x0, y0, x, y, color);
|
||||||
uint8_t x = 0;
|
while (y >= x) {
|
||||||
uint8_t y = radius;
|
|
||||||
|
|
||||||
setPixel(x0, y0 + radius, color);
|
|
||||||
setPixel(x0, y0 - radius, color);
|
|
||||||
setPixel(x0 + radius, y0, color);
|
|
||||||
setPixel(x0 - radius, y0, color);
|
|
||||||
|
|
||||||
while (x < y) {
|
|
||||||
if (f >= 0) {
|
|
||||||
y--;
|
|
||||||
ddF_y += 2;
|
|
||||||
f += ddF_y;
|
|
||||||
}
|
|
||||||
x++;
|
x++;
|
||||||
ddF_x += 2;
|
if (d>0) {
|
||||||
f += ddF_x + 1;
|
y--;
|
||||||
|
d = d + 4*(x-y) + 10;
|
||||||
setPixel(x0 + x, y0 + y, color);
|
} else {
|
||||||
setPixel(x0 - x, y0 + y, color);
|
d = d + 4*x + 6;
|
||||||
setPixel(x0 + x, y0 - y, color);
|
}
|
||||||
setPixel(x0 - x, y0 - y, color);
|
_circle_point(x0, y0, x, y, color);
|
||||||
|
|
||||||
setPixel(x0 + y, y0 + x, color);
|
|
||||||
setPixel(x0 - y, y0 + x, color);
|
|
||||||
setPixel(x0 + y, y0 - x, color);
|
|
||||||
setPixel(x0 - y, y0 - x, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,21 +3,54 @@
|
|||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include "ntp.h"
|
#include "ntp.h"
|
||||||
|
|
||||||
void BigClockEffect::drawNumber(uint8_t number, int x, int y, CRGB color) {
|
|
||||||
char buffer[7];
|
|
||||||
sprintf(buffer, "%02d", number);
|
|
||||||
drawText(buffer, x, y, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BigClockEffect::drawText(char *text, int x, int y, CRGB color) {
|
|
||||||
for (uint8_t i = 0; i < strlen(text); i++) {
|
|
||||||
window->drawChar(&font_numbers4x7, text[i], x + i * 4, y, &color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BigClockEffect::loop() {
|
void BigClockEffect::loop() {
|
||||||
window->clear();
|
window->clear();
|
||||||
drawNumber(ntpClient.getHours(), 0, 0, color_h);
|
uint8_t h = ntpClient.getHours();
|
||||||
drawNumber(ntpClient.getMinutes(), 8, 0, color_m);
|
window->drawChar(&font_numbers3x5_blocky, 6, 2, '0' + (h / 10), &_color_font);
|
||||||
drawNumber(ntpClient.getSeconds(), 8, 8, color_colon);
|
window->drawChar(&font_numbers3x5_blocky, 11, 2, '0' + (h % 10), &_color_font);
|
||||||
|
|
||||||
|
uint8_t m = ntpClient.getMinutes();
|
||||||
|
window->drawChar(&font_numbers3x5_blocky, 6, 9, '0' + (m / 10), &_color_font);
|
||||||
|
window->drawChar(&font_numbers3x5_blocky, 11, 9, '0' + (m % 10), &_color_font);
|
||||||
|
|
||||||
|
uint8_t s = ntpClient.getSeconds();
|
||||||
|
if (s & 1) {
|
||||||
|
window->setPixel(3, 10, &_color_font);
|
||||||
|
window->setPixel(3, 12, &_color_font);
|
||||||
|
}
|
||||||
|
|
||||||
|
_draw_seconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BigClockEffect::_draw_seconds() {
|
||||||
|
uint8_t seconds = ntpClient.getSeconds();
|
||||||
|
for (int i=1; i<=seconds; i++) {
|
||||||
|
_draw_border_pixel(i, &_color_seconds);
|
||||||
|
}
|
||||||
|
uint16_t millis = ntpClient.getEpochMillis() % 1000;
|
||||||
|
if (millis > 0) {
|
||||||
|
uint8_t part = 60 - ((60 - seconds) * millis / 1000);
|
||||||
|
_draw_border_pixel(part, &_color_seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BigClockEffect::_draw_border_pixel(uint8_t i, CRGB* color) {
|
||||||
|
uint8_t x, y;
|
||||||
|
if (i<=8) {
|
||||||
|
x = 7 + i;
|
||||||
|
y = 0;
|
||||||
|
} else if (i<=23) {
|
||||||
|
x = 15;
|
||||||
|
y = i - 8;
|
||||||
|
} else if (i<= 38) {
|
||||||
|
x = 15 - i + 23;
|
||||||
|
y = 15;
|
||||||
|
} else if (i <= 53) {
|
||||||
|
x = 0;
|
||||||
|
y = 15 - i + 38;
|
||||||
|
} else {
|
||||||
|
x = i - 53;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
window->setPixel(x, y, color);
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ void MatrixEffectColumn::draw() {
|
|||||||
int8_t ydir = 0;
|
int8_t ydir = 0;
|
||||||
switch (_direction) {
|
switch (_direction) {
|
||||||
case DIR_NORTH: ydir = 1; break;
|
case DIR_NORTH: ydir = 1; break;
|
||||||
case DIR_EAST: xdir = 1; break;
|
case DIR_EAST: xdir = -1; break;
|
||||||
case DIR_SOUTH: ydir = -1; break;
|
case DIR_SOUTH: ydir = -1; break;
|
||||||
case DIR_WEST: xdir = -1; break;
|
case DIR_WEST: xdir = 1; break;
|
||||||
}
|
}
|
||||||
for(int i=0; i<length; i++) {
|
for(int i=0; i<length; i++) {
|
||||||
CRGB color = _getColor(i);
|
CRGB color = _getColor(i);
|
||||||
@ -144,18 +144,16 @@ boolean MatrixEffect::can_be_shown_with_clock() { return true; };
|
|||||||
|
|
||||||
MatrixEffect::MatrixEffect() {
|
MatrixEffect::MatrixEffect() {
|
||||||
_columns = new MatrixEffectColumn* [window->width];
|
_columns = new MatrixEffectColumn* [window->width];
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MatrixEffect::_init() {
|
|
||||||
for (int i=0; i<window->width; i++) _columns[i] = new MatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
|
for (int i=0; i<window->width; i++) _columns[i] = new MatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomMatrixEffect::_init() {
|
RandomMatrixEffect::RandomMatrixEffect() {
|
||||||
|
_columns = new MatrixEffectColumn* [window->width];
|
||||||
for (int i=0; i<window->width; i++) _columns[i] = new RandomMatrixEffectColumn(window, random8(4), true);
|
for (int i=0; i<window->width; i++) _columns[i] = new RandomMatrixEffectColumn(window, random8(4), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RainbowMatrixEffect::_init() {
|
RainbowMatrixEffect::RainbowMatrixEffect() {
|
||||||
|
_columns = new MatrixEffectColumn* [window->width];
|
||||||
for (int i=0; i<window->width; i++) _columns[i] = new RainbowMatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
|
for (int i=0; i<window->width; i++) _columns[i] = new RainbowMatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,16 @@
|
|||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
void TwirlEffect::loop() {
|
void TwirlEffect::loop() {
|
||||||
|
double center_x = _real_center_x; // - (cos8(_center_offset_angle)>>6);
|
||||||
|
double center_y = _real_center_y; // + (sin8(_center_offset_angle)>>6);
|
||||||
for (int x=0; x<window->width; x++) for (int y=0; y<window->height; y++) {
|
for (int x=0; x<window->width; x++) for (int y=0; y<window->height; y++) {
|
||||||
uint8_t angle = (x==center_x && y==center_y) ? 0 : atan2(y - center_y, x - center_x) / M_PI * 128 + 128 + angleOffset;
|
uint8_t angle = atan2(y - center_y, x - center_x) / M_PI * 128 + 128 + angleOffset;
|
||||||
uint8_t brightness = sqrt16((center_x - x) * (center_x - x) + (center_y - y) * (center_y - y)) & 0xFF;
|
uint16_t distance = sqrt16((center_x - x) * (center_x - x) + (center_y - y) * (center_y - y));
|
||||||
CRGB color(CHSV(angle, (brightness<<5) & 0xFF, 255));
|
if (distance > 255) distance = 255;
|
||||||
|
angle -= distance << 2;
|
||||||
|
CRGB color(CHSV(angle, 255, 255 - distance*16));
|
||||||
window->setPixel(x, y, &color);
|
window->setPixel(x, y, &color);
|
||||||
}
|
}
|
||||||
angleOffset += 1;
|
angleOffset += 1;
|
||||||
|
if (angleOffset % 17 == 0) _center_offset_angle++;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ bool change_current_effect(String payload) {
|
|||||||
LOGln("Effects * Could not find effect with name %s", payload.c_str());
|
LOGln("Effects * Could not find effect with name %s", payload.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
LOGln("Effects * Switching to effect %s", payload.c_str());
|
||||||
delete current_effect;
|
delete current_effect;
|
||||||
current_effect = new_effect;
|
current_effect = new_effect;
|
||||||
|
|
||||||
@ -91,8 +92,16 @@ bool change_current_effect(String payload) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cycle_effects[] = {"sinematrix3", "multi_dynamic", "matrix", "confetti", "single_dynamic", "snake", "gol"};
|
const char* cycle_effects[] = {
|
||||||
uint8_t cycle_effects_count = 7;
|
"sinematrix3",
|
||||||
|
"multi_dynamic",
|
||||||
|
"matrix", "rainbow_matrix", "random_matrix",
|
||||||
|
"confetti", "random_confetti",
|
||||||
|
"single_dynamic",
|
||||||
|
"snake",
|
||||||
|
"gol",
|
||||||
|
"twirl"};
|
||||||
|
uint8_t cycle_effects_count = 11;
|
||||||
|
|
||||||
void setup_effects() {
|
void setup_effects() {
|
||||||
current_effect = new CycleEffect();
|
current_effect = new CycleEffect();
|
||||||
|
@ -10,14 +10,26 @@ const uint8_t font_numbers3x5_data[] PROGMEM = {
|
|||||||
B01110, B10101, B10110, // 6
|
B01110, B10101, B10110, // 6
|
||||||
B10000, B10011, B11100, // 7
|
B10000, B10011, B11100, // 7
|
||||||
B11111, B10101, B11111, // 8
|
B11111, B10101, B11111, // 8
|
||||||
|
B01101, B10101, B01110, // 9
|
||||||
|
};
|
||||||
|
bool font_numbers3x5_check(const char c) { return c>='0' && c<='9'; }
|
||||||
|
uint16_t font_numbers3x5_get(const char c) { return c - '0'; }
|
||||||
|
Font font_numbers3x5 = {3, 5, &font_numbers3x5_data[0], font_numbers3x5_check, font_numbers3x5_get};
|
||||||
|
|
||||||
|
const uint8_t font_numbers3x5_blocky_data[] PROGMEM = {
|
||||||
|
B11111, B10001, B11111, // 0
|
||||||
|
B00000, B11111, B00000, // 1
|
||||||
|
B10111, B10101, B11101, // 2
|
||||||
|
B10001, B10101, B11111, // 3
|
||||||
|
B11100, B00100, B11111, // 4
|
||||||
|
B11101, B10101, B11111, // 5
|
||||||
|
B11111, B10101, B10111, // 6
|
||||||
|
B10000, B10000, B11111, // 7
|
||||||
|
B11111, B10101, B11111, // 8
|
||||||
B11101, B10101, B11111, // 9
|
B11101, B10101, B11111, // 9
|
||||||
};
|
};
|
||||||
|
Font font_numbers3x5_blocky = {3, 5, &font_numbers3x5_blocky_data[0], font_numbers3x5_check, font_numbers3x5_get};
|
||||||
|
|
||||||
bool font_numbers3x5_check(const char c) { return c>='0' && c<='9'; }
|
|
||||||
|
|
||||||
uint16_t font_numbers3x5_get(const char c) { return c - '0'; }
|
|
||||||
|
|
||||||
Font font_numbers3x5 = {3, 5, &font_numbers3x5_data[0], font_numbers3x5_check, font_numbers3x5_get};
|
|
||||||
|
|
||||||
const uint8_t font_numbers4x7_data[] PROGMEM = {
|
const uint8_t font_numbers4x7_data[] PROGMEM = {
|
||||||
0x3E, 0x51, 0x45, 0x3E,// 0
|
0x3E, 0x51, 0x45, 0x3E,// 0
|
||||||
|
@ -9,12 +9,16 @@
|
|||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "effects.h"
|
#include "effects.h"
|
||||||
#include "http_server.h"
|
#include "http_server.h"
|
||||||
|
#include "recorder.h"
|
||||||
|
|
||||||
uint8_t starting_up = OTA_STARTUP_DELAY;
|
uint8_t starting_up = OTA_STARTUP_DELAY;
|
||||||
int loop_timeouts = 0;
|
int loop_timeouts = 0;
|
||||||
long loop_started_at = 0;
|
long loop_started_at = 0;
|
||||||
uint8_t baseHue = 0; // defined as extern in prototypes.h
|
uint8_t baseHue = 0; // defined as extern in prototypes.h
|
||||||
char hostname[30]; // defined as extern in prototypes.h
|
char hostname[30]; // defined as extern in prototypes.h
|
||||||
|
#ifdef RECORDER_ENABLE
|
||||||
|
Recorder* recorder;
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(74880);
|
Serial.begin(74880);
|
||||||
@ -40,6 +44,9 @@ void setup() {
|
|||||||
#ifdef MQTT_ENABLE
|
#ifdef MQTT_ENABLE
|
||||||
mqtt_setup();
|
mqtt_setup();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef RECORDER_ENABLE
|
||||||
|
recorder = new Recorder();
|
||||||
|
#endif
|
||||||
SPIFFS.begin();
|
SPIFFS.begin();
|
||||||
LOGln("Core * Setup complete");
|
LOGln("Core * Setup complete");
|
||||||
}
|
}
|
||||||
@ -84,6 +91,10 @@ void loop() {
|
|||||||
effect_clock.loop(current_effect->clock_as_mask(), CRGB(0xFFFFFF), CRGB(0x000000));
|
effect_clock.loop(current_effect->clock_as_mask(), CRGB(0xFFFFFF), CRGB(0x000000));
|
||||||
}
|
}
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
|
|
||||||
|
#ifdef RECORDER_ENABLE
|
||||||
|
recorder->loop();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MQTT_ENABLE) && defined(MQTT_REPORT_METRICS)
|
#if defined(MQTT_ENABLE) && defined(MQTT_REPORT_METRICS)
|
||||||
|
67
src/recorder.cpp
Normal file
67
src/recorder.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "recorder.h"
|
||||||
|
#include "my_fastled.h"
|
||||||
|
#include "functions.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
#ifdef RECORDER_ENABLE
|
||||||
|
|
||||||
|
Recorder::Recorder() {
|
||||||
|
_buffer_len = LED_WIDTH * LED_HEIGHT * 3 + 3;
|
||||||
|
_buffer = (char*)malloc(_buffer_len);
|
||||||
|
_server = new AsyncServer(RECORDER_PORT);
|
||||||
|
_server->onClient([&](void* a, AsyncClient* c) {
|
||||||
|
LOGln("Recorder * New client: %s. Waiting for port number...", c->remoteIP().toString().c_str());
|
||||||
|
if (_client) {
|
||||||
|
LOGln("Recorder * Killing old client.");
|
||||||
|
_client->close();
|
||||||
|
_client_port = 0;
|
||||||
|
delete _client;
|
||||||
|
}
|
||||||
|
_client = c;
|
||||||
|
_msgid = 0;
|
||||||
|
char dim[3] = {LED_WIDTH, LED_HEIGHT, 255};
|
||||||
|
_client->write(dim, 3);
|
||||||
|
_client->onDisconnect([&](void* a, AsyncClient* client) {
|
||||||
|
LOGln("Recorder * Client disconnected");
|
||||||
|
_client_port = 0;
|
||||||
|
}, NULL);
|
||||||
|
_client->onData([&](void* a, AsyncClient* client, void* data, size_t len) {
|
||||||
|
if (*(char*)data == 'P') {
|
||||||
|
LOGln("Found.");
|
||||||
|
if (len >= 3) {
|
||||||
|
uint8_t* d = (uint8_t*)data;
|
||||||
|
_client_port = d[1]<<8 | d[2];
|
||||||
|
LOGln("Recorder * Sending data to port %d", _client_port);
|
||||||
|
}
|
||||||
|
} else if (*(char*)data == 'E') {
|
||||||
|
String effect = String(((char*)(data+1)));
|
||||||
|
LOGln("Recorder * Setting effect %s", effect.c_str());
|
||||||
|
change_current_effect(effect);
|
||||||
|
}
|
||||||
|
}, NULL);
|
||||||
|
}, _server);
|
||||||
|
_server->begin();
|
||||||
|
LOGln("Recorder * Listening on port %d", RECORDER_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::loop() {
|
||||||
|
if (_client && _client_port) {
|
||||||
|
_buffer[0] = _msgid >> 8;
|
||||||
|
_buffer[1] = _msgid & 0xFF;
|
||||||
|
for (uint8_t y=0; y<LED_HEIGHT; y++) for(uint8_t x=0; x<LED_WIDTH; x++) {
|
||||||
|
uint16_t index = XYsafe(x, y);
|
||||||
|
CRGB pixel = leds[index];
|
||||||
|
_buffer[2 + (y*LED_WIDTH + x)*3 + 0] = (pixel.r==255 ? 254 : pixel.r);
|
||||||
|
_buffer[2 + (y*LED_WIDTH + x)*3 + 1] = (pixel.g==255 ? 254 : pixel.g);
|
||||||
|
_buffer[2 + (y*LED_WIDTH + x)*3 + 2] = (pixel.b==255 ? 254 : pixel.b);
|
||||||
|
}
|
||||||
|
_buffer[_buffer_len - 1] = 255;
|
||||||
|
_udp.beginPacket("10.10.2.1", 13330);
|
||||||
|
_udp.write(_buffer, _buffer_len);
|
||||||
|
_udp.endPacket();
|
||||||
|
_msgid++;
|
||||||
|
//_client->write(_buffer, _buffer_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -6,22 +6,20 @@ namespace tests {
|
|||||||
LOGln("Tests * Running test for memory leaks...");
|
LOGln("Tests * Running test for memory leaks...");
|
||||||
test_effects_for_memory_leaks();
|
test_effects_for_memory_leaks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_effects_for_memory_leaks() {
|
void test_effects_for_memory_leaks() {
|
||||||
int i=0;
|
int i=0;
|
||||||
Effect* effect;
|
Effect* effect;
|
||||||
int32_t diffs[3] = {0, 0, 0};
|
int32_t diffs[3] = {0, 0, 0};
|
||||||
int32_t usage = 0;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
for (int j=0; j<3; j++) {
|
for (int j=0; j<3; j++) {
|
||||||
int free_at_start = ESP.getFreeHeap();
|
int free_at_start = ESP.getFreeHeap();
|
||||||
effect = select_effect(i);
|
effect = select_effect(i);
|
||||||
if (j==0) usage = free_at_start - ESP.getFreeHeap();
|
|
||||||
if (effect == NULL) return;
|
if (effect == NULL) return;
|
||||||
delete effect;
|
delete effect;
|
||||||
diffs[j] = free_at_start - ESP.getFreeHeap();
|
diffs[i] = ESP.getFreeHeap() - free_at_start;
|
||||||
}
|
}
|
||||||
LOGln("Tests * Memory usage of effect #%d: %d, leakage %d, %d, %d", i, usage, diffs[0], diffs[1], diffs[2]);
|
LOGln("Tests * Memory leakage of effect #%d: %d, %d, %d", i, diffs[0], diffs[1], diffs[2]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/tools/generate_gifs.sh
Executable file
20
src/tools/generate_gifs.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
IP="$1"
|
||||||
|
EFFECTS=`egrep "case" ../effects.cpp | tr -s "\t" " " | cut -d" " -f 7 | sort`
|
||||||
|
|
||||||
|
mkdir effects
|
||||||
|
|
||||||
|
for effect in $EFFECTS; do
|
||||||
|
[ "$effect" = "cycle" ] && continue
|
||||||
|
[ "$effect" = "off" ] && continue
|
||||||
|
[ "$effect" = "koopa" ] && continue
|
||||||
|
[ "$effect" = "couple_rain" ] && continue
|
||||||
|
[ "$effect" = "cake" ] && continue
|
||||||
|
|
||||||
|
echo " + ./recorder.rb $IP /tmp/effect.gif $effect"
|
||||||
|
./recorder.rb $IP /tmp/effect.gif $effect
|
||||||
|
echo
|
||||||
|
echo " + gifsicle /tmp/effect.gif -o effects/$effect.gif"
|
||||||
|
gifsicle /tmp/effect.gif -o effects/$effect.gif
|
||||||
|
done
|
59
src/tools/monitor.rb
Normal file
59
src/tools/monitor.rb
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
require 'socket'
|
||||||
|
require 'pp'
|
||||||
|
|
||||||
|
def rgb2ansi(r, g, b)
|
||||||
|
if r==g && g==b
|
||||||
|
return 16 if r<8
|
||||||
|
return 231 if r>248
|
||||||
|
return (((r - 8) / 247.0) * 24).round + 232
|
||||||
|
end
|
||||||
|
|
||||||
|
return 16 + 36*(r/51.0).round + 6*(g/51.0).round + (b/51.0).round
|
||||||
|
end
|
||||||
|
|
||||||
|
IP = ARGV[0]
|
||||||
|
PORT = 2122
|
||||||
|
EFFECT = ARGV[1]
|
||||||
|
|
||||||
|
puts "Connecting to #{IP}:#{PORT}..."
|
||||||
|
|
||||||
|
s = TCPSocket.new(IP, PORT)
|
||||||
|
|
||||||
|
puts "Connected."
|
||||||
|
init = s.recv(3).unpack("C*")
|
||||||
|
|
||||||
|
raise "Initial data packet wasn't usable!" if init[2] != 0xFF
|
||||||
|
puts "Got initial data packet."
|
||||||
|
|
||||||
|
dim_x, dim_y = *init
|
||||||
|
len = dim_x * dim_y * 3 + 3
|
||||||
|
|
||||||
|
puts "Size: #{dim_x}x#{dim_y}. Expecting packet length #{len}."
|
||||||
|
|
||||||
|
puts "Opening local UDP socket..."
|
||||||
|
udp = UDPSocket.new
|
||||||
|
udp.bind("10.10.2.1", 13330)
|
||||||
|
puts "Waiting for UDP packets on port 13330..."
|
||||||
|
s.sendmsg("P\x12\x34\x00")
|
||||||
|
s.sendmsg("E#{EFFECT}\x00") if EFFECT
|
||||||
|
|
||||||
|
|
||||||
|
while 1
|
||||||
|
data = udp.recvfrom(1024)[0].unpack("C*")
|
||||||
|
#puts "Packet. ID: #{data[0]}, length: #{data.length}"
|
||||||
|
raise "Unexpected packet length" unless data.count == len
|
||||||
|
raise "Invalid data packet" unless data[len - 1]==0xFF
|
||||||
|
id = data.shift << 8 | data.shift
|
||||||
|
#next
|
||||||
|
#print "."
|
||||||
|
puts "\033[2J"
|
||||||
|
(0...dim_y).each do |y|
|
||||||
|
(0...dim_x).each do |x|
|
||||||
|
r, g, b = *data.shift(3)
|
||||||
|
color_code = rgb2ansi(r, g, b)
|
||||||
|
print "\033[48;5;#{color_code}m "
|
||||||
|
end
|
||||||
|
puts "\033[0m"
|
||||||
|
end
|
||||||
|
end
|
93
src/tools/recorder.rb
Executable file
93
src/tools/recorder.rb
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
require 'socket'
|
||||||
|
require 'pp'
|
||||||
|
require 'rmagick'
|
||||||
|
|
||||||
|
include Magick
|
||||||
|
|
||||||
|
IP = ARGV[0]
|
||||||
|
PORT = 2122
|
||||||
|
FILE = ARGV[1] or raise "No filename given"
|
||||||
|
EFFECT = ARGV[2]
|
||||||
|
FRAMES = 250
|
||||||
|
FACTOR = 1
|
||||||
|
delay = 50
|
||||||
|
|
||||||
|
puts "Connecting to #{IP}:#{PORT}..."
|
||||||
|
|
||||||
|
s = TCPSocket.new(IP, PORT)
|
||||||
|
|
||||||
|
puts "Connected."
|
||||||
|
init = s.recv(3).unpack("C*")
|
||||||
|
|
||||||
|
raise "Initial data packet wasn't usable!" if init[2] != 0xFF
|
||||||
|
puts "Got initial data packet."
|
||||||
|
|
||||||
|
dim_x, dim_y = *init
|
||||||
|
len = dim_x * dim_y * 3 + 3
|
||||||
|
|
||||||
|
puts "Size: #{dim_x}x#{dim_y}. Expecting packet length #{len}."
|
||||||
|
|
||||||
|
puts "Opening local UDP socket..."
|
||||||
|
udp = UDPSocket.new
|
||||||
|
udp.bind("10.10.2.1", 13330)
|
||||||
|
puts "Waiting for UDP packets on port 13330..."
|
||||||
|
s.sendmsg("P\x12\x34\x00")
|
||||||
|
s.sendmsg("E#{EFFECT}\x00") if EFFECT
|
||||||
|
|
||||||
|
gif = ImageList.new
|
||||||
|
last_id = 255
|
||||||
|
last_frame_time = nil
|
||||||
|
img = nil
|
||||||
|
last_diff = nil
|
||||||
|
|
||||||
|
while gif.length < FRAMES do
|
||||||
|
data = udp.recvfrom(1024)[0].unpack("C*")
|
||||||
|
if delay > 0
|
||||||
|
delay -= 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
#puts "Packet. ID: #{data[0]}, length: #{data.length}"
|
||||||
|
raise "Unexpected packet length" unless data.count == len
|
||||||
|
raise "Invalid data packet" unless data[len - 1]==0xFF
|
||||||
|
|
||||||
|
id = data.shift << 8 | data.shift
|
||||||
|
if last_id != id-1 && last_id != id-2
|
||||||
|
puts
|
||||||
|
gif = ImageList.new
|
||||||
|
end
|
||||||
|
last_id = id
|
||||||
|
|
||||||
|
if img && last_frame_time
|
||||||
|
last_diff = diff = Time.now.to_f * 100 - last_frame_time.to_f * 100
|
||||||
|
img.delay = diff
|
||||||
|
end
|
||||||
|
|
||||||
|
last_frame_time = Time.now
|
||||||
|
|
||||||
|
img = Image.new(dim_x, dim_y)
|
||||||
|
img.delay = 5
|
||||||
|
gc = Draw.new
|
||||||
|
|
||||||
|
#next
|
||||||
|
print "."
|
||||||
|
print "#{gif.length}" if gif.length%50==0
|
||||||
|
(0...dim_y).each do |y|
|
||||||
|
(0...dim_x).each do |x|
|
||||||
|
r, g, b = *data.shift(3)
|
||||||
|
gc.fill("rgb(#{r}, #{g}, #{b})")
|
||||||
|
gc.point(x, y)
|
||||||
|
#img.pixel_color(x, y, Pixel.new(r, g, b, 255))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
gc.draw(img)
|
||||||
|
img.sample!(FACTOR)
|
||||||
|
gif << img
|
||||||
|
end
|
||||||
|
img.delay = last_diff
|
||||||
|
s.close
|
||||||
|
puts
|
||||||
|
puts "Generating gif..."
|
||||||
|
gif.write(FILE)
|
||||||
|
puts
|
||||||
|
puts
|
18
test.txt
18
test.txt
@ -1,18 +0,0 @@
|
|||||||
Original:
|
|
||||||
DATA: [==== ] 40.5% (used 33164 bytes from 81920 bytes)
|
|
||||||
PROGRAM: [==== ] 36.0% (used 375664 bytes from 1044464 bytes)
|
|
||||||
|
|
||||||
|
|
||||||
lots of compares:
|
|
||||||
DATA: [==== ] 38.6% (used 31640 bytes from 81920 bytes)
|
|
||||||
PROGRAM: [==== ] 35.6% (used 371740 bytes from 1044464 bytes)
|
|
||||||
|
|
||||||
crc32:
|
|
||||||
DATA: [==== ] 38.5% (used 31532 bytes from 81920 bytes)
|
|
||||||
PROGRAM: [==== ] 35.6% (used 371456 bytes from 1044464 bytes)
|
|
||||||
|
|
||||||
original:
|
|
||||||
DATA: [==== ] 39.4% (used 32256 bytes from 81920 bytes) │pitrix_dev/log MQTT * Received data for topic pitrix_dev/uptime with payload 391
|
|
||||||
PROGRAM: [==== ] 37.4% (used 390380 bytes from 1044464 bytes)
|
|
||||||
DATA: [==== ] 37.4% (used 30608 bytes from 81920 bytes) │pitrix_dev/free_heap 43624
|
|
||||||
PROGRAM: [==== ] 37.4% (used 390556 bytes from 1044464 bytes)
|
|
Loading…
Reference in New Issue
Block a user