Show IP address on startup

To accomplish this, the following changes were made:

- Added an image-scrolling animation
- Implemented a bitmap font engine to generate an image from text
- On startup, an image-scrolling animation is set up with an image
  generated from the local IP address
This commit is contained in:
Thomas Kolb 2019-12-23 19:56:33 +01:00
parent c2a96747b9
commit d5357b2021
12 changed files with 235 additions and 2 deletions

View file

@ -5,3 +5,4 @@
#include "FireAnimation.h"
#include "SnowfallAnimation.h"
#include "FadeToColorAnimation.h"
#include "ImageScrollerAnimation.h"

View file

@ -15,6 +15,7 @@ class AnimationController
FIRE_HOT = 0,
FIRE_COLD = 1,
SNOWFALL = 2,
FONT_TEST = 3,
NUM_DEFAULT_ANIMATIONS
};
@ -22,7 +23,8 @@ class AnimationController
static const constexpr std::array<const char*, NUM_DEFAULT_ANIMATIONS> AnimationNames{
"Hot Fire",
"Cold Fire",
"Snowfall"
"Snowfall",
"Font Test"
};
AnimationController(Fader *fader);

View file

@ -0,0 +1,31 @@
#pragma once
#include <random>
#include <vector>
#include "Animation.h"
#include "Bitmap.h"
class ImageScrollerAnimation : public Animation
{
public:
ImageScrollerAnimation(Fader *fader, Bitmap *image, uint32_t interval = 3);
void loop(uint64_t frame) override;
void stop(void) override
{
m_stopping = true;
}
void reset(void) override;
private:
Bitmap m_image;
int32_t m_startIdx;
uint32_t m_interval;
bool m_stopping;
};

33
include/Bitmap.h Normal file
View file

@ -0,0 +1,33 @@
#pragma once
#include "Fader.h"
class Bitmap
{
public:
std::vector<Fader::Color> m_pixdata;
uint32_t width;
uint32_t height;
Bitmap(uint32_t w, uint32_t h)
: m_pixdata(w * h, Fader::Color{0, 0, 0, 0}),
width(w),
height(h)
{
}
Bitmap() : Bitmap(0, 0) {}
Fader::Color &pixel(uint32_t x, uint32_t y)
{
return m_pixdata[idx(x, y)];
}
uint32_t idx(uint32_t x, uint32_t y)
{
return x * height + y;
}
void resize(uint32_t w, uint32_t h);
};

12
include/Font.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
#include <Bitmap.h>
class Font
{
public:
static void textToBitmap(const char *text,
Bitmap *bmp,
const Fader::Color &color_on = Fader::Color{0, 0, 0, 32},
const Fader::Color &color_off = Fader::Color{0, 0, 0, 0});
};

12
include/font16_data.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef FONT16_DATA_H
#define FONT16_DATA_H
#include <stdint.h>
extern const uint16_t font_data[];
extern const uint16_t font_pos[];
extern const uint8_t font_width[];
extern const uint8_t font_lut[];
extern const uint8_t font_height;
#endif // FONT16_DATA_H

View file

@ -2,6 +2,8 @@
#include "Animation/AllAnimations.h"
#include "Font.h"
const constexpr
std::array<const char*, AnimationController::NUM_DEFAULT_ANIMATIONS>
AnimationController::AnimationNames;
@ -47,6 +49,15 @@ void AnimationController::changeAnimation(AnimationController::DefaultAnimation
changeAnimation(std::unique_ptr<Animation>(new SnowfallAnimation(m_fader)), transition);
break;
case FONT_TEST:
{
Bitmap bmp(16, 16);
Font::textToBitmap("Hello World!", &bmp, Fader::Color{0, 0, 32, 32});
changeAnimation(std::unique_ptr<Animation>(new ImageScrollerAnimation(m_fader, &bmp)), transition);
}
break;
default:
return; // unknown id, do nothing
}

View file

@ -0,0 +1,58 @@
#include "Animation/ImageScrollerAnimation.h"
#include <iostream>
ImageScrollerAnimation::ImageScrollerAnimation(Fader *fader, Bitmap *image, uint32_t interval)
: Animation(fader),
m_image(*image),
m_interval(interval)
{
reset();
}
void ImageScrollerAnimation::loop(uint64_t frame)
{
int32_t nled = m_fader->modules_per_strip();
int32_t nstrip = m_fader->strips();
if((frame % m_interval) != 0) {
return;
}
// blit the image
m_fader->set_color(Fader::Color{0, 0, 0, 0});
for(int32_t strip = 0; strip < nstrip; strip++) {
for(int32_t led = 0; led < nled; led++) {
int32_t im_x = m_startIdx - strip;
int32_t im_y = m_fader->modules_per_strip() - led - 1;
if(im_x < 0 || im_x >= m_image.width || im_y < 0 || im_y >= m_image.height) {
// the current pixel is not inside the shifted image
continue;
}
int32_t s = (nstrip - strip - 1 + 5) % nstrip;
m_fader->set_color(s, led, m_image.pixel(im_x, im_y));
}
}
// move the image around the lamp
m_startIdx++;
if(m_startIdx >= static_cast<int32_t>(nstrip + m_image.width)) {
if(m_stopping) {
m_running = false;
} else {
reset();
}
}
}
void ImageScrollerAnimation::reset(void)
{
m_stopping = false;
m_running = true;
m_startIdx = 0;
}

9
src/Bitmap.cpp Normal file
View file

@ -0,0 +1,9 @@
#include "Bitmap.h"
void Bitmap::resize(uint32_t w, uint32_t h)
{
width = w;
height = h;
m_pixdata.resize(w*h, Fader::Color{0, 0, 0, 0});
}

46
src/Font.cpp Normal file
View file

@ -0,0 +1,46 @@
#include "Font.h"
#include "font16_data.h"
void Font::textToBitmap(const char *text, Bitmap *bmp, const Fader::Color &color_on, const Fader::Color &color_off)
{
uint32_t bitmapWidth = 0;
const char *cp = text;
while(*cp) {
uint8_t idx = font_lut[static_cast<uint8_t>(*cp)];
bitmapWidth += font_width[idx];
cp++;
}
bmp->resize(bitmapWidth, font_height);
uint32_t bmp_x = 0;
cp = text;
while(*cp) {
uint8_t idx = font_lut[static_cast<uint8_t>(*cp)];
uint16_t char_start = font_pos[idx];
uint16_t char_end = char_start + font_width[idx];
for(uint16_t char_pos = char_start; char_pos < char_end; char_pos++) {
uint16_t char_data = font_data[char_pos];
for(uint8_t y = 0; y < font_height; y++) {
uint32_t bmp_y = y;
if(char_data & (1 << y)) {
bmp->pixel(bmp_x, bmp_y) = color_on;
} else {
bmp->pixel(bmp_x, bmp_y) = color_off;
}
}
bmp_x++;
}
cp++;
}
}

10
src/font16_data.c Normal file
View file

@ -0,0 +1,10 @@
#include "font16_data.h"
const uint16_t font_data[643] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f0, 0x808, 0x1004, 0x10c4, 0x10c4, 0x808, 0x7f0, 0x0, 0x0, 0x0, 0x1008, 0x1004, 0x1ffc, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x1018, 0x180c, 0x1404, 0x1204, 0x1104, 0x1088, 0x1078, 0x0, 0x0, 0x808, 0x1004, 0x1084, 0x1084, 0x1084, 0x1948, 0xf78, 0x0, 0x0, 0x300, 0x2c0, 0x260, 0x218, 0x20c, 0x1ffc, 0x200, 0x0, 0x0, 0x8fc, 0x1044, 0x1044, 0x1044, 0x1044, 0x884, 0x700, 0x0, 0x0, 0x7e0, 0x898, 0x104c, 0x1044, 0x1044, 0x18c4, 0xf88, 0x0, 0x0, 0x4, 0x1004, 0xc04, 0x304, 0xc4, 0x3c, 0xc, 0x0, 0x0, 0xf78, 0x194c, 0x1084, 0x1084, 0x1084, 0x194c, 0xf78, 0x0, 0x0, 0x8f8, 0x118c, 0x1104, 0x1104, 0x1904, 0xc88, 0x3f0, 0x0, 0x0, 0xe00, 0x1340, 0x1120, 0x1120, 0x1120, 0x920, 0x1fc0, 0x0, 0x0, 0x1ffc, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0x780, 0x0, 0x0, 0x780, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0x0, 0x0, 0x0, 0x780, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0x1ffc, 0x0, 0x0, 0x780, 0xa40, 0x1220, 0x1220, 0x1220, 0x1240, 0xb80, 0x0, 0x0, 0x0, 0x20, 0x20, 0x1ff8, 0x24, 0x24, 0x24, 0x0, 0x0, 0x780, 0x4840, 0x9020, 0x9020, 0x9020, 0xc840, 0x7fe0, 0x0, 0x0, 0x1ffc, 0x40, 0x20, 0x20, 0x20, 0x60, 0x1fc0, 0x0, 0x0, 0x1000, 0x1020, 0x1020, 0x1fec, 0x1000, 0x1000, 0x1000, 0x0, 0x0, 0x8000, 0x8020, 0x8020, 0x7fec, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ffc, 0x100, 0x180, 0x240, 0x440, 0x820, 0x1000, 0x0, 0x4, 0x4, 0x4, 0xffc, 0x1000, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x1fe0, 0x20, 0x20, 0x1fe0, 0x20, 0x20, 0x1fc0, 0x0, 0x0, 0x1fe0, 0x40, 0x20, 0x20, 0x20, 0x60, 0x1fc0, 0x0, 0x0, 0x780, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0x780, 0x0, 0x0, 0xffe0, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0x780, 0x0, 0x0, 0x780, 0x840, 0x1020, 0x1020, 0x1020, 0x840, 0xffe0, 0x0, 0x0, 0x0, 0x0, 0x1fe0, 0x40, 0x20, 0x20, 0x20, 0x40, 0x0, 0x9c0, 0x1120, 0x1120, 0x1120, 0x1220, 0x1220, 0xe40, 0x0, 0x0, 0x20, 0x20, 0xff8, 0x1020, 0x1020, 0x1020, 0x0, 0x0, 0x0, 0xfe0, 0x1800, 0x1000, 0x1000, 0x1000, 0x800, 0x1fe0, 0x0, 0x0, 0x20, 0x1c0, 0xe00, 0x1000, 0xe00, 0x1c0, 0x20, 0x0, 0x60, 0x780, 0x1800, 0x600, 0x180, 0x600, 0x1800, 0x780, 0x60, 0x0, 0x1020, 0x1860, 0x480, 0x300, 0x480, 0x1860, 0x1020, 0x0, 0x0, 0x20, 0x81c0, 0x8600, 0x7800, 0xe00, 0x1c0, 0x20, 0x0, 0x0, 0x1820, 0x1420, 0x1220, 0x1220, 0x1120, 0x10a0, 0x1060, 0x0, 0x0, 0x1800, 0x780, 0x278, 0x204, 0x278, 0x780, 0x1800, 0x0, 0x0, 0x1ffc, 0x1084, 0x1084, 0x1084, 0x1084, 0x19cc, 0xf78, 0x0, 0x0, 0x3e0, 0xc18, 0x1004, 0x1004, 0x1004, 0x1004, 0x808, 0x0, 0x0, 0x1ffc, 0x1004, 0x1004, 0x1004, 0x180c, 0xc18, 0x3e0, 0x0, 0x0, 0x1ffc, 0x1084, 0x1084, 0x1084, 0x1084, 0x1084, 0x1084, 0x0, 0x0, 0x1ffc, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x0, 0x0, 0x3e0, 0xc18, 0x1004, 0x1004, 0x1084, 0x1084, 0xf88, 0x0, 0x0, 0x1ffc, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1ffc, 0x0, 0x0, 0x0, 0x1004, 0x1004, 0x1ffc, 0x1004, 0x1004, 0x0, 0x0, 0x0, 0x800, 0x1000, 0x1004, 0x1004, 0x1804, 0xffc, 0x0, 0x0, 0x0, 0x1ffc, 0x80, 0x40, 0x1a0, 0x210, 0xc08, 0x1004, 0x0, 0x0, 0x1ffc, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0, 0x0, 0x1ffc, 0x1c, 0xe0, 0x100, 0xe0, 0x1c, 0x1ffc, 0x0, 0x0, 0x1ffc, 0xc, 0x70, 0x1c0, 0x600, 0x1800, 0x1ffc, 0x0, 0x0, 0x7f0, 0x808, 0x1004, 0x1004, 0x1004, 0x808, 0x7f0, 0x0, 0x0, 0x1ffc, 0x104, 0x104, 0x104, 0x104, 0x188, 0xf8, 0x0, 0x0, 0x7f0, 0x808, 0x1004, 0x1004, 0x3004, 0x7808, 0x7f0, 0x0, 0x0, 0x1ffc, 0x84, 0x84, 0x84, 0x84, 0x14c, 0xe78, 0x1000, 0x0, 0x878, 0x1848, 0x1084, 0x1084, 0x1084, 0x190c, 0xf08, 0x0, 0x0, 0x4, 0x4, 0x4, 0x1ffc, 0x4, 0x4, 0x4, 0x0, 0x0, 0xffc, 0x1800, 0x1000, 0x1000, 0x1000, 0x1800, 0xffc, 0x0, 0x0, 0xc, 0xf0, 0xf00, 0x1000, 0xf00, 0xf0, 0xc, 0x0, 0x1c, 0x7e0, 0x1800, 0x7c0, 0x20, 0x7c0, 0x1800, 0x7e0, 0x1c, 0x0, 0x1004, 0xc18, 0x360, 0x80, 0x360, 0xc18, 0x1004, 0x0, 0x4, 0xc, 0x30, 0x60, 0x1f80, 0x40, 0x30, 0xc, 0x4, 0x0, 0x1804, 0x1404, 0x1304, 0x1084, 0x1064, 0x1014, 0x100c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1800, 0x1800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1860, 0x1860, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x4, 0x1b84, 0x84, 0x44, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19fc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100, 0x100, 0x100, 0xfe0, 0x100, 0x100, 0x100, 0x0, 0x0, 0x0, 0x0, 0x100, 0x100, 0x100, 0x100, 0x0, 0x0, 0x0, 0x48, 0x50, 0x30, 0xfc, 0x30, 0x50, 0x48, 0x0, 0x0, 0x2000, 0x1800, 0x600, 0x180, 0x60, 0x18, 0x4, 0x0, 0x0, 0x240, 0x240, 0x240, 0x240, 0x240, 0x240, 0x240, 0x240 };
const uint16_t font_pos[64] = { 0, 4, 13, 22, 31, 40, 49, 58, 67, 76, 85, 94, 103, 112, 121, 130, 139, 148, 157, 166, 175, 184, 193, 202, 211, 220, 229, 238, 247, 256, 265, 274, 283, 292, 301, 310, 319, 328, 337, 346, 355, 364, 373, 382, 391, 400, 409, 418, 427, 436, 445, 454, 463, 472, 481, 490, 499, 508, 517, 526, 535, 544, 553, 562 };
const uint8_t font_width[64] = { 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
const uint8_t font_lut[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 69, 67, 0, 68, 63, 70, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 64, 0, 0, 71, 0, 66, 0, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const uint8_t font_height = 16;

View file

@ -13,6 +13,7 @@
#include "Fader.h"
#include "UDPProto.h"
#include "UpdateServer.h"
#include "Font.h"
#include "Config.h"
#include "Animation/AllAnimations.h"
@ -118,7 +119,12 @@ static void ledFSM(void)
animController.loop();
if(animController.isIdle()) {
animController.changeAnimation(std::unique_ptr<Animation>(new FireAnimation(&ledFader, false)), false);
Bitmap bmp(16, 16);
String infoStr = "IP: " + WiFi.localIP().toString(); // + " - IPv6: " + WiFi.localIPv6().toString();
Font::textToBitmap(infoStr.c_str(), &bmp, Fader::Color{0, 0, 0, 32});
animController.changeAnimation(std::unique_ptr<Animation>(new ImageScrollerAnimation(&ledFader, &bmp, 5)), false);
//animController.changeAnimation(std::unique_ptr<Animation>(new FireAnimation(&ledFader, false)), false);
ledState = ANIMATION;
}
break;
@ -262,6 +268,8 @@ void wifi_setup(void)
{
Serial.println("Trying to connect...");
WiFi.setHostname("mlmini");
for(size_t tries = 0; tries < 10; tries++)
{
if(wiFiMulti.run() == WL_CONNECTED) {