menu first work

This commit is contained in:
Andrea Baccega 2024-01-27 11:46:08 +01:00
parent 84c246d3d7
commit 721113ddcb
8 changed files with 272 additions and 124 deletions

View File

@ -12,7 +12,7 @@
platform = atmelmegaavr
board = ATmega4809
framework = arduino
monitor_speed = 38400
upload_speed = 115200
board_hardware.uart = uart0
upload_protocol = arduino

View File

@ -50,6 +50,7 @@ template <typename First, typename Second>
class Pair
{
public:
Pair(){};
Pair(First first, Second second) : first(first), second(second) {}
First first;
Second second;

View File

@ -0,0 +1,128 @@
#ifndef __OLEDSTATEMACHINE_H_
#define __OLEDSTATEMACHINE_H_
#include "../buttons/base.h"
#include "../common.h"
#include <Arduino.h>
class OledMenuItem {
public:
OledMenuItem(){};
OledMenuItem(char *title): title(title), identifier(0) {};
OledMenuItem(char *title, uint8_t identifier): title(title), identifier(identifier) {};
char const * title;
// Identifier c
uint8_t identifier;
};
class OledMenu {
public:
OledMenu(){};
OledMenu(uint8_t identifier): identifier(identifier), elementsLength(0), childrenLength(0) {};
~OledMenu() {
delete elements;
delete children;
delete childrenMatrix;
};
uint8_t identifier;
void setChildren(OledMenu **children, int length) {
this->children = children;
this->childrenLength = length;
for (int i=0; i<length; i++) {
children[i]->parent = this;
}
}
void setElements(OledMenuItem *elements, int length) {
this->elements = new OledMenuItem[length];
for (int i=0; i<length; i++) {
this->elements[i].title = malloc(strlen(elements[i].title) + 1);
memcpy(this->elements[i].title, elements[i].title, strlen(elements[i].title) + 1);
this->elements[i].identifier = elements[i].identifier;
Serial.println(String(this->elements[i].title) + " " + String(elements[i].title));
}
this->elementsLength = length;
}
void setChildrenMatrix(int length, uint8_t (*matrix)[2]) {
this->childrenMatrix = matrix;
this->childrenMatrixLength = length;
}
// To be invoked when the user presses the SELECT btn
// If null is returned then the menu should not be changed
OledMenu *getNextMenu() {
for (int i=0; i<childrenMatrixLength; i++) {
if (childrenMatrix[i][0] == curItem) {
return children[childrenMatrix[i][1]];
}
}
return nullptr;
}
// To be invoked when the user presses the UP btn
OledMenuItem goNextItem() {
curItem++;
curItem = curItem % elementsLength;
Serial.println(String(elements[curItem].title) + " - " + String(curItem));
return elements[curItem];
}
// To be invoked when the user presses the DOWN btn
OledMenuItem goPrevItem() {
curItem--;
if (curItem < 0) {
curItem = elementsLength - 1;
}
Serial.println(String(elements[curItem].title) + " - " + String(curItem));
return elements[curItem];
}
OledMenuItem getCurItem() {
return elements[curItem];
}
OledMenu *parent;
protected:
int curItem = 0;
OledMenuItem *elements;
int elementsLength;
OledMenu **children;
int childrenLength;
/**
* Matrix of pairs of (element index, children index)
* ex if element at index 0 should go to children at index 1 when user hits SELECT
* then the matrix would be:
* { ..., {0, 1}, ...}
*/
uint8_t (*childrenMatrix)[2]; // First is element index, second is children index,
int childrenMatrixLength;
};
#define SETMATRIX(menuItem, CODE) { Pair<ButtonKind,int> matrix[] = { CODE }; menuItem.setMatrix( sizeof(matrix)/sizeof(matrix[0]), matrix); }
#define UPBUTTON(index) Pair<ButtonKind, int>(ButtonKind::UP, index),
#define DOWNBUTTON(index) Pair<ButtonKind, int>(ButtonKind::DOWN, index),
#define SELECTBUTTON(index) Pair<ButtonKind, int>(ButtonKind::SELECT, index),
#define BACKBUTTON(index) Pair<ButtonKind, int>(ButtonKind::BACK, index),
// #define SETOLED_HANDLER(handler, CODE) { handler.buttonPressed = [](ButtonKind kind) -> OledInterfaceHandler* { CODE }; }
// #define BTNGOTOHANDLER(_kind, gotoHandler) if (kind == _kind) { return gotoHandler; }
// #define HANDLER_ONUP(gotoHandler) BTNGOTOHANDLER(ButtonKind::UP, gotoHandler)
// #define HANDLER_ONDOWN(gotoHandler) BTNGOTOHANDLER(ButtonKind::DOWN, gotoHandler)
// #define HANDLER_ONBACK(gotoHandler) BTNGOTOHANDLER(ButtonKind::BACK, gotoHandler)
// #define HANDLER_ONSELECT(gotoHandler) BTNGOTOHANDLER(ButtonKind::SELECT, gotoHandler)
// #define HANDLER_NULL return nullptr;
#endif

View File

@ -1,9 +1,11 @@
#include "./oled.h"
#include <Arduino.h>
#include "../globals.h"
#include "./menustatemachine.h"
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define MENUID_PLATERES 2
unsigned long lastProcessedReflowState = 0;
OledDisplay::OledDisplay()
@ -12,8 +14,70 @@ OledDisplay::OledDisplay()
display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT);
}
void OledDisplay::handleButtonStateChange(Pair<ButtonKind, StateChangeEvent<ButtonState>> change)
{
if (change.second.to == ButtonState::PRESSED)
{
if (change.first == ButtonKind::SELECT)
{
OledMenu *selectedMenu = curMenu->getNextMenu();
if (selectedMenu != NULL)
{
curMenu = selectedMenu;
}
} else if (change.first == ButtonKind::BACK) {
OledMenu *selectedMenu = curMenu->parent;
if (selectedMenu != NULL)
{
curMenu = selectedMenu;
}
} else if (change.first == ButtonKind::UP) {
curMenu->goNextItem();
} else if (change.first == ButtonKind::DOWN){
curMenu->goPrevItem();
}
}
}
void OledDisplay::setup()
{
curMenu = new OledMenu();
curMenu->setElements(new OledMenuItem[3]{
OledMenuItem("Reflow\0"),
OledMenuItem("PlateR\0"),
OledMenuItem("Temps\0"),
}, 3);
OledMenu *pickProfilesMenu = new OledMenu(1);
OledMenuItem *pickProfilesMenuItems = new OledMenuItem[nReflowProfiles];
for (int i=0; i<nReflowProfiles; i++) {
pickProfilesMenuItems[i] = OledMenuItem(reflowProfiles[i].name, 100+1);
}
pickProfilesMenu->setElements(pickProfilesMenuItems, nReflowProfiles);
OledMenu *plateRMenu = new OledMenu(MENUID_PLATERES);
OledMenu *tempsMenu = new OledMenu(3);
tempsMenu->setElements(new OledMenuItem[6]{
OledMenuItem("T1\0", 150),
OledMenuItem("T2\0", 151),
OledMenuItem("T3\0", 152),
OledMenuItem("T4\0", 153),
OledMenuItem("T5\0", 154),
OledMenuItem("T6\0", 155),
}, 6);
curMenu->setChildren(new OledMenu*[3]{
pickProfilesMenu,
plateRMenu,
tempsMenu,
}, 3);
curMenu->setChildrenMatrix(3, new uint8_t[3][2]{
{0, 0},
{1, 1},
{2, 2},
});
// curItem = 0; // ROOT
// Setup implementation
bool initialized = display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
if (!initialized)
@ -25,51 +89,37 @@ void OledDisplay::setup()
Serial.println("OLED Display initialized");
}
display.setRotation(0);
display.setCursor(0, 0);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE); // Defaults to white
}
void OledDisplay::loop()
{
StateChangeEvent<ReflowProcessState> *evt = reflowProcessState.getSince(lastProcessedReflowState);
// REdraw only on reflow state change
if (evt != NULL)
ReflowProcessState state = reflowProcessState.get();
if (state == USER_INPUT)
{
lastProcessedReflowState = millis();
ReflowProcessState reflowState = reflowProcessState.get();
if (reflowState == USER_INPUT)
{
handleUserInputState();
return;
}
else if (reflowState == SOAK)
{
handleSoakState();
return;
}
else if (reflowState == REFLOW)
{
handleReflowState();
return;
}
else if (reflowState == ReflowProcessState::COOL)
{
handleCoolingState();
return;
}
else if (reflowState == ReflowProcessState::DONE)
{
handleFinishedState();
return;
}
}
display.clearDisplay();
display.setTextSize(2);
if (reflowProcessState.get() == PREHEAT)
{
drawDebug();
OledMenuItem menuItem = curMenu->getCurItem();
display.setTextSize(2);
if (curMenu->identifier == MENUID_PLATERES) {
} else {
// draw menu item with selectors.
display.setRotation(0);
centerText(menuItem.title);
display.setRotation(1);
display.setCursor(0,SCREEN_WIDTH/2-5);
display.print("<");
display.setCursor(SCREEN_HEIGHT-14,SCREEN_WIDTH/2-5);
display.print(">");
}
display.display();
}
// Loop implementation
}
@ -96,35 +146,24 @@ void OledDisplay::drawDebug()
display.display();
}
void OledDisplay::centerText(const char *txt)
{
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
display.setCursor(display.width() / 2 - w / 2, display.height() / 2 -h/2);
display.println(txt);
}
void OledDisplay::handleUserInputState()
{
Serial.println("USER_INPUT_STATE");
display.clearDisplay();
display.setCursor(0, 0);
display.setCursor(0, SCREEN_HEIGHT / 2 + 10);
display.setTextSize(2);
display.println("INPUT_STATE");
display.display();
}
void OledDisplay::handlePreheatState()
{
display.clearDisplay();
display.setCursor(0, 0);
display.println("PREHEATING");
display.display();
}
void OledDisplay::handleSoakState()
{
display.clearDisplay();
display.setCursor(0, 0);
display.println("SOAKING");
display.display();
}
void OledDisplay::handleReflowState()
{
display.clearDisplay();
@ -133,21 +172,3 @@ void OledDisplay::handleReflowState()
display.println("REFLOW");
display.display();
}
void OledDisplay::handleCoolingState()
{
display.clearDisplay();
display.setCursor(0, 0);
display.println("COOLING");
display.display();
}
void OledDisplay::handleFinishedState()
{
display.clearDisplay();
display.setCursor(0, 0);
display.println("Done :)");
display.display();
}

View File

@ -2,22 +2,24 @@
#define __oled_h
#include <Adafruit_SSD1306.h>
#include "../reflow.h"
#include "menustatemachine.h"
class OledDisplay {
public:
OledDisplay();
void setup();
void loop();
void teardown();
void handleButtonStateChange(Pair<ButtonKind, StateChangeEvent<ButtonState>> change);
private:
OledMenu *curMenu;
Adafruit_SSD1306 display;
void drawDebug();
void handleUserInputState();
void handlePreheatState();
void handleSoakState();
void handleReflowState();
void handleCoolingState();
void handleFinishedState();
void centerText(const char * text);
};

View File

@ -12,4 +12,6 @@ extern Thermistor thermistor3;
extern Thermistor thermistor4;
extern Thermistor thermistor5;
extern Thermistor thermistor6;
extern ReflowProfile reflowProfiles[];
extern int nReflowProfiles;
#endif

View File

@ -19,6 +19,7 @@ void LEDS::handleButtonStateChange(Pair<ButtonKind, StateChangeEvent<ButtonState
{
switch (change.first) {
case ButtonKind::UP:
Serial.println("MEOW");
if (change.second.to == ButtonState::PRESSED) {
digitalWrite(yellowLED, HIGH);
} else if (!yellowLEDSeleOn) {

View File

@ -43,17 +43,28 @@ LEDS leds = LEDS();
// Declare the PID
ArduPID PID;
OledDisplay oled = OledDisplay();
ReflowProfile profile = ReflowProfile(new ReflowStep[5] {
ReflowProfile reflowProfiles[] = {
ReflowProfile(new ReflowStep[5] {
ReflowStep(ReflowProcessState::PREHEAT, 2, 150),
ReflowStep(ReflowProcessState::SOAK, 3, 180),
ReflowStep(ReflowProcessState::REFLOW, 3, 220, EASE_IN_OUT),
ReflowStep(ReflowProcessState::COOL, 3, 100),
ReflowStep(ReflowProcessState::DONE, 0, 0)
}, "meow\0");
}, "Test\0"),
ReflowProfile(new ReflowStep[5] {
ReflowStep(ReflowProcessState::PREHEAT, 2, 150),
ReflowStep(ReflowProcessState::SOAK, 3, 180),
ReflowStep(ReflowProcessState::REFLOW, 3, 220, EASE_IN_OUT),
ReflowStep(ReflowProcessState::COOL, 3, 100),
ReflowStep(ReflowProcessState::DONE, 0, 0)
}, "Test2\0"),
};
int nReflowProfiles = 2;
void setup()
{
Serial.begin(9600);
Serial.begin(38400);
Serial.println("Starting OLED");
// Set PWM frequency to 64 kHz
@ -61,27 +72,8 @@ void setup()
buttons.setup();
leds.setup();
oled.setup();
char name[20] = "meow\0";
// ReflowProfile profile = ReflowProfile::fromEEPROM(0);
// ReflowProfile profile = ReflowProfile(new ReflowStep[5] {
// ReflowStep(ReflowProcessState::PREHEAT, 30, 150),
// ReflowStep(ReflowProcessState::SOAK, 30, 180),
// ReflowStep(ReflowProcessState::REFLOW, 30, 220),
// ReflowStep(ReflowProcessState::COOL, 30, 100),
// ReflowStep(ReflowProcessState::DONE, 0, 0)
// }, name);
// profile.toEEPROM(0);
Serial.println(profile.name);
for (int i=0; i<5; i++) {
Serial.print(profile.steps[i].duration);
Serial.print(" ");
Serial.println(profile.steps[i].targetTempAtEnd);
}
reflowProcessState = USER_INPUT;
profile.start();
}
void loop()
@ -92,29 +84,30 @@ void loop()
if (k != NULL) {
leds.handleButtonStateChange(*k);
oled.handleButtonStateChange(*k);
if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::SELECT, ButtonState::PRESSED)) {
reflowProcessState.set(ReflowProcessState::PREHEAT);
} else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::BACK, ButtonState::PRESSED)) {
reflowProcessState.set(ReflowProcessState::USER_INPUT);
} else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::UP, ButtonState::PRESSED)) {
reflowProcessState.set(ReflowProcessState::COOL);
} else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::DOWN, ButtonState::PRESSED)) {
reflowProcessState.set(ReflowProcessState::REFLOW);
}
// if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::SELECT, ButtonState::PRESSED)) {
// reflowProcessState.set(ReflowProcessState::PREHEAT);
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::BACK, ButtonState::PRESSED)) {
// reflowProcessState.set(ReflowProcessState::USER_INPUT);
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::UP, ButtonState::PRESSED)) {
// reflowProcessState.set(ReflowProcessState::COOL);
// } else if (ISBUTTONMIGRATEDTOSTATE(*k, ButtonKind::DOWN, ButtonState::PRESSED)) {
// reflowProcessState.set(ReflowProcessState::REFLOW);
// }
}
ReflowStep step = profile.curReflowStep();
if (step.state != reflowProcessState.get()) {
reflowProcessState.set(step.state);
}
// ReflowStep step = profile.curReflowStep();
// if (step.state != reflowProcessState.get()) {
// reflowProcessState.set(step.state);
// }
oled.loop();
if (step.state == ReflowProcessState::DONE) {
profile.start();
return;
}
Serial.print(String(STATE_STR(step.state)) + " " + String(step.duration) + " " + String(step.targetTempAtEnd) + " " + String(profile.getTargetTemp())+"\r");
oled.loop();
// if (step.state == ReflowProcessState::DONE) {
// profile.start();
// return;
// }
// Serial.print(String(STATE_STR(step.state)) + " " + String(step.duration) + " " + String(step.targetTempAtEnd) + " " + String(profile.getTargetTemp())+"\r");
}