btclock_v3/src/lib/screen_handler.cpp

355 lines
11 KiB
C++
Raw Normal View History

2023-11-07 00:11:12 +00:00
#include "screen_handler.hpp"
// TaskHandle_t priceUpdateTaskHandle;
// TaskHandle_t blockUpdateTaskHandle;
// TaskHandle_t timeUpdateTaskHandle;
2023-11-07 20:26:15 +00:00
TaskHandle_t taskScreenRotateTaskHandle;
TaskHandle_t workerTaskHandle;
2023-11-07 20:26:15 +00:00
esp_timer_handle_t screenRotateTimer;
esp_timer_handle_t minuteTimer;
2023-11-07 00:11:12 +00:00
2023-11-30 21:38:01 +00:00
std::array<std::string, NUM_SCREENS> taskEpdContent = {"", "", "", "",
"", "", ""};
2023-11-07 00:11:12 +00:00
std::string priceString;
#define WORK_QUEUE_SIZE 10
QueueHandle_t workQueue = NULL;
2023-11-07 20:26:15 +00:00
uint currentScreen;
2023-11-07 00:11:12 +00:00
2023-11-30 21:38:01 +00:00
void workerTask(void *pvParameters) {
WorkItem receivedItem;
while (1) {
// Wait for a work item to be available in the queue
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
uint firstIndex = 0;
// Process the work item based on its type
switch (receivedItem.type) {
2024-07-29 18:49:46 +00:00
case TASK_BITAXE_UPDATE: {
if (getCurrentScreen() == SCREEN_BITAXE_HASHRATE) {
taskEpdContent =
parseBitaxeHashRate(getBitAxeHashRate());
} else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) {
taskEpdContent =
parseBitaxeBestDiff(getBitaxeBestDiff());
}
setEpdContent(taskEpdContent);
}
break;
2023-11-30 21:56:50 +00:00
case TASK_PRICE_UPDATE: {
uint price = getPrice();
2024-08-14 22:37:50 +00:00
u_char priceSymbol = '$';
if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) {
2023-11-30 21:56:50 +00:00
priceSymbol = '[';
}
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
taskEpdContent = parsePriceData(price, priceSymbol, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE));
2023-11-30 21:56:50 +00:00
} else if (getCurrentScreen() == SCREEN_MSCW_TIME) {
taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
2023-11-30 21:56:50 +00:00
} else {
taskEpdContent =
parseMarketCap(getBlockHeight(), price, priceSymbol,
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
2023-11-30 21:56:50 +00:00
}
2023-11-08 11:18:59 +00:00
2023-11-30 21:38:01 +00:00
setEpdContent(taskEpdContent);
2023-11-30 21:56:50 +00:00
break;
2023-11-30 21:38:01 +00:00
}
case TASK_FEE_UPDATE: {
if (getCurrentScreen() == SCREEN_BLOCK_FEE_RATE) {
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
setEpdContent(taskEpdContent);
}
break;
}
2023-11-30 21:56:50 +00:00
case TASK_BLOCK_UPDATE: {
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) {
taskEpdContent = parseBlockHeight(getBlockHeight());
} else {
taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
2023-11-30 21:38:01 +00:00
}
2023-11-30 21:56:50 +00:00
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN ||
getCurrentScreen() == SCREEN_BLOCK_HEIGHT) {
setEpdContent(taskEpdContent);
2023-11-30 21:38:01 +00:00
}
2023-11-30 21:56:50 +00:00
break;
2023-11-08 11:18:59 +00:00
}
2023-11-30 21:56:50 +00:00
case TASK_TIME_UPDATE: {
if (getCurrentScreen() == SCREEN_TIME) {
time_t currentTime;
struct tm timeinfo;
time(&currentTime);
localtime_r(&currentTime, &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);
}
2023-11-08 11:18:59 +00:00
2023-11-30 21:56:50 +00:00
break;
}
// Add more cases for additional task types
2023-11-30 21:38:01 +00:00
}
2023-11-07 20:26:15 +00:00
}
2023-11-30 21:38:01 +00:00
}
2023-11-07 20:26:15 +00:00
}
2023-11-30 21:38:01 +00:00
void taskScreenRotate(void *pvParameters) {
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
2024-07-29 18:49:46 +00:00
nextScreen();
2023-11-30 21:38:01 +00:00
}
2023-11-07 20:26:15 +00:00
}
2023-11-30 21:38:01 +00:00
void IRAM_ATTR minuteTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
if (priceFetchTaskHandle != NULL) {
vTaskNotifyGiveFromISR(priceFetchTaskHandle, &xHigherPriorityTaskWoken);
}
2024-07-29 18:49:46 +00:00
if (bitaxeFetchTaskHandle != NULL) {
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
}
2023-11-30 21:38:01 +00:00
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
void IRAM_ATTR screenRotateTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
2023-11-07 20:26:15 +00:00
}
2023-11-07 00:11:12 +00:00
2023-11-30 21:38:01 +00:00
void setupTasks() {
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
2023-11-30 21:38:01 +00:00
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
&workerTaskHandle);
2023-11-30 21:38:01 +00:00
xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY,
&taskScreenRotateTaskHandle);
2023-11-30 21:38:01 +00:00
waitUntilNoneBusy();
setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
2023-11-07 20:26:15 +00:00
}
2023-11-30 21:38:01 +00:00
void setupTimeUpdateTimer(void *pvParameters) {
const esp_timer_create_args_t minuteTimerConfig = {
.callback = &minuteTimerISR, .name = "minute_timer"};
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
esp_timer_create(&minuteTimerConfig, &minuteTimer);
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
time_t currentTime;
struct tm timeinfo;
time(&currentTime);
localtime_r(&currentTime, &timeinfo);
uint32_t secondsUntilNextMinute = 60 - timeinfo.tm_sec;
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
if (secondsUntilNextMinute > 0)
vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000)));
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
esp_timer_start_periodic(minuteTimer, usPerMinute);
2023-11-30 21:38:01 +00:00
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
// xTaskNotifyGive(timeUpdateTaskHandle);
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
vTaskDelete(NULL);
2023-11-07 20:26:15 +00:00
}
2023-11-30 21:38:01 +00:00
void setupScreenRotateTimer(void *pvParameters) {
const esp_timer_create_args_t screenRotateTimerConfig = {
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) {
2023-11-30 21:38:01 +00:00
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
}
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
vTaskDelete(NULL);
2023-11-07 20:26:15 +00:00
}
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); }
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
2023-11-30 21:38:01 +00:00
void setTimerActive(bool status) {
if (status) {
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
queueLedEffect(LED_EFFECT_START_TIMER);
preferences.putBool("timerActive", true);
} else {
esp_timer_stop(screenRotateTimer);
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false);
}
2023-11-07 20:26:15 +00:00
2023-11-30 21:56:50 +00:00
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
2023-11-08 11:18:59 +00:00
}
2023-11-30 21:38:01 +00:00
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
uint getCurrentScreen() { return currentScreen; }
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
void setCurrentScreen(uint newScreen) {
if (newScreen != SCREEN_CUSTOM) {
preferences.putUInt("currentScreen", newScreen);
}
2023-11-07 20:26:15 +00:00
2023-11-30 21:38:01 +00:00
currentScreen = newScreen;
2023-11-30 21:38:01 +00:00
switch (currentScreen) {
2023-11-30 21:56:50 +00:00
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_MSCW_TIME:
case SCREEN_BTC_TICKER: {
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
// xTaskNotifyGive(priceUpdateTaskHandle);
break;
}
2024-03-10 19:37:45 +00:00
case SCREEN_BLOCK_FEE_RATE: {
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
break;
}
2024-07-29 18:49:46 +00:00
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;
}
2023-11-30 21:38:01 +00:00
}
2023-11-30 21:56:50 +00:00
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
2023-11-08 11:18:59 +00:00
}
2023-11-30 21:38:01 +00:00
void nextScreen() {
2024-07-29 18:49:46 +00:00
int currentIndex = findScreenIndexByValue(getCurrentScreen());
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
int newCurrentScreen;
if (currentIndex < screenMappings.size() - 1) {
newCurrentScreen = (screenMappings[currentIndex + 1].value);
} else {
newCurrentScreen = screenMappings.front().value;
}
2024-09-02 20:44:23 +00:00
String key = "screen" + String(newCurrentScreen) + "Visible";
2023-11-08 11:18:59 +00:00
2023-11-30 21:38:01 +00:00
while (!preferences.getBool(key.c_str(), true)) {
2024-07-29 18:49:46 +00:00
currentIndex = findScreenIndexByValue(newCurrentScreen);
if (currentIndex < screenMappings.size() - 1) {
newCurrentScreen = (screenMappings[currentIndex + 1].value);
} else {
newCurrentScreen = screenMappings.front().value;
}
2023-11-30 21:38:01 +00:00
key = "screen" + String(newCurrentScreen) + "Visible";
}
2024-09-02 20:44:23 +00:00
2023-11-30 21:38:01 +00:00
setCurrentScreen(newCurrentScreen);
2023-11-08 11:18:59 +00:00
}
2023-11-30 21:38:01 +00:00
void previousScreen() {
2024-07-29 18:49:46 +00:00
int currentIndex = findScreenIndexByValue(getCurrentScreen());
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
int newCurrentScreen;
if (currentIndex > 0) {
newCurrentScreen = screenMappings[currentIndex - 1].value;
} else {
newCurrentScreen = screenMappings.back().value;
}
2023-11-30 21:38:01 +00:00
String key = "screen" + String(newCurrentScreen) + "Visible";
2023-11-08 11:18:59 +00:00
2023-11-30 21:38:01 +00:00
while (!preferences.getBool(key.c_str(), true)) {
2024-07-29 18:49:46 +00:00
int currentIndex = findScreenIndexByValue(newCurrentScreen);
if (currentIndex > 0) {
newCurrentScreen = screenMappings[currentIndex - 1].value;
} else {
newCurrentScreen = screenMappings.back().value;
}
2023-11-30 21:38:01 +00:00
key = "screen" + String(newCurrentScreen) + "Visible";
}
setCurrentScreen(newCurrentScreen);
2023-11-08 11:18:59 +00:00
}
2023-11-30 21:38:01 +00:00
void showSystemStatusScreen() {
2024-09-02 20:44:23 +00:00
std::array<String, NUM_SCREENS> sysStatusEpdContent;
std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), "");
2023-11-30 21:38:01 +00:00
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);
2023-11-07 00:11:12 +00:00
}