Make ScreenHandler class, fix button handling
This commit is contained in:
parent
698c3a3a43
commit
17fef80253
11 changed files with 484 additions and 410 deletions
|
@ -36,7 +36,7 @@ void taskBitaxeFetch(void *pvParameters)
|
||||||
bitaxeHashrate = std::to_string(static_cast<int>(std::round(doc["hashRate"].as<float>())));
|
bitaxeHashrate = std::to_string(static_cast<int>(std::round(doc["hashRate"].as<float>())));
|
||||||
bitaxeBestDiff = doc["bestDiff"].as<std::string>();
|
bitaxeBestDiff = doc["bestDiff"].as<std::string>();
|
||||||
|
|
||||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BITAXE_HASHRATE || getCurrentScreen() == SCREEN_BITAXE_BESTDIFF))
|
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF))
|
||||||
{
|
{
|
||||||
WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
|
|
@ -200,7 +200,7 @@ void processNewBlock(uint newBlockHeight) {
|
||||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||||
|
|
||||||
if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
||||||
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
|
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
|
||||||
{
|
{
|
||||||
uint64_t timerPeriod = 0;
|
uint64_t timerPeriod = 0;
|
||||||
|
@ -210,7 +210,7 @@ void processNewBlock(uint newBlockHeight) {
|
||||||
timerPeriod = getTimerSeconds();
|
timerPeriod = getTimerSeconds();
|
||||||
esp_timer_stop(screenRotateTimer);
|
esp_timer_stop(screenRotateTimer);
|
||||||
}
|
}
|
||||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||||
if (timerPeriod > 0)
|
if (timerPeriod > 0)
|
||||||
{
|
{
|
||||||
esp_timer_start_periodic(screenRotateTimer,
|
esp_timer_start_periodic(screenRotateTimer,
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "button_handler.hpp"
|
#include "button_handler.hpp"
|
||||||
|
|
||||||
TaskHandle_t buttonTaskHandle = NULL;
|
TaskHandle_t buttonTaskHandle = NULL;
|
||||||
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
ButtonState buttonStates[4];
|
||||||
TickType_t lastDebounceTime = 0;
|
|
||||||
|
|
||||||
#ifdef IS_BTCLOCK_V8
|
#ifdef IS_BTCLOCK_V8
|
||||||
#define BTN_1 256
|
#define BTN_1 256
|
||||||
|
@ -17,65 +16,134 @@ TickType_t lastDebounceTime = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void buttonTask(void *parameter) {
|
void buttonTask(void *parameter) {
|
||||||
while (1) {
|
while (1) {
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
TickType_t currentTime = xTaskGetTickCount();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(mcpMutex);
|
||||||
|
|
||||||
|
if (!digitalRead(MCP_INT_PIN)) {
|
||||||
|
uint16_t intFlags = mcp1.getInterruptFlagRegister();
|
||||||
|
uint16_t intCap = mcp1.getInterruptCaptureRegister();
|
||||||
|
|
||||||
|
// Check button states
|
||||||
|
if (intFlags & BTN_1) handleButtonPress(0);
|
||||||
|
if (intFlags & BTN_2) handleButtonPress(1);
|
||||||
|
if (intFlags & BTN_3) handleButtonPress(2);
|
||||||
|
if (intFlags & BTN_4) handleButtonPress(3);
|
||||||
|
|
||||||
|
// Check for button releases
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (buttonStates[i].isPressed) {
|
||||||
|
bool currentlyPressed = false;
|
||||||
|
switch (i) {
|
||||||
|
case 0: currentlyPressed = (intCap & BTN_1); break;
|
||||||
|
case 1: currentlyPressed = (intCap & BTN_2); break;
|
||||||
|
case 2: currentlyPressed = (intCap & BTN_3); break;
|
||||||
|
case 3: currentlyPressed = (intCap & BTN_4); break;
|
||||||
|
}
|
||||||
|
if (!currentlyPressed) {
|
||||||
|
handleButtonRelease(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for long press on pressed buttons
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (buttonStates[i].isPressed && !buttonStates[i].longPressHandled) {
|
||||||
|
if ((currentTime - buttonStates[i].pressStartTime) >= longPressDelay) {
|
||||||
|
handleLongPress(i);
|
||||||
|
buttonStates[i].longPressHandled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear interrupt state
|
||||||
|
while (!digitalRead(MCP_INT_PIN)) {
|
||||||
|
mcp1.getInterruptCaptureRegister();
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleButtonPress(int buttonIndex) {
|
||||||
TickType_t currentTime = xTaskGetTickCount();
|
TickType_t currentTime = xTaskGetTickCount();
|
||||||
|
ButtonState &state = buttonStates[buttonIndex];
|
||||||
|
|
||||||
if ((currentTime - lastDebounceTime) >= debounceDelay) {
|
if ((currentTime - state.lastPressTime) >= debounceDelay) {
|
||||||
lastDebounceTime = currentTime;
|
state.isPressed = true;
|
||||||
|
state.pressStartTime = currentTime;
|
||||||
std::lock_guard<std::mutex> lock(mcpMutex);
|
state.longPressHandled = false;
|
||||||
|
|
||||||
if (!digitalRead(MCP_INT_PIN)) {
|
// Check for double click
|
||||||
uint16_t intFlags = mcp1.getInterruptFlagRegister();
|
if ((currentTime - state.lastPressTime) <= doubleClickDelay) {
|
||||||
uint16_t intCap = mcp1.getInterruptCaptureRegister();
|
state.clickCount++;
|
||||||
|
if (state.clickCount == 2) {
|
||||||
// Check each button individually
|
handleDoubleClick(buttonIndex);
|
||||||
if (intFlags & BTN_1) handleButton1();
|
state.clickCount = 0;
|
||||||
if (intFlags & BTN_2) handleButton2();
|
}
|
||||||
if (intFlags & BTN_3) handleButton3();
|
} else {
|
||||||
if (intFlags & BTN_4) handleButton4();
|
state.clickCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.lastPressTime = currentTime;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleButtonRelease(int buttonIndex) {
|
||||||
|
TickType_t currentTime = xTaskGetTickCount();
|
||||||
|
ButtonState &state = buttonStates[buttonIndex];
|
||||||
|
|
||||||
// Clear interrupt state
|
state.isPressed = false;
|
||||||
while (!digitalRead(MCP_INT_PIN)) {
|
|
||||||
std::lock_guard<std::mutex> lock(mcpMutex);
|
// If this wasn't a long press or double click, handle as single click
|
||||||
mcp1.getInterruptCaptureRegister();
|
if (!state.longPressHandled && state.clickCount == 1 &&
|
||||||
delay(1); // Small delay to prevent tight loop
|
(currentTime - state.pressStartTime) < longPressDelay) {
|
||||||
|
handleSingleClick(buttonIndex);
|
||||||
|
state.clickCount = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions to handle each button
|
// Button action handlers
|
||||||
void handleButton1() {
|
void handleSingleClick(int buttonIndex) {
|
||||||
toggleTimerActive();
|
switch (buttonIndex) {
|
||||||
|
case 0:
|
||||||
|
toggleTimerActive();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Serial.println("Button 2 single click");
|
||||||
|
ScreenHandler::nextScreen();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Serial.println("Button 3 single click");
|
||||||
|
ScreenHandler::previousScreen();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ScreenHandler::showSystemStatusScreen();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleButton2() {
|
void handleDoubleClick(int buttonIndex) {
|
||||||
nextScreen();
|
Serial.printf("Button %d double clicked\n", buttonIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleButton3() {
|
void handleLongPress(int buttonIndex) {
|
||||||
previousScreen();
|
Serial.printf("Button %d long press detected\n", buttonIndex + 1);
|
||||||
}
|
|
||||||
|
|
||||||
void handleButton4() {
|
|
||||||
showSystemStatusScreen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR handleButtonInterrupt() {
|
void IRAM_ATTR handleButtonInterrupt() {
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupButtonTask() {
|
void setupButtonTask() {
|
||||||
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
|
||||||
&buttonTaskHandle); // Create the FreeRTOS task
|
&buttonTaskHandle);
|
||||||
// Use interrupt instead of task
|
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING);
|
||||||
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,3 +18,37 @@ void handleButton1();
|
||||||
void handleButton2();
|
void handleButton2();
|
||||||
void handleButton3();
|
void handleButton3();
|
||||||
void handleButton4();
|
void handleButton4();
|
||||||
|
|
||||||
|
// New features
|
||||||
|
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
||||||
|
const TickType_t doubleClickDelay = pdMS_TO_TICKS(300); // Maximum time between clicks for double click
|
||||||
|
const TickType_t longPressDelay = pdMS_TO_TICKS(1000); // Time to hold for long press
|
||||||
|
|
||||||
|
// Track timing for each button
|
||||||
|
struct ButtonState {
|
||||||
|
TickType_t lastPressTime = 0;
|
||||||
|
TickType_t pressStartTime = 0;
|
||||||
|
bool isPressed = false;
|
||||||
|
uint8_t clickCount = 0;
|
||||||
|
bool longPressHandled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ButtonState buttonStates[4];
|
||||||
|
|
||||||
|
#ifdef IS_BTCLOCK_V8
|
||||||
|
#define BTN_1 256
|
||||||
|
#define BTN_2 512
|
||||||
|
#define BTN_3 1024
|
||||||
|
#define BTN_4 2048
|
||||||
|
#else
|
||||||
|
#define BTN_1 2048
|
||||||
|
#define BTN_2 1024
|
||||||
|
#define BTN_3 512
|
||||||
|
#define BTN_4 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void handleButtonPress(int buttonIndex);
|
||||||
|
void handleButtonRelease(int buttonIndex);
|
||||||
|
void handleSingleClick(int buttonIndex);
|
||||||
|
void handleDoubleClick(int buttonIndex);
|
||||||
|
void handleLongPress(int buttonIndex);
|
||||||
|
|
|
@ -285,9 +285,9 @@ void setupPreferences()
|
||||||
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
||||||
|
|
||||||
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE))
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE))
|
||||||
setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD));
|
ScreenHandler::setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD));
|
||||||
else
|
else
|
||||||
setCurrentCurrency(CURRENCY_USD);
|
ScreenHandler::setCurrentCurrency(CURRENCY_USD);
|
||||||
|
|
||||||
if (!preferences.isKey("flDisable")) {
|
if (!preferences.isKey("flDisable")) {
|
||||||
preferences.putBool("flDisable", isWhiteVersion() ? false : true);
|
preferences.putBool("flDisable", isWhiteVersion() ? false : true);
|
||||||
|
@ -482,7 +482,7 @@ void setupHardware()
|
||||||
Serial.printf("Error setting pin %d to input pull up\n", i);
|
Serial.printf("Error setting pin %d to input pull up\n", i);
|
||||||
}
|
}
|
||||||
// Enable interrupt on CHANGE for each pin
|
// Enable interrupt on CHANGE for each pin
|
||||||
if (!mcp1.enableInterrupt(i, CHANGE)) {
|
if (!mcp1.enableInterrupt(i, FALLING)) {
|
||||||
Serial.printf("Error enabling interrupt for pin %d\n", i);
|
Serial.printf("Error enabling interrupt for pin %d\n", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ void taskMiningPoolStatsFetch(void *pvParameters)
|
||||||
miningPoolStatsDailyEarnings = 0; // or any other default value
|
miningPoolStatsDailyEarnings = 0; // or any other default value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS))
|
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS))
|
||||||
{
|
{
|
||||||
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
@ -78,7 +78,7 @@ void downloadMiningPoolLogoTask(void *pvParameters) {
|
||||||
PoolFactory::downloadPoolLogo(poolName, poolInterface.get());
|
PoolFactory::downloadPoolLogo(poolName, poolInterface.get());
|
||||||
|
|
||||||
// If we're on the mining pool stats screen, trigger a display update
|
// If we're on the mining pool stats screen, trigger a display update
|
||||||
if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
|
if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
|
||||||
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,7 +276,7 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
|
||||||
timerPeriod = getTimerSeconds();
|
timerPeriod = getTimerSeconds();
|
||||||
esp_timer_stop(screenRotateTimer);
|
esp_timer_stop(screenRotateTimer);
|
||||||
}
|
}
|
||||||
setCurrentScreen(SCREEN_CUSTOM);
|
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||||
|
|
||||||
setEpdContent(textEpdContent);
|
setEpdContent(textEpdContent);
|
||||||
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
|
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
|
||||||
|
|
|
@ -133,9 +133,9 @@ void processNewPrice(uint newPrice, char currency)
|
||||||
}
|
}
|
||||||
lastUpdateMap[currency] = currentTime;
|
lastUpdateMap[currency] = currentTime;
|
||||||
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
||||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||||
getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||||
getCurrentScreen() == SCREEN_MARKET_CAP))
|
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||||
{
|
{
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
|
|
@ -1,343 +1,315 @@
|
||||||
#include "screen_handler.hpp"
|
#include "screen_handler.hpp"
|
||||||
|
|
||||||
// TaskHandle_t priceUpdateTaskHandle;
|
|
||||||
// TaskHandle_t blockUpdateTaskHandle;
|
|
||||||
// TaskHandle_t timeUpdateTaskHandle;
|
|
||||||
TaskHandle_t taskScreenRotateTaskHandle;
|
TaskHandle_t taskScreenRotateTaskHandle;
|
||||||
TaskHandle_t workerTaskHandle;
|
TaskHandle_t workerTaskHandle;
|
||||||
|
|
||||||
|
|
||||||
std::array<std::string, NUM_SCREENS> taskEpdContent = {};
|
|
||||||
std::string priceString;
|
|
||||||
|
|
||||||
#define WORK_QUEUE_SIZE 10
|
|
||||||
QueueHandle_t workQueue = NULL;
|
QueueHandle_t workQueue = NULL;
|
||||||
|
|
||||||
uint currentScreen = SCREEN_BLOCK_HEIGHT;
|
// Initialize static members
|
||||||
uint currentCurrency = CURRENCY_USD;
|
uint ScreenHandler::currentScreen = SCREEN_BLOCK_HEIGHT;
|
||||||
|
uint ScreenHandler::currentCurrency = CURRENCY_USD;
|
||||||
|
|
||||||
void workerTask(void *pvParameters) {
|
std::array<std::string, NUM_SCREENS> taskEpdContent = {};
|
||||||
WorkItem receivedItem;
|
|
||||||
|
|
||||||
while (1) {
|
// Convert existing functions to static member functions
|
||||||
// Wait for a work item to be available in the queue
|
void ScreenHandler::setCurrentScreen(uint newScreen) {
|
||||||
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
|
if (newScreen != SCREEN_CUSTOM) {
|
||||||
// Process the work item based on its type
|
preferences.putUInt("currentScreen", newScreen);
|
||||||
switch (receivedItem.type) {
|
}
|
||||||
case TASK_BITAXE_UPDATE: {
|
currentScreen = newScreen;
|
||||||
if (getCurrentScreen() == SCREEN_BITAXE_HASHRATE) {
|
|
||||||
taskEpdContent =
|
switch (currentScreen) {
|
||||||
parseBitaxeHashRate(getBitAxeHashRate());
|
case SCREEN_TIME: {
|
||||||
} else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) {
|
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||||
taskEpdContent =
|
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||||
parseBitaxeBestDiff(getBitaxeBestDiff());
|
break;
|
||||||
}
|
}
|
||||||
setEpdContent(taskEpdContent);
|
case SCREEN_HALVING_COUNTDOWN:
|
||||||
break;
|
case SCREEN_BLOCK_HEIGHT: {
|
||||||
}
|
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||||
case TASK_MINING_POOL_STATS_UPDATE: {
|
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||||
if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
|
break;
|
||||||
taskEpdContent =
|
}
|
||||||
parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool());
|
case SCREEN_MARKET_CAP:
|
||||||
} else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) {
|
case SCREEN_SATS_PER_CURRENCY:
|
||||||
taskEpdContent =
|
case SCREEN_BTC_TICKER: {
|
||||||
parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel(), *getMiningPool());
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||||
}
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
setEpdContent(taskEpdContent);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case SCREEN_BLOCK_FEE_RATE: {
|
||||||
case TASK_PRICE_UPDATE: {
|
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||||
uint currency = getCurrentCurrency();
|
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||||
uint price = getPrice(currency);
|
break;
|
||||||
|
}
|
||||||
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
|
case SCREEN_BITAXE_BESTDIFF:
|
||||||
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE),
|
case SCREEN_BITAXE_HASHRATE: {
|
||||||
preferences.getBool("mowMode", DEFAULT_MOW_MODE),
|
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) {
|
||||||
preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT)
|
WorkItem bitaxeUpdate = {TASK_BITAXE_UPDATE, 0};
|
||||||
);
|
xQueueSend(workQueue, &bitaxeUpdate, portMAX_DELAY);
|
||||||
} else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) {
|
} else {
|
||||||
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||||
} else {
|
return;
|
||||||
taskEpdContent =
|
}
|
||||||
parseMarketCap(getBlockHeight(), price, currency,
|
break;
|
||||||
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
}
|
||||||
}
|
case SCREEN_MINING_POOL_STATS_HASHRATE:
|
||||||
|
case SCREEN_MINING_POOL_STATS_EARNINGS: {
|
||||||
setEpdContent(taskEpdContent);
|
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) {
|
||||||
break;
|
WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||||
}
|
xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY);
|
||||||
case TASK_FEE_UPDATE: {
|
} else {
|
||||||
if (getCurrentScreen() == SCREEN_BLOCK_FEE_RATE) {
|
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
|
return;
|
||||||
setEpdContent(taskEpdContent);
|
}
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
case TASK_BLOCK_UPDATE: {
|
|
||||||
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) {
|
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||||
taskEpdContent = parseBlockHeight(getBlockHeight());
|
}
|
||||||
} else {
|
|
||||||
taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
|
void ScreenHandler::setCurrentCurrency(char currency) {
|
||||||
}
|
currentCurrency = currency;
|
||||||
|
preferences.putUChar("lastCurrency", currency);
|
||||||
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN ||
|
}
|
||||||
getCurrentScreen() == SCREEN_BLOCK_HEIGHT) {
|
|
||||||
setEpdContent(taskEpdContent);
|
bool ScreenHandler::isCurrencySpecific(uint screen) {
|
||||||
}
|
switch (screen) {
|
||||||
break;
|
case SCREEN_BTC_TICKER:
|
||||||
}
|
case SCREEN_SATS_PER_CURRENCY:
|
||||||
case TASK_TIME_UPDATE: {
|
case SCREEN_MARKET_CAP:
|
||||||
if (getCurrentScreen() == SCREEN_TIME) {
|
return true;
|
||||||
time_t currentTime;
|
default:
|
||||||
struct tm timeinfo;
|
return false;
|
||||||
time(¤tTime);
|
}
|
||||||
localtime_r(¤tTime, &timeinfo);
|
}
|
||||||
std::string timeString;
|
|
||||||
|
bool ScreenHandler::handleCurrencyRotation(bool forward) {
|
||||||
String minute = String(timeinfo.tm_min);
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
||||||
if (minute.length() < 2) {
|
std::vector<std::string> ac = getActiveCurrencies();
|
||||||
minute = "0" + minute;
|
if (ac.empty()) return false;
|
||||||
}
|
|
||||||
|
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
||||||
timeString =
|
auto it = std::find(ac.begin(), ac.end(), curCode);
|
||||||
std::to_string(timeinfo.tm_hour) + ":" + minute.c_str();
|
|
||||||
timeString.insert(timeString.begin(),
|
if (it == ac.end()) {
|
||||||
NUM_SCREENS - timeString.length(), ' ');
|
// Current currency not found in active currencies - initialize based on direction
|
||||||
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" +
|
setCurrentCurrency(getCurrencyChar(forward ? ac.front() : ac.back()));
|
||||||
std::to_string(timeinfo.tm_mon + 1);
|
setCurrentScreen(getCurrentScreen());
|
||||||
|
return true;
|
||||||
for (uint i = 1; i < NUM_SCREENS; i++) {
|
} else if (forward && curCode != ac.back()) {
|
||||||
taskEpdContent[i] = timeString[i];
|
// Moving forward and not at last currency
|
||||||
}
|
setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) + 1)));
|
||||||
setEpdContent(taskEpdContent);
|
setCurrentScreen(getCurrentScreen());
|
||||||
}
|
return true;
|
||||||
|
} else if (!forward && curCode != ac.front()) {
|
||||||
break;
|
// Moving backward and not at first currency
|
||||||
}
|
setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) - 1)));
|
||||||
// Add more cases for additional task types
|
setCurrentScreen(getCurrentScreen());
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScreenHandler::findNextVisibleScreen(int currentScreen, bool forward) {
|
||||||
|
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
||||||
|
int newScreen;
|
||||||
|
|
||||||
|
if (forward) {
|
||||||
|
newScreen = (currentScreen < screenMappings.size() - 1) ?
|
||||||
|
screenMappings[currentScreen + 1].value : screenMappings.front().value;
|
||||||
|
} else {
|
||||||
|
newScreen = (currentScreen > 0) ?
|
||||||
|
screenMappings[currentScreen - 1].value : screenMappings.back().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = "screen" + String(newScreen) + "Visible";
|
||||||
|
while (!preferences.getBool(key.c_str(), true)) {
|
||||||
|
currentScreen = findScreenIndexByValue(newScreen);
|
||||||
|
if (forward) {
|
||||||
|
newScreen = (currentScreen < screenMappings.size() - 1) ?
|
||||||
|
screenMappings[currentScreen + 1].value : screenMappings.front().value;
|
||||||
|
} else {
|
||||||
|
newScreen = (currentScreen > 0) ?
|
||||||
|
screenMappings[currentScreen - 1].value : screenMappings.back().value;
|
||||||
|
}
|
||||||
|
key = "screen" + String(newScreen) + "Visible";
|
||||||
|
}
|
||||||
|
|
||||||
|
return newScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenHandler::nextScreen() {
|
||||||
|
if (handleCurrencyRotation(true)) return;
|
||||||
|
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||||
|
setCurrentScreen(findNextVisibleScreen(currentIndex, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenHandler::previousScreen() {
|
||||||
|
if (handleCurrencyRotation(false)) return;
|
||||||
|
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||||
|
setCurrentScreen(findNextVisibleScreen(currentIndex, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenHandler::showSystemStatusScreen() {
|
||||||
|
std::array<String, NUM_SCREENS> sysStatusEpdContent;
|
||||||
|
std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), "");
|
||||||
|
|
||||||
|
String ipAddr = WiFi.localIP().toString();
|
||||||
|
String subNet = WiFi.subnetMask().toString();
|
||||||
|
|
||||||
|
sysStatusEpdContent[0] = "IP/Subnet";
|
||||||
|
|
||||||
|
int ipAddrPos = 0;
|
||||||
|
int subnetPos = 0;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) +
|
||||||
|
"/" + subNet.substring(0, subNet.indexOf('.'));
|
||||||
|
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||||
|
subnetPos = subNet.indexOf('.') + 1;
|
||||||
|
ipAddr = ipAddr.substring(ipAddrPos);
|
||||||
|
subNet = subNet.substring(subnetPos);
|
||||||
|
}
|
||||||
|
sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status";
|
||||||
|
|
||||||
|
sysStatusEpdContent[NUM_SCREENS - 1] =
|
||||||
|
String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
|
||||||
|
(int)round(ESP.getHeapSize() / 1024);
|
||||||
|
setCurrentScreen(SCREEN_CUSTOM);
|
||||||
|
setEpdContent(sysStatusEpdContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep these as free functions
|
||||||
|
void workerTask(void *pvParameters) {
|
||||||
|
WorkItem receivedItem;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
|
||||||
|
uint currentScreenValue = ScreenHandler::getCurrentScreen();
|
||||||
|
|
||||||
|
switch (receivedItem.type) {
|
||||||
|
case TASK_BITAXE_UPDATE: {
|
||||||
|
if (currentScreenValue != SCREEN_BITAXE_HASHRATE &&
|
||||||
|
currentScreenValue != SCREEN_BITAXE_BESTDIFF) break;
|
||||||
|
|
||||||
|
taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ?
|
||||||
|
parseBitaxeHashRate(getBitAxeHashRate()) :
|
||||||
|
parseBitaxeBestDiff(getBitaxeBestDiff());
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TASK_MINING_POOL_STATS_UPDATE: {
|
||||||
|
if (currentScreenValue != SCREEN_MINING_POOL_STATS_HASHRATE &&
|
||||||
|
currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break;
|
||||||
|
|
||||||
|
taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ?
|
||||||
|
parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()) :
|
||||||
|
parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(),
|
||||||
|
getMiningPool()->getDailyEarningsLabel(), *getMiningPool());
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TASK_PRICE_UPDATE: {
|
||||||
|
uint currency = ScreenHandler::getCurrentCurrency();
|
||||||
|
uint price = getPrice(currency);
|
||||||
|
|
||||||
|
if (currentScreenValue == SCREEN_BTC_TICKER) {
|
||||||
|
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE),
|
||||||
|
preferences.getBool("mowMode", DEFAULT_MOW_MODE),
|
||||||
|
preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT)
|
||||||
|
);
|
||||||
|
} else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) {
|
||||||
|
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
||||||
|
} else {
|
||||||
|
taskEpdContent =
|
||||||
|
parseMarketCap(getBlockHeight(), price, currency,
|
||||||
|
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TASK_FEE_UPDATE: {
|
||||||
|
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
|
||||||
|
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TASK_BLOCK_UPDATE: {
|
||||||
|
if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) {
|
||||||
|
taskEpdContent = parseBlockHeight(getBlockHeight());
|
||||||
|
} else {
|
||||||
|
taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
|
||||||
|
currentScreenValue == SCREEN_BLOCK_HEIGHT) {
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TASK_TIME_UPDATE: {
|
||||||
|
if (currentScreenValue == SCREEN_TIME) {
|
||||||
|
time_t currentTime;
|
||||||
|
struct tm timeinfo;
|
||||||
|
time(¤tTime);
|
||||||
|
localtime_r(¤tTime, &timeinfo);
|
||||||
|
std::string timeString;
|
||||||
|
|
||||||
|
String minute = String(timeinfo.tm_min);
|
||||||
|
if (minute.length() < 2) {
|
||||||
|
minute = "0" + minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeString =
|
||||||
|
std::to_string(timeinfo.tm_hour) + ":" + minute.c_str();
|
||||||
|
timeString.insert(timeString.begin(),
|
||||||
|
NUM_SCREENS - timeString.length(), ' ');
|
||||||
|
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" +
|
||||||
|
std::to_string(timeinfo.tm_mon + 1);
|
||||||
|
|
||||||
|
for (uint i = 1; i < NUM_SCREENS; i++) {
|
||||||
|
taskEpdContent[i] = timeString[i];
|
||||||
|
}
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Add more cases for additional task types
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void taskScreenRotate(void *pvParameters) {
|
void taskScreenRotate(void *pvParameters) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
ScreenHandler::nextScreen();
|
||||||
nextScreen();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupTasks() {
|
void setupTasks() {
|
||||||
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
||||||
|
|
||||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||||
&workerTaskHandle);
|
&workerTaskHandle);
|
||||||
|
|
||||||
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
|
||||||
&taskScreenRotateTaskHandle);
|
&taskScreenRotateTaskHandle);
|
||||||
|
|
||||||
waitUntilNoneBusy();
|
waitUntilNoneBusy();
|
||||||
|
|
||||||
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
|
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
|
||||||
setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
|
ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint getCurrentScreen() { return currentScreen; }
|
void cleanup() {
|
||||||
|
vQueueDelete(workQueue);
|
||||||
void setCurrentScreen(uint newScreen) {
|
// Add any other cleanup needed
|
||||||
if (newScreen != SCREEN_CUSTOM) {
|
|
||||||
preferences.putUInt("currentScreen", newScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentScreen = newScreen;
|
|
||||||
|
|
||||||
switch (currentScreen) {
|
|
||||||
case SCREEN_TIME: {
|
|
||||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
|
||||||
// xTaskNotifyGive(timeUpdateTaskHandle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCREEN_HALVING_COUNTDOWN:
|
|
||||||
case SCREEN_BLOCK_HEIGHT: {
|
|
||||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
|
||||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCREEN_MARKET_CAP:
|
|
||||||
case SCREEN_SATS_PER_CURRENCY:
|
|
||||||
case SCREEN_BTC_TICKER: {
|
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
|
||||||
// xTaskNotifyGive(priceUpdateTaskHandle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCREEN_BLOCK_FEE_RATE: {
|
|
||||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCREEN_BITAXE_BESTDIFF:
|
|
||||||
case SCREEN_BITAXE_HASHRATE: {
|
|
||||||
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) {
|
|
||||||
WorkItem bitaxeUpdate = {TASK_BITAXE_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &bitaxeUpdate, portMAX_DELAY);
|
|
||||||
} else {
|
|
||||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCREEN_MINING_POOL_STATS_HASHRATE:
|
|
||||||
case SCREEN_MINING_POOL_STATS_EARNINGS: {
|
|
||||||
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) {
|
|
||||||
WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
|
||||||
xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY);
|
|
||||||
} else {
|
|
||||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCurrencySpecific(uint screen) {
|
|
||||||
switch (screen) {
|
|
||||||
case SCREEN_BTC_TICKER:
|
|
||||||
case SCREEN_SATS_PER_CURRENCY:
|
|
||||||
case SCREEN_MARKET_CAP:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextScreen() {
|
|
||||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
|
||||||
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
|
||||||
|
|
||||||
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
|
||||||
std::vector<std::string> ac = getActiveCurrencies();
|
|
||||||
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
|
||||||
if (getCurrencyCode(getCurrentCurrency()) != ac.back()) {
|
|
||||||
auto it = std::find(ac.begin(), ac.end(), curCode);
|
|
||||||
if (it != ac.end()) {
|
|
||||||
size_t index = std::distance(ac.begin(), it);
|
|
||||||
setCurrentCurrency(getCurrencyChar(ac.at(index+1)));
|
|
||||||
setCurrentScreen(getCurrentScreen());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setCurrentCurrency(getCurrencyChar(ac.front()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int newCurrentScreen;
|
|
||||||
|
|
||||||
if (currentIndex < screenMappings.size() - 1) {
|
|
||||||
newCurrentScreen = (screenMappings[currentIndex + 1].value);
|
|
||||||
} else {
|
|
||||||
newCurrentScreen = screenMappings.front().value;
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
|
||||||
|
|
||||||
while (!preferences.getBool(key.c_str(), true)) {
|
|
||||||
currentIndex = findScreenIndexByValue(newCurrentScreen);
|
|
||||||
if (currentIndex < screenMappings.size() - 1) {
|
|
||||||
newCurrentScreen = (screenMappings[currentIndex + 1].value);
|
|
||||||
} else {
|
|
||||||
newCurrentScreen = screenMappings.front().value;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentScreen(newCurrentScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void previousScreen() {
|
|
||||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
|
||||||
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
|
||||||
|
|
||||||
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
|
||||||
std::vector<std::string> ac = getActiveCurrencies();
|
|
||||||
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
|
||||||
if (getCurrencyCode(getCurrentCurrency()) != ac.front()) {
|
|
||||||
auto it = std::find(ac.begin(), ac.end(), curCode);
|
|
||||||
if (it != ac.end()) {
|
|
||||||
size_t index = std::distance(ac.begin(), it);
|
|
||||||
setCurrentCurrency(getCurrencyChar(ac.at(index-1)));
|
|
||||||
setCurrentScreen(getCurrentScreen());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setCurrentCurrency(getCurrencyChar(ac.back()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int newCurrentScreen;
|
|
||||||
|
|
||||||
if (currentIndex > 0) {
|
|
||||||
newCurrentScreen = screenMappings[currentIndex - 1].value;
|
|
||||||
} else {
|
|
||||||
newCurrentScreen = screenMappings.back().value;
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
|
||||||
|
|
||||||
while (!preferences.getBool(key.c_str(), true)) {
|
|
||||||
int currentIndex = findScreenIndexByValue(newCurrentScreen);
|
|
||||||
if (currentIndex > 0) {
|
|
||||||
newCurrentScreen = screenMappings[currentIndex - 1].value;
|
|
||||||
} else {
|
|
||||||
newCurrentScreen = screenMappings.back().value;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
|
||||||
}
|
|
||||||
setCurrentScreen(newCurrentScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showSystemStatusScreen() {
|
|
||||||
std::array<String, NUM_SCREENS> sysStatusEpdContent;
|
|
||||||
std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), "");
|
|
||||||
|
|
||||||
|
|
||||||
String ipAddr = WiFi.localIP().toString();
|
|
||||||
String subNet = WiFi.subnetMask().toString();
|
|
||||||
|
|
||||||
sysStatusEpdContent[0] = "IP/Subnet";
|
|
||||||
|
|
||||||
int ipAddrPos = 0;
|
|
||||||
int subnetPos = 0;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) +
|
|
||||||
"/" + subNet.substring(0, subNet.indexOf('.'));
|
|
||||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
|
||||||
subnetPos = subNet.indexOf('.') + 1;
|
|
||||||
ipAddr = ipAddr.substring(ipAddrPos);
|
|
||||||
subNet = subNet.substring(subnetPos);
|
|
||||||
}
|
|
||||||
sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status";
|
|
||||||
|
|
||||||
sysStatusEpdContent[NUM_SCREENS - 1] =
|
|
||||||
String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
|
|
||||||
(int)round(ESP.getHeapSize() / 1024);
|
|
||||||
setCurrentScreen(SCREEN_CUSTOM);
|
|
||||||
setEpdContent(sysStatusEpdContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCurrentCurrency(char currency) {
|
|
||||||
currentCurrency = currency;
|
|
||||||
preferences.putUChar("lastCurrency", currency);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint getCurrentCurrency() {
|
|
||||||
return currentCurrency;
|
|
||||||
}
|
}
|
|
@ -11,12 +11,10 @@
|
||||||
#include "lib/epd.hpp"
|
#include "lib/epd.hpp"
|
||||||
#include "lib/shared.hpp"
|
#include "lib/shared.hpp"
|
||||||
|
|
||||||
// extern TaskHandle_t priceUpdateTaskHandle;
|
#define WORK_QUEUE_SIZE 10
|
||||||
// extern TaskHandle_t blockUpdateTaskHandle;
|
|
||||||
// extern TaskHandle_t timeUpdateTaskHandle;
|
|
||||||
extern TaskHandle_t workerTaskHandle;
|
extern TaskHandle_t workerTaskHandle;
|
||||||
extern TaskHandle_t taskScreenRotateTaskHandle;
|
extern TaskHandle_t taskScreenRotateTaskHandle;
|
||||||
|
|
||||||
extern QueueHandle_t workQueue;
|
extern QueueHandle_t workQueue;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -33,24 +31,26 @@ typedef struct {
|
||||||
char data;
|
char data;
|
||||||
} WorkItem;
|
} WorkItem;
|
||||||
|
|
||||||
|
class ScreenHandler {
|
||||||
|
private:
|
||||||
|
static uint currentScreen;
|
||||||
|
static uint currentCurrency;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static uint getCurrentScreen() { return currentScreen; }
|
||||||
|
static uint getCurrentCurrency() { return currentCurrency; }
|
||||||
|
static void setCurrentScreen(uint newScreen);
|
||||||
|
static void setCurrentCurrency(char currency);
|
||||||
|
static void nextScreen();
|
||||||
|
static void previousScreen();
|
||||||
|
static void showSystemStatusScreen();
|
||||||
|
static bool isCurrencySpecific(uint screen);
|
||||||
|
static bool handleCurrencyRotation(bool forward);
|
||||||
|
static int findNextVisibleScreen(int currentScreen, bool forward);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep as free functions since they deal with FreeRTOS tasks
|
||||||
void workerTask(void *pvParameters);
|
void workerTask(void *pvParameters);
|
||||||
uint getCurrentScreen();
|
|
||||||
void setCurrentScreen(uint newScreen);
|
|
||||||
void nextScreen();
|
|
||||||
void previousScreen();
|
|
||||||
|
|
||||||
void showSystemStatusScreen();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// void taskPriceUpdate(void *pvParameters);
|
|
||||||
// void taskBlockUpdate(void *pvParameters);
|
|
||||||
// void taskTimeUpdate(void *pvParameters);
|
|
||||||
void taskScreenRotate(void *pvParameters);
|
void taskScreenRotate(void *pvParameters);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setupTasks();
|
void setupTasks();
|
||||||
void setCurrentCurrency(char currency);
|
void cleanup();
|
||||||
|
|
||||||
uint getCurrentCurrency();
|
|
|
@ -228,7 +228,7 @@ JsonDocument getStatusObject()
|
||||||
{
|
{
|
||||||
JsonDocument root;
|
JsonDocument root;
|
||||||
|
|
||||||
root["currentScreen"] = getCurrentScreen();
|
root["currentScreen"] = ScreenHandler::getCurrentScreen();
|
||||||
root["numScreens"] = NUM_SCREENS;
|
root["numScreens"] = NUM_SCREENS;
|
||||||
root["timerRunning"] = isTimerActive();
|
root["timerRunning"] = isTimerActive();
|
||||||
root["espUptime"] = esp_timer_get_time() / 1000000;
|
root["espUptime"] = esp_timer_get_time() / 1000000;
|
||||||
|
@ -248,7 +248,7 @@ JsonDocument getStatusObject()
|
||||||
conStatus["nostr"] = nostrConnected();
|
conStatus["nostr"] = nostrConnected();
|
||||||
|
|
||||||
root["rssi"] = WiFi.RSSI();
|
root["rssi"] = WiFi.RSSI();
|
||||||
root["currency"] = getCurrencyCode(getCurrentCurrency());
|
root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency());
|
||||||
#ifdef HAS_FRONTLIGHT
|
#ifdef HAS_FRONTLIGHT
|
||||||
std::vector<uint16_t> statuses = frontlightGetStatus();
|
std::vector<uint16_t> statuses = frontlightGetStatus();
|
||||||
uint16_t arr[NUM_SCREENS];
|
uint16_t arr[NUM_SCREENS];
|
||||||
|
@ -386,7 +386,7 @@ void onApiShowScreen(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
const AsyncWebParameter *p = request->getParam("s");
|
const AsyncWebParameter *p = request->getParam("s");
|
||||||
uint currentScreen = p->value().toInt();
|
uint currentScreen = p->value().toInt();
|
||||||
setCurrentScreen(currentScreen);
|
ScreenHandler::setCurrentScreen(currentScreen);
|
||||||
}
|
}
|
||||||
request->send(HTTP_OK);
|
request->send(HTTP_OK);
|
||||||
}
|
}
|
||||||
|
@ -398,9 +398,9 @@ void onApiShowScreen(AsyncWebServerRequest *request)
|
||||||
void onApiScreenControl(AsyncWebServerRequest *request) {
|
void onApiScreenControl(AsyncWebServerRequest *request) {
|
||||||
const String& action = request->url();
|
const String& action = request->url();
|
||||||
if (action.endsWith("/next")) {
|
if (action.endsWith("/next")) {
|
||||||
nextScreen();
|
ScreenHandler::nextScreen();
|
||||||
} else if (action.endsWith("/previous")) {
|
} else if (action.endsWith("/previous")) {
|
||||||
previousScreen();
|
ScreenHandler::previousScreen();
|
||||||
}
|
}
|
||||||
request->send(HTTP_OK);
|
request->send(HTTP_OK);
|
||||||
}
|
}
|
||||||
|
@ -421,7 +421,7 @@ void onApiShowText(AsyncWebServerRequest *request)
|
||||||
|
|
||||||
setEpdContent(textEpdContent);
|
setEpdContent(textEpdContent);
|
||||||
}
|
}
|
||||||
setCurrentScreen(SCREEN_CUSTOM);
|
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||||
request->send(HTTP_OK);
|
request->send(HTTP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +439,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
|
|
||||||
setEpdContent(epdContent);
|
setEpdContent(epdContent);
|
||||||
|
|
||||||
setCurrentScreen(SCREEN_CUSTOM);
|
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
|
||||||
request->send(HTTP_OK);
|
request->send(HTTP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,8 +998,8 @@ void onApiShowCurrency(AsyncWebServerRequest *request)
|
||||||
|
|
||||||
char curChar = getCurrencyChar(currency);
|
char curChar = getCurrencyChar(currency);
|
||||||
|
|
||||||
setCurrentCurrency(curChar);
|
ScreenHandler::setCurrentCurrency(curChar);
|
||||||
setCurrentScreen(getCurrentScreen());
|
ScreenHandler::setCurrentScreen(ScreenHandler::getCurrentScreen());
|
||||||
|
|
||||||
request->send(HTTP_OK);
|
request->send(HTTP_OK);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue