204 lines
5.9 KiB
C++
204 lines
5.9 KiB
C++
|
|
#include "Display.h"
|
|
#include <MD_Parola.h>
|
|
#include <MD_MAX72xx.h>
|
|
#include <SPI.h>
|
|
#include "MD_RobotEyes.h"
|
|
extern "C" {
|
|
#include "user_interface.h"
|
|
}
|
|
|
|
#define DISPLAY_CLK_PIN D5
|
|
#define DISPLAY_DATA_PIN D7
|
|
#define DISPLAY_CS_PIN D6
|
|
#define VERTICAL_BAR_STARTS_TOP false
|
|
|
|
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
|
|
#define MAX_DISPLAY_DEVICES 4
|
|
|
|
static MD_Parola P = MD_Parola(HARDWARE_TYPE, DISPLAY_DATA_PIN, DISPLAY_CLK_PIN, DISPLAY_CS_PIN, MAX_DISPLAY_DEVICES);
|
|
static MD_RobotEyes E;
|
|
static MD_MAX72XX *graphicDisplay = NULL;
|
|
|
|
|
|
void Display::begin() {
|
|
int charCode;
|
|
#if VERTICAL_BAR_STARTS_TOP
|
|
static uint8_t verticalBarFont[] = {
|
|
1, 0x00, /* blank */
|
|
1, 0x01, /* 1 dot */
|
|
1, 0x03, /* 2 dots */
|
|
1, 0x07,
|
|
1, 0x0f,
|
|
1, 0x1f,
|
|
1, 0x3f,
|
|
1, 0x7f,
|
|
1, 0xff, /* vertical bar completely set */
|
|
}; // columns from right to left, each byte is a single column
|
|
#else
|
|
static uint8_t verticalBarFont[] = {
|
|
1, 0x00, /* blank */
|
|
1, 0x80, /* 1 dot */
|
|
1, 0xc0, /* 2 dots */
|
|
1, 0xe0,
|
|
1, 0xf0,
|
|
1, 0xf8,
|
|
1, 0xfc,
|
|
1, 0xfe,
|
|
1, 0xff, /* vertical bar completely set */
|
|
}; // columns from right to left, each byte is a single column
|
|
#endif
|
|
static uint8_t newZero[] = {0x05, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00};
|
|
|
|
P.begin();
|
|
// P.setZoneEffect(0, true, PA_FLIP_LR);
|
|
graphicDisplay = P.getGraphicObject();
|
|
E.begin(graphicDisplay, 1); // start at 2nd module, count starts with 0
|
|
|
|
P.setIntensity(1);
|
|
for (charCode=1; charCode<=9; ++charCode) {
|
|
P.addChar(charCode, verticalBarFont+2*(charCode-1));
|
|
}
|
|
// replace the 0 characters, we do not like the "slash"
|
|
P.addChar('0', newZero);
|
|
|
|
char intro[] = {' ', 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00};
|
|
P.print(intro);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
char name[7];
|
|
MD_RobotEyes::emotion_t e;
|
|
uint16_t timePause; // in milliseconds
|
|
} sampleItem_t;
|
|
|
|
static const sampleItem_t eSeq[] =
|
|
{
|
|
{ "Nutral", MD_RobotEyes::E_NEUTRAL, 1000 },
|
|
{ "Blink" , MD_RobotEyes::E_BLINK, 1000 },
|
|
{ "Wink" , MD_RobotEyes::E_WINK, 1000 },
|
|
{ "Left" , MD_RobotEyes::E_LOOK_L, 1000 },
|
|
{ "Right" , MD_RobotEyes::E_LOOK_R, 1000 },
|
|
{ "Up" , MD_RobotEyes::E_LOOK_U, 1000 },
|
|
{ "Down" , MD_RobotEyes::E_LOOK_D, 1000 },
|
|
{ "Angry" , MD_RobotEyes::E_ANGRY, 1000 },
|
|
{ "Sad" , MD_RobotEyes::E_SAD, 1000 },
|
|
{ "Evil" , MD_RobotEyes::E_EVIL, 1000 },
|
|
{ "Evil2" , MD_RobotEyes::E_EVIL2, 1000 },
|
|
{ "Squint", MD_RobotEyes::E_SQUINT, 1000 },
|
|
{ "Dead" , MD_RobotEyes::E_DEAD, 1000 },
|
|
{ "ScanV" , MD_RobotEyes::E_SCAN_UD, 1000 },
|
|
{ "ScanH" , MD_RobotEyes::E_SCAN_LR, 1000 },
|
|
};
|
|
#define DISPLAY_ANIM_NAME false
|
|
|
|
void Display::loopEyeAnimation() {
|
|
// show startup animation
|
|
boolean animationFinished = false;
|
|
static uint32_t timeStartDelay;
|
|
static uint8_t index = ARRAY_SIZE(eSeq);
|
|
static enum { S_IDLE, S_TEXT, S_ANIM, S_PAUSE } state = S_IDLE;
|
|
|
|
animationFinished = E.runAnimation();
|
|
|
|
switch (state)
|
|
{
|
|
case S_IDLE:
|
|
index++;
|
|
if (index >= ARRAY_SIZE(eSeq))
|
|
index = 0;
|
|
P.displayClear();
|
|
#if DISPLAY_ANIM_NAME
|
|
E.setText(eSeq[index].name);
|
|
#endif
|
|
state = S_TEXT;
|
|
break;
|
|
|
|
case S_TEXT: // wait for the text to finish
|
|
if (animationFinished) // text animation is finished
|
|
{
|
|
E.setAnimation(eSeq[index].e, true);
|
|
state = S_ANIM;
|
|
}
|
|
break;
|
|
|
|
case S_ANIM: // checking animation is completed
|
|
if (animationFinished) // animation is finished
|
|
{
|
|
timeStartDelay = millis();
|
|
state = S_PAUSE;
|
|
}
|
|
break;
|
|
|
|
case S_PAUSE: // non blocking waiting for a period between animations
|
|
if (millis() - timeStartDelay >= eSeq[index].timePause)
|
|
state = S_IDLE;
|
|
break;
|
|
|
|
default:
|
|
state = S_IDLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Display::loop() {
|
|
char minuteProgressIndicator;
|
|
char timeBuffer[10];
|
|
|
|
minuteProgressIndicator = currentTime->getSeconds()/6.7 + 1; // char code 1-8 show vertical bar
|
|
if (minuteProgressIndicator > 9) minuteProgressIndicator = 9;
|
|
snprintf(timeBuffer, 10, "%c %2d:%02d", minuteProgressIndicator, currentTime->getHours(), currentTime->getMinutes());
|
|
|
|
// standard procedure to display
|
|
static uint32_t last_clock_refresh = 0;
|
|
static uint32_t lastTimeClockNameShown = 0;
|
|
static boolean showingClockName = false;
|
|
|
|
if (showingClockName) {
|
|
if (millis() - lastTimeClockNameShown > clockNameDurationTime_ms) {
|
|
// stop showingClockName
|
|
showingClockName = false;
|
|
}
|
|
} else {
|
|
if ((millis() - lastTimeClockNameShown > displayClockNameEvery_ms)
|
|
&& (currentTime->getSeconds() < 60-doNotShowClockNameBeforeAndAfterMinuteChange_s)
|
|
&& (currentTime->getSeconds() > doNotShowClockNameBeforeAndAfterMinuteChange_s)) {
|
|
// re-initialize, that fixes display problems due to electrical relais feedbacks
|
|
reInitializeDisplay();
|
|
P.setIntensity(2);
|
|
P.print(currentTime->getClockName());
|
|
lastTimeClockNameShown = millis();
|
|
showingClockName = true;
|
|
} else {
|
|
// showing clock
|
|
if (millis() - last_clock_refresh > displayRefresh_ms) {
|
|
// re-initialize, that fixes display problems due to electrical relais feedbacks
|
|
reInitializeDisplay();
|
|
P.setIntensity(1);
|
|
P.print(timeBuffer);
|
|
last_clock_refresh = millis();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Display::reInitializeDisplay() {
|
|
uint32_t free = system_get_free_heap_size();
|
|
#define REINIT_AFTER_ms 5000
|
|
#define AVOID_REINIT_BEFORE_AND_AFTER_FULLMINUTE_FOR_s 3
|
|
|
|
if (last_reinit_ts == 0) last_reinit_ts = millis();
|
|
|
|
if (millis() - last_reinit_ts > REINIT_AFTER_ms
|
|
&& currentTime->getSeconds() < 60 - AVOID_REINIT_BEFORE_AND_AFTER_FULLMINUTE_FOR_s
|
|
&& currentTime->getSeconds() > AVOID_REINIT_BEFORE_AND_AFTER_FULLMINUTE_FOR_s) {
|
|
P.begin();
|
|
Serial.print("reinit display, free="); Serial.println(free);
|
|
last_reinit_ts = millis();
|
|
}
|
|
}
|
|
|
|
void Display::print(const char *s) { P.print(s); }
|
|
void Display::print(const String s) { P.print(s); }
|