Rewrote the AI slop
This commit is contained in:
+13
-15
@@ -4,28 +4,26 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
|
|
||||||
#include "screens.h"
|
struct Screen
|
||||||
|
{
|
||||||
|
void (*draw)(U8G2 &u8g2);
|
||||||
|
};
|
||||||
|
|
||||||
class Carousel {
|
class Carousel
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
Carousel(Screen *screens, size_t screenCount);
|
Carousel(Screen *screens, size_t screenCount);
|
||||||
|
void draw(U8G2 &u8g2);
|
||||||
void begin(unsigned long now);
|
|
||||||
void update(unsigned long now);
|
|
||||||
void next(unsigned long now);
|
|
||||||
void render(U8X8 &display) const;
|
|
||||||
bool consumeDirty();
|
bool consumeDirty();
|
||||||
|
void nextScreen();
|
||||||
|
void update(unsigned long now);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Screen *screens_;
|
Screen *screens_;
|
||||||
size_t screenCount_;
|
size_t screenCount_;
|
||||||
size_t currentIndex_;
|
size_t currentIndex_;
|
||||||
unsigned long nextAutoAdvanceAt_;
|
unsigned long nextUpdate_;
|
||||||
unsigned long manualModeUntil_;
|
|
||||||
bool dirty_;
|
bool dirty_;
|
||||||
|
|
||||||
void scheduleNextAdvance(unsigned long now);
|
|
||||||
void drawIndicators(U8X8 &display) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef DISPLAY_CONFIG_H
|
|
||||||
#define DISPLAY_CONFIG_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
namespace display_config {
|
|
||||||
|
|
||||||
constexpr uint8_t kNextButtonPin = A4;
|
|
||||||
|
|
||||||
constexpr unsigned long kAutoAdvanceIntervalMs = 10000;
|
|
||||||
constexpr unsigned long kManualHoldIntervalMs = 60000;
|
|
||||||
constexpr unsigned long kButtonDebounceMs = 150;
|
|
||||||
constexpr unsigned long kDebugLogIntervalMs = 500;
|
|
||||||
|
|
||||||
constexpr uint8_t kDisplayColumns = 16;
|
|
||||||
constexpr uint8_t kDisplayRows = 8;
|
|
||||||
constexpr uint8_t kIndicatorRow = 7;
|
|
||||||
constexpr uint8_t kIndicatorSpacing = 2;
|
|
||||||
|
|
||||||
} // namespace display_config
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef SCREENS_H
|
|
||||||
#define SCREENS_H
|
|
||||||
|
|
||||||
#include <U8g2lib.h>
|
|
||||||
|
|
||||||
struct Screen {
|
|
||||||
const char *title;
|
|
||||||
void (*render)(U8X8 &display);
|
|
||||||
};
|
|
||||||
|
|
||||||
void renderTimeScreen(U8X8 &display);
|
|
||||||
void renderWeatherScreen(U8X8 &display);
|
|
||||||
void renderTemperatureScreen(U8X8 &display);
|
|
||||||
void renderHumidityScreen(U8X8 &display);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+23
-91
@@ -1,104 +1,36 @@
|
|||||||
#include "carousel.h"
|
#include "carousel.h"
|
||||||
|
|
||||||
#include "display_config.h"
|
const unsigned long pageInterval = 5000;
|
||||||
|
|
||||||
Carousel::Carousel(Screen *screens, size_t screenCount)
|
Carousel::Carousel(Screen *screens, size_t screenCount)
|
||||||
: screens_(screens),
|
: screens_(screens),
|
||||||
screenCount_(screenCount),
|
screenCount_(screenCount),
|
||||||
|
dirty_(true),
|
||||||
currentIndex_(0),
|
currentIndex_(0),
|
||||||
nextAutoAdvanceAt_(0),
|
nextUpdate_(pageInterval) {}
|
||||||
manualModeUntil_(0),
|
|
||||||
dirty_(true) {}
|
|
||||||
|
|
||||||
void Carousel::begin(unsigned long now) {
|
void Carousel::draw(U8G2 &u8g2)
|
||||||
currentIndex_ = 0;
|
{
|
||||||
manualModeUntil_ = 0;
|
screens_[currentIndex_].draw(u8g2);
|
||||||
|
dirty_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Carousel::consumeDirty()
|
||||||
|
{
|
||||||
|
bool d = dirty_;
|
||||||
|
dirty_ = false;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Carousel::nextScreen()
|
||||||
|
{
|
||||||
|
currentIndex_ = (currentIndex_ + 1) % screenCount_;
|
||||||
dirty_ = true;
|
dirty_ = true;
|
||||||
scheduleNextAdvance(now);
|
nextUpdate_ += pageInterval;
|
||||||
Serial.print("carousel: begin index=");
|
|
||||||
Serial.print(currentIndex_);
|
|
||||||
Serial.print(" nextAutoAdvanceAt=");
|
|
||||||
Serial.println(nextAutoAdvanceAt_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Carousel::update(unsigned long now) {
|
void Carousel::update(unsigned long now) {
|
||||||
if (screenCount_ == 0) {
|
if (now > nextUpdate_) {
|
||||||
return;
|
nextScreen();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (manualModeUntil_ != 0 && now < manualModeUntil_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now >= nextAutoAdvanceAt_) {
|
|
||||||
currentIndex_ = (currentIndex_ + 1) % screenCount_;
|
|
||||||
dirty_ = true;
|
|
||||||
scheduleNextAdvance(now);
|
|
||||||
Serial.print("carousel: auto advance index=");
|
|
||||||
Serial.print(currentIndex_);
|
|
||||||
Serial.print(" now=");
|
|
||||||
Serial.print(now);
|
|
||||||
Serial.print(" nextAutoAdvanceAt=");
|
|
||||||
Serial.println(nextAutoAdvanceAt_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Carousel::next(unsigned long now) {
|
|
||||||
if (screenCount_ == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex_ = (currentIndex_ + 1) % screenCount_;
|
|
||||||
manualModeUntil_ = now + display_config::kManualHoldIntervalMs;
|
|
||||||
dirty_ = true;
|
|
||||||
scheduleNextAdvance(manualModeUntil_);
|
|
||||||
Serial.print("carousel: manual advance index=");
|
|
||||||
Serial.print(currentIndex_);
|
|
||||||
Serial.print(" now=");
|
|
||||||
Serial.print(now);
|
|
||||||
Serial.print(" manualModeUntil=");
|
|
||||||
Serial.print(manualModeUntil_);
|
|
||||||
Serial.print(" nextAutoAdvanceAt=");
|
|
||||||
Serial.println(nextAutoAdvanceAt_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Carousel::render(U8X8 &display) const {
|
|
||||||
if (screenCount_ == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
screens_[currentIndex_].render(display);
|
|
||||||
drawIndicators(display);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Carousel::consumeDirty() {
|
|
||||||
const bool wasDirty = dirty_;
|
|
||||||
dirty_ = false;
|
|
||||||
return wasDirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Carousel::scheduleNextAdvance(unsigned long now) {
|
|
||||||
nextAutoAdvanceAt_ = now + display_config::kAutoAdvanceIntervalMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Carousel::drawIndicators(U8X8 &display) const {
|
|
||||||
char indicatorLine[display_config::kDisplayColumns + 1];
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < display_config::kDisplayColumns; ++i) {
|
|
||||||
indicatorLine[i] = ' ';
|
|
||||||
}
|
|
||||||
indicatorLine[display_config::kDisplayColumns] = '\0';
|
|
||||||
|
|
||||||
const int totalWidth =
|
|
||||||
static_cast<int>((screenCount_ - 1) * display_config::kIndicatorSpacing) + 1;
|
|
||||||
const int startX = (display_config::kDisplayColumns - totalWidth) / 2;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < screenCount_; ++i) {
|
|
||||||
const int x = startX + static_cast<int>(i * display_config::kIndicatorSpacing);
|
|
||||||
if (x >= 0 && x < display_config::kDisplayColumns) {
|
|
||||||
indicatorLine[x] = (i == currentIndex_) ? '*' : 'o';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
display.drawString(0, display_config::kIndicatorRow, indicatorLine);
|
|
||||||
}
|
|
||||||
+35
-47
@@ -3,66 +3,54 @@
|
|||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
#include "carousel.h"
|
#include "carousel.h"
|
||||||
#include "display_config.h"
|
|
||||||
#include "screens.h"
|
|
||||||
|
|
||||||
// SH1106 128x64 OLED over hardware I2C, rotated 180 degrees for flipped mounting.
|
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, U8X8_PIN_NONE);
|
||||||
U8X8_SH1106_128X64_NONAME_HW_I2C display(U8X8_PIN_NONE, SCL, SDA);
|
|
||||||
|
int lastButtonState = LOW;
|
||||||
|
uint8_t buttonOne = A3;
|
||||||
|
|
||||||
|
int number = 0;
|
||||||
|
bool dirty = true;
|
||||||
|
|
||||||
|
void drawScreen1(U8G2 &u8g2) {
|
||||||
|
u8g2.setFont(u8g2_font_ncenB14_tr);
|
||||||
|
u8g2.drawStr(0, 20, "Screen 1");
|
||||||
|
}
|
||||||
|
void drawScreen2(U8G2 &u8g2) {
|
||||||
|
u8g2.setFont(u8g2_font_ncenB14_tr);
|
||||||
|
u8g2.drawStr(0, 40, "Screen 2");
|
||||||
|
}
|
||||||
|
|
||||||
Screen screens[] = {
|
Screen screens[] = {
|
||||||
{"Local Time", renderTimeScreen},
|
{ drawScreen1 },
|
||||||
{"Forecast", renderWeatherScreen},
|
{ drawScreen2 }
|
||||||
{"Temperature", renderTemperatureScreen},
|
|
||||||
{"Humidity", renderHumidityScreen},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Carousel carousel(screens, sizeof(screens) / sizeof(screens[0]));
|
Carousel carousel(screens, sizeof(screens) / sizeof(screens[0]));
|
||||||
|
|
||||||
unsigned long lastButtonPressAt = 0;
|
|
||||||
int lastNextButtonState = LOW;
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
pinMode(buttonOne, INPUT);
|
||||||
pinMode(display_config::kNextButtonPin, INPUT);
|
|
||||||
|
|
||||||
display.begin();
|
u8g2.begin();
|
||||||
display.setFlipMode(1);
|
u8g2.clearBuffer();
|
||||||
display.setFont(u8x8_font_chroma48medium8_r);
|
u8g2.sendBuffer();
|
||||||
display.clearDisplay();
|
|
||||||
carousel.begin(millis());
|
|
||||||
|
|
||||||
Serial.println("setup: display initialized");
|
|
||||||
Serial.print("setup: next button pin=");
|
|
||||||
Serial.println(display_config::kNextButtonPin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop(){
|
||||||
const unsigned long now = millis();
|
const unsigned long now = millis();
|
||||||
const int nextButtonState = digitalRead(display_config::kNextButtonPin);
|
|
||||||
|
|
||||||
if (nextButtonState != lastNextButtonState) {
|
|
||||||
Serial.print("button: state changed to ");
|
|
||||||
Serial.print(nextButtonState);
|
|
||||||
Serial.print(" at ");
|
|
||||||
Serial.println(now);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastNextButtonState == HIGH && nextButtonState == LOW &&
|
|
||||||
now - lastButtonPressAt >= display_config::kButtonDebounceMs) {
|
|
||||||
Serial.print("button: press detected at ");
|
|
||||||
Serial.println(now);
|
|
||||||
carousel.next(now);
|
|
||||||
lastButtonPressAt = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastNextButtonState = nextButtonState;
|
|
||||||
|
|
||||||
carousel.update(now);
|
carousel.update(now);
|
||||||
|
|
||||||
|
const int currentButtonState = digitalRead(buttonOne);
|
||||||
|
if (lastButtonState == LOW && currentButtonState == HIGH) {
|
||||||
|
number += 10;
|
||||||
|
carousel.nextScreen();
|
||||||
|
}
|
||||||
|
lastButtonState = currentButtonState;
|
||||||
|
|
||||||
if (carousel.consumeDirty()) {
|
if (carousel.consumeDirty()) {
|
||||||
Serial.print("display: redraw at ");
|
u8g2.clearBuffer();
|
||||||
Serial.println(now);
|
carousel.draw(u8g2);
|
||||||
carousel.render(display);
|
u8g2.sendBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(100);
|
delay(50);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
#include "screens.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void clearContentRows(U8X8 &display) {
|
|
||||||
for (uint8_t row = 0; row < 7; ++row) {
|
|
||||||
display.clearLine(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawScreenFrame(U8X8 &display, const char *title, const char *value) {
|
|
||||||
clearContentRows(display);
|
|
||||||
display.drawString(0, 0, title);
|
|
||||||
display.drawString(0, 2, "--------------");
|
|
||||||
display.drawString(0, 4, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void renderTimeScreen(U8X8 &display) {
|
|
||||||
drawScreenFrame(display, "Local Time", "12:34");
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderWeatherScreen(U8X8 &display) {
|
|
||||||
drawScreenFrame(display, "Forecast", "Sunny");
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderTemperatureScreen(U8X8 &display) {
|
|
||||||
drawScreenFrame(display, "Temperature", "21.5 C");
|
|
||||||
}
|
|
||||||
|
|
||||||
void renderHumidityScreen(U8X8 &display) {
|
|
||||||
drawScreenFrame(display, "Humidity", "45 %");
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user