Files
e-ink_F1_Display/src/main.cpp
T

174 lines
4.9 KiB
C++

#include <stdlib.h>
#include <Arduino.h>
#include <WiFi.h>
#include <time.h>
#include "F1_api.h"
#include "FreeRTOS.h"
#include "task.h"
#include <semphr.h>
#include "config.h"
extern "C" {
#include "DEV_Config.h"
#include "EPD_4in2_V2.h"
#include "GUI_Paint.h"
#include "ImageData.h"
}
static UBYTE displayBuffer[(EPD_4IN2_V2_WIDTH / 8) * EPD_4IN2_V2_HEIGHT];
static constexpr UWORD COUNTER_WIDTH = 400;
static constexpr UWORD COUNTER_HEIGHT = 38;
static constexpr UWORD COUNTER_Y = 20;
static UBYTE counterBuffer[(COUNTER_WIDTH / 8) * COUNTER_HEIGHT];
static int counter = 0;
data_struct_t race_data;
SemaphoreHandle_t dataMutex;
void wifi_connect() {
WiFi.setHostname(DEVICE_HOSTNAME);
Serial.println("Connecting to WiFi...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
for (int attempt = 0; attempt < WIFI_MAXIMUM_RETRY; ++attempt) {
const unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
delay(250);
}
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Connected. IP address: ");
Serial.println(WiFi.localIP());
return;
}
if (attempt + 1 < WIFI_MAXIMUM_RETRY) {
Serial.println("WiFi connection failed; retrying...");
WiFi.disconnect();
delay(500);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
}
Serial.println("Failed to connect to WiFi.");
}
void sync_time() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Skipping NTP synchronization because WiFi is disconnected.");
return;
}
NTP.begin("pool.ntp.org", "time.nist.gov");
const bool synchronized = NTP.waitSet(10000);
setenv("TZ", TIMEZONE, 1);
tzset();
struct tm timeinfo;
const time_t now = time(nullptr);
if (synchronized && localtime_r(&now, &timeinfo) != nullptr) {
Serial.print("Time synchronized: ");
Serial.println(asctime(&timeinfo));
} else {
Serial.println("Failed to synchronize time within 10 seconds.");
}
}
bool readLocalTime(struct tm* result) {
const time_t now = time(nullptr);
return localtime_r(&now, result) != nullptr;
}
void display_loop(void *pvParameters) {
static data_struct_t local_data;
while (true) {
static unsigned long lastRefresh = 0;
static char counterStr[32];
const unsigned long elapsed = millis() - lastRefresh;
if (elapsed < 10000) {
vTaskDelay(pdMS_TO_TICKS(10000 - elapsed));
continue;
}
lastRefresh = millis();
counter++;
if (xSemaphoreTake(dataMutex, MUTEX_TIMEOUT_TICKS)) {
local_data = race_data;
xSemaphoreGive(dataMutex);
//Display will continue to use old data
} else {
Serial.print("");
Serial.println("Failed to acquire mutex in display thread!");
}
if (local_data.meeting_info.meeting_key == 0) {
snprintf(counterStr, sizeof(counterStr), "Counter: %d", counter);
Serial.print("");
Serial.println(counterStr);
} else {
snprintf(counterStr, sizeof(counterStr), "%s", local_data.meeting_info.meeting_name);
}
Paint_Clear(WHITE);
if (local_data.session_info.date_start[0] != 0) {
Serial.print("");
Serial.printf("date start: %s\n", local_data.session_info.date_start);
Paint_DrawString_EN(10, 22, local_data.session_info.date_start, &Font16, WHITE, BLACK);
}
Paint_DrawString_EN(10, 0, counterStr, &Font16, WHITE, BLACK);
EPD_4IN2_V2_PartialDisplay(
counterBuffer,
0,
COUNTER_Y,
COUNTER_WIDTH,
COUNTER_Y + COUNTER_HEIGHT);
vTaskDelay(pdMS_TO_TICKS(100)); // Add a small delay to prevent busy looping
}
}
void setup() {
Serial.begin(115200);
dataMutex = xSemaphoreCreateMutex();
if (dataMutex == NULL) {
Serial.println("Failed to create mutex!");
while(1);
}
if (DEV_Module_Init() != 0) {
Serial.println("Failed to initialize display module.");
return;
}
EPD_4IN2_V2_Init();
Serial.println("e-Paper initialization complete; clearing display...");
//EPD_4IN2_V2_Clear();
Paint_NewImage(displayBuffer, EPD_4IN2_V2_WIDTH, EPD_4IN2_V2_HEIGHT, ROTATE_0, WHITE);
Paint_SelectImage(displayBuffer);
Paint_Clear(WHITE);
Paint_DrawString_EN(10, 0, "F1 Display Booting...", &Font16, WHITE, BLACK);
EPD_4IN2_V2_Display(displayBuffer);
DEV_Delay_ms(500);
wifi_connect();
sync_time();
Serial.println("Begin display loop.\n");
Paint_NewImage(counterBuffer, COUNTER_WIDTH, COUNTER_HEIGHT, ROTATE_0, WHITE);
Paint_SelectImage(counterBuffer);
xTaskCreate(display_loop, "display_loop", 1024, NULL, 5, NULL);
xTaskCreate(get_next_race, "get_next_race", 2048, NULL, 5, NULL);
}