esp32 firmware for a toaster reflow oven WIP!!!!!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
reflower/main/liquid/liquid.c

153 lines
4.8 KiB

#include <malloc.h>
#include <assert.h>
#include <esp_log.h>
#include <rom/queue.h>
#include "liquid.h"
#include "nokia.h"
static const char *TAG = "Liquid";
extern struct Scene *NewScene_Root(void);
static struct SceneEvent Liquid_initTopScene(struct Liquid *container);
static bool processReturnValue(struct Liquid *container, struct SceneEvent result);
struct RunningScene {
struct Scene *scene;
SLIST_ENTRY(RunningScene) next;
} cmd_item_t;
struct Liquid {
SLIST_HEAD(, RunningScene) stack; // stack with the topmost scene as the first element / head
};
static struct SceneEvent Default_onChildReturn(struct Scene *scene, uint32_t tag, int32_t status, void *data) {
if (data) free(data);
return SceneEvent_Repaint();
}
static void addChild(struct Liquid *container, struct Scene *child) {
struct RunningScene *elm = calloc(1, sizeof(struct RunningScene));
if (!child->onChildReturn) child->onChildReturn = Default_onChildReturn;
elm->scene = child;
SLIST_INSERT_HEAD(&container->stack, elm, next);
}
struct Liquid *Liquid_start(void) {
struct Liquid *container = calloc(1, sizeof(struct Liquid));
addChild(container, NewScene_Root());
struct SceneEvent result = Liquid_initTopScene(container);
if (processReturnValue(container, result)) {
Liquid_paint(container);
}
return container;
}
static struct SceneEvent handleSceneEvent(struct Liquid *container, struct SceneEvent event) {
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
struct Scene *newScene;
uint32_t tag;
switch (event.kind) {
case SceneEventKind_Close:
assert(SLIST_NEXT(topmost, next) != NULL);
SLIST_REMOVE_HEAD(&container->stack, next);
tag = topmost->scene->tag;
if (topmost->scene->free) {
topmost->scene->free(topmost->scene);
}
free(topmost->scene);
free(topmost);
topmost = SLIST_FIRST(&container->stack);
// this is always set.
return topmost->scene->onChildReturn(topmost->scene, tag, event.close.status, event.close.data);
case SceneEventKind_OpenChild:
if (!event.open.scene) {
ESP_LOGE(TAG, "Attempt to open NULL scene!");
return SceneEvent_None();
}
newScene = event.open.scene;
newScene->tag = event.open.tag;
addChild(container, newScene);
return Liquid_initTopScene(container);
case SceneEventKind_RequestRepaint:
case SceneEventKind_None:
default:
// this shouldn't get here
return event;
}
}
/**
* returns true if repaint is requested
*/
static bool processReturnValue(struct Liquid *container, struct SceneEvent result) {
bool repaint = false;
while (result.kind != SceneEventKind_None) {
if (result.kind == SceneEventKind_RequestRepaint) {
// Repaint explicitly requested, there's no more chained events.
repaint = true;
break;
}
if (result.kind == SceneEventKind_Close) {
// child close always triggers repaint, but the event handler can return
// another event (e.g. close itself, or open a new child).
repaint = true;
}
// one event can lead to another...
result = handleSceneEvent(container, result);
}
return repaint;
}
bool Liquid_handleInput(struct Liquid *container, struct InputEvent event) {
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
assert(topmost != NULL);
assert(topmost->scene != NULL);
if (topmost->scene->onInput) {
struct SceneEvent result = topmost->scene->onInput(topmost->scene, event);
return processReturnValue(container, result);
} else {
return false;
}
}
bool Liquid_handleTick(struct Liquid *container) {
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
assert(topmost != NULL);
assert(topmost->scene != NULL);
if (topmost->scene->onTick) {
struct SceneEvent result = topmost->scene->onTick(topmost->scene);
return processReturnValue(container, result);
} else {
return false;
}
}
static struct SceneEvent Liquid_initTopScene(struct Liquid *container) {
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
assert(topmost != NULL);
assert(topmost->scene != NULL);
if (topmost->scene->init) {
return topmost->scene->init(topmost->scene);
} else {
return SceneEvent_Repaint();
}
}
void Liquid_paint(struct Liquid *container) {
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
assert(topmost != NULL);
if (topmost->scene->paint) {
topmost->scene->paint(topmost->scene);
}
LCD_updateDisplay();
}