Added app modes, extracted into mode controllers.

This commit is contained in:
dejvino
2020-02-02 01:04:10 +01:00
parent f343983184
commit a32fcd8785
32 changed files with 323 additions and 107 deletions
+12
View File
@@ -0,0 +1,12 @@
#ifndef _APPMODE_H_
#define _APPMODE_H_
class AppMode
{
public:
virtual void start();
virtual void loop();
virtual void finish();
};
#endif
+19
View File
@@ -0,0 +1,19 @@
#include "core/common.h"
#include "core/display.h"
#include "ModeRunner.h"
#include "MainMenuMode.h"
#include "BootMode.h"
void BootMode::start()
{}
void BootMode::loop()
{
display_splash_screen();
delay(500);
getModeRunner()->startMainMode(new MainMenuMode());
}
void BootMode::finish()
{}
+9
View File
@@ -0,0 +1,9 @@
#include "AppMode.h"
class BootMode : public AppMode
{
public:
virtual void start();
virtual void loop();
virtual void finish();
};
+25
View File
@@ -0,0 +1,25 @@
#include "core/common.h"
#include "core/buttons.h"
#include "core/display.h"
#include <EPD.h>
#include "MainMenuMode.h"
void MainMenuMode::start()
{}
void MainMenuMode::loop()
{
display_clear();
EPD_print("Main Menu", CENTER, 0);
display_update();
while(1) {
delay(5);
if (buttons_pressed_ok()) {
break;
}
}
}
void MainMenuMode::finish()
{}
+9
View File
@@ -0,0 +1,9 @@
#include "AppMode.h"
class MainMenuMode : public AppMode
{
public:
virtual void start();
virtual void loop();
virtual void finish();
};
+55
View File
@@ -0,0 +1,55 @@
#include "ModeRunner.h"
#include "esp_log.h"
static const char *TAG = "ModeRunner";
void ModeRunner::init()
{
this->modeStackDepth = -1;
}
void ModeRunner::loop()
{
if (this->modeStackDepth < 0) {
ESP_LOGE(TAG, "Cannot run app mode. None activated (depth %d).", this->modeStackDepth);
return;
}
this->modeStack[this->modeStackDepth]->loop();
}
void ModeRunner::startMainMode(AppMode* mode)
{
this->finishMode(NULL);
this->modeStackDepth = -1;
this->startInnerMode(mode);
}
void ModeRunner::startInnerMode(AppMode* mode)
{
if (this->modeStackDepth + 1 >= MODE_STACK_SIZE) {
ESP_LOGE(TAG, "Cannot start inner mode. Stack overflow.");
return;
}
this->modeStackDepth++;
this->modeStack[this->modeStackDepth] = mode;
ESP_LOGI(TAG, "Starting new mode (depth %d).", this->modeStackDepth);
mode->start();
}
void ModeRunner::finishMode(AppMode* mode)
{
for (int i = this->modeStackDepth; i >= 0; i--) {
ESP_LOGI(TAG, "Finishing mode (depth %d).", this->modeStackDepth);
this->modeStack[i]->finish();
this->modeStackDepth--;
if (mode == this->modeStack[i]) {
break;
}
}
}
ModeRunner modeRunner;
ModeRunner* getModeRunner()
{
return &modeRunner;
}
+20
View File
@@ -0,0 +1,20 @@
#include "AppMode.h"
#define MODE_STACK_SIZE 5
class ModeRunner
{
public:
void init();
void loop();
void startMainMode(AppMode* mode);
void startInnerMode(AppMode* mode);
void finishMode(AppMode* mode);
private:
AppMode* modeStack[MODE_STACK_SIZE];
int modeStackDepth = -1;
};
ModeRunner* getModeRunner();
+106
View File
@@ -0,0 +1,106 @@
#include "core/common.h"
#include "string.h"
#include "core/buttons.h"
#include "core/display.h"
#include "reader/Typesetter.h"
#include "reader/TextStorage.h"
#include "reader/PagePrinter.h"
#include "ReaderMode.h"
#include "esp_log.h"
static const char *TAG = "ReaderMode";
// TODO: class members
Typesetter typesetter;
PagePrinter pagePrinter;
TextStorage textStorage;
TextReader* textReader = textStorage.open("/sdcard/book.txt");
Page* pageLast = NULL;
Page* pageCurrent = NULL;
long bookmark = 0;
//bool displaySleeping = false;
void ReaderMode::start()
{
}
void ReaderMode::loop()
{
char text[1024];
if (textReader != NULL) {
if (pageCurrent == NULL) {
size_t read = textReader->read(bookmark, text, sizeof(text));
pageCurrent = typesetter.preparePage(text, read);
pageCurrent->start = bookmark;
}
if (pageLast == NULL) {
// align with the start?
if (bookmark < sizeof(text)) {
size_t read = textReader->read(0, text, sizeof(text));
pageLast = typesetter.preparePage(text, read);
pageLast->start = 0;
} else {
size_t read = textReader->read((bookmark - sizeof(text)), text, sizeof(text));
pageLast = typesetter.preparePreviousPage(text, read);
pageLast->start = bookmark - pageLast->len;
}
}
} else {
typesetter.destroyPage(pageCurrent);
strcpy(text, "File could not be opened.");
pageCurrent = typesetter.preparePage(text, sizeof(text));
}
display_clear();
pagePrinter.print(pageCurrent);
display_update();
//time_t idleStart = clock();
while (1) {
delay(10);
if (buttons_pressed_ok()) {
ESP_LOGI(TAG, "Clear page.");
display_refresh();
break;
}
if (buttons_pressed_plus()) {
ESP_LOGI(TAG, "Turn page PLUS.");
if (pageCurrent != NULL) {
bookmark = pageCurrent->start + pageCurrent->len;
// TODO: limit bookmark to file size
typesetter.destroyPage(pageLast);
pageLast = pageCurrent;
pageCurrent = NULL;
} else {
ESP_LOGW(TAG, "No current page.");
}
break;
}
if (buttons_pressed_minus()) {
ESP_LOGI(TAG, "Turn page MINUS.");
if (pageLast != NULL) {
bookmark = pageLast->start;
typesetter.destroyPage(pageCurrent);
pageCurrent = pageLast;
pageLast = NULL;
} else {
ESP_LOGW(TAG, "No last page.");
}
break;
}
/*if (!displaySleeping && (clock() - idleStart > DISPLAY_SLEEP_TIMEOUT)) {
displaySleeping = true;
ESP_LOGI(TAG, "Display going to sleep after %d ms.", DISPLAY_SLEEP_TIMEOUT);
display_sleep();
}*/
}
/*if (displaySleeping) {
displaySleeping = false;
ESP_LOGI(TAG, "Display waking up.");
display_wake();
}*/
}
void ReaderMode::finish()
{}
+9
View File
@@ -0,0 +1,9 @@
#include "AppMode.h"
class ReaderMode : AppMode
{
public:
virtual void start();
virtual void loop();
virtual void finish();
};
+4
View File
@@ -0,0 +1,4 @@
#include "Page.h"
Page::Page()
{}
+17
View File
@@ -0,0 +1,17 @@
#ifndef _PAGE_H_
#define _PAGE_H_
#include <stdlib.h>
class Page
{
public:
Page();
size_t start;
char* text;
size_t len;
private:
};
#endif
+28
View File
@@ -0,0 +1,28 @@
#include "display.h"
#include "EPD.h"
#include "PagePrinter.h"
#include "esp_log.h"
static const char *TAG = "PagePrinter";
//int pageFont = DEFAULT_FONT;
int pageFont = DEJAVU18_FONT;
PagePrinter::PagePrinter()
{}
void PagePrinter::print(Page* page)
{
if (page->text == NULL) {
ESP_LOGE(TAG, "Page text is NULL");
return;
}
if (page->len == 0) {
return;
}
EPD_setFont(pageFont, NULL);
text_wrap = 1;
EPD_print(page->text, 0, 0);
//EPD_UpdateScreen();
}
+9
View File
@@ -0,0 +1,9 @@
#include "Page.h"
class PagePrinter
{
public:
PagePrinter();
void print(Page* page);
};
@@ -0,0 +1,48 @@
#include "PageSettingsProvider.h"
#include "EPD.h"
#include "EPDspi.h" // TODO: remove after display config is extracted
int PageSettingsProvider::getWidth()
{
return EPD_DISPLAY_WIDTH;
}
int PageSettingsProvider::getHeight()
{
return EPD_DISPLAY_HEIGHT;
}
int PageSettingsProvider::getCharWidth(char c)
{
char txt[2] = { c, 0x00 };
return this->getStringWidth(txt);
}
extern int pageFont;
void activatePageFont()
{
EPD_setFont(pageFont, NULL); // TODO: hack to get the same font as the printer
}
int PageSettingsProvider::getStringWidth(char* string)
{
activatePageFont();
int ret = EPD_getStringWidth(string);
return ret;
}
int PageSettingsProvider::getCharSpace()
{
return font_x_space;
}
int PageSettingsProvider::getLineHeight()
{
activatePageFont();
return EPD_getfontheight();
}
int PageSettingsProvider::getLineSpace()
{
return font_line_space;
}
+12
View File
@@ -0,0 +1,12 @@
class PageSettingsProvider
{
public:
int getWidth();
int getHeight();
int getCharWidth(char c);
int getStringWidth(char* string);
int getCharSpace();
int getLineHeight();
int getLineSpace();
};
+43
View File
@@ -0,0 +1,43 @@
#include <string.h>
#include "TextReader.h"
#include "esp_log.h"
static const char *TAG = "TextReader";
TextReader::TextReader(FILE* file)
{
this->f = file;
}
void TextReader::close()
{
fclose(this->f);
}
size_t TextReader::read(long pos, char* text, size_t len)
{
memset(text, 0, len);
if (pos < 0) {
len += pos;
pos = 0;
}
if (len <= 0) {
return 0;
}
if (this->f == NULL) {
ESP_LOGE(TAG, "File not opened.");
sprintf(text, "File could not be opened.");
return 0;
} else {
fseek(this->f, pos, SEEK_SET);
size_t read = fread(text, 1, len, this->f);
if (read > 0) {
//ESP_LOGI(TAG, "Read content: %s", text);
} else {
ESP_LOGI(TAG, "End of file. Closing.");
fclose(this->f);
this->f = NULL;
}
return read;
}
}
+16
View File
@@ -0,0 +1,16 @@
#include <stdlib.h>
#include <stdio.h>
class TextReader
{
public:
TextReader(FILE* file);
size_t read(long pos, char* text, size_t len);
void close();
private:
FILE* f;
};
+25
View File
@@ -0,0 +1,25 @@
#include "TextStorage.h"
#include "esp_log.h"
static const char *TAG = "TextStorage";
TextStorage::TextStorage()
{}
TextReader* TextStorage::open(char* filename)
{
FILE* f = fopen("/sdcard/book.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "File could not be opened");
return NULL;
}
ESP_LOGI(TAG, "File opened for reading.");
return new TextReader(f);
}
void TextStorage::close(TextReader* reader)
{
reader->close();
delete reader;
ESP_LOGI(TAG, "File closed.");
}
+10
View File
@@ -0,0 +1,10 @@
#include "TextReader.h"
class TextStorage
{
public:
TextStorage();
TextReader* open(char* filename);
void close(TextReader* reader);
};
+82
View File
@@ -0,0 +1,82 @@
#include <string.h>
#include "Typesetter.h"
#include "esp_log.h"
static const char *TAG = "Typesetter";
Typesetter::Typesetter()
{
this->pageSettingsProvider = new PageSettingsProvider(); // TODO: make it a param
}
Typesetter::~Typesetter()
{
delete this->pageSettingsProvider;
}
static Page* extractPage(char* text, size_t len)
{
Page* page = new Page;
page->text = new char[len+1];
memcpy(page->text, text, len);
page->text[len] = 0;
page->len = len;
ESP_LOGI(TAG, "Extracted page (%d bytes):\n%s\n----", page->len, page->text);
return page;
}
Page* Typesetter::preparePage(char* text, size_t len)
{
return this->preparePageInternal(text, len, 0);
}
Page* Typesetter::preparePreviousPage(char* text, size_t len)
{
return this->preparePageInternal(text, len, 1);
}
void Typesetter::destroyPage(Page* page)
{
if (page == NULL) {
return;
}
delete page->text;
delete page;
}
Page* Typesetter::preparePageInternal(char* text, size_t len, int reverse)
{
int page_width = this->pageSettingsProvider->getWidth();
int page_height = this->pageSettingsProvider->getHeight();
int line_height = this->pageSettingsProvider->getLineHeight()
+ this->pageSettingsProvider->getLineSpace();
int line_count = page_height / line_height;
char buf[len+1];
memset(buf, 0, len+1);
int line_start = 0;
ESP_LOGI(TAG, " === Typesetting%s page === ", reverse ? " reversed" : "");
for (int line = 0; line < line_count && line_start < len; line++) {
int i;
for (i = line_start; i < len; i++) {
buf[i] = text[reverse ? (len - i) : (i)];
if (buf[i] == '\n') {
break;
}
int line_width = this->pageSettingsProvider->getStringWidth(&buf[line_start]);
if (line_width > page_width) {
// backtrack
buf[i] = 0;
i--;
break;
}
}
ESP_LOGI(TAG, "Line %d | %s", line, &buf[line_start]);
//ESP_LOGI(TAG, "Line %d [%04d:%04d] | %s | %03d / %03d", line, line_start, i, &buf[line_start],
// this->pageSettingsProvider->getStringWidth(&buf[line_start]), page_width);
line_start = i + 1;
}
return extractPage(text, line_start);
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdlib.h>
#include "Page.h"
#include "PageSettingsProvider.h"
class Typesetter
{
public:
Typesetter();
~Typesetter();
Page* preparePage(char* text, size_t len);
Page* preparePreviousPage(char* text, size_t len);
void destroyPage(Page* page);
private:
Page* preparePageInternal(char* text, size_t len, int direction);
PageSettingsProvider* pageSettingsProvider; // TODO: expose so it may be changed
};