From 3ec87ada9c437f03cdb6da92a3396e35895cb8af Mon Sep 17 00:00:00 2001 From: Adam Bissen Date: Fri, 6 Nov 2026 15:22:02 -0600 Subject: [PATCH] Add mutex to global race data. --- include/config.h | 2 ++ src/F1_api.h | 71 ++++++++++++++++++++++++++++-------------------- src/main.cpp | 26 ++++++++++++++++-- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/include/config.h b/include/config.h index 89f2266..dbcb7bf 100644 --- a/include/config.h +++ b/include/config.h @@ -12,3 +12,5 @@ // Display resolution #define EPD_4IN2B_V2_WIDTH 400 #define EPD_4IN2B_V2_HEIGHT 300 + +#define MUTEX_TIMEOUT_TICKS pdMS_TO_TICKS(150) diff --git a/src/F1_api.h b/src/F1_api.h index 32c63f9..bbf0497 100644 --- a/src/F1_api.h +++ b/src/F1_api.h @@ -4,8 +4,9 @@ #include "task.h" #include "secrets.h" #include "ArduinoJson.h" +#include "config.h" -struct race_info { +struct race_info_t { char session_name[50]; char date_start[32]; char circuit_short_name[50]; @@ -14,7 +15,8 @@ struct race_info { uint16_t circuit_key; }; -extern race_info next_race; +extern race_info_t race_data; +extern SemaphoreHandle_t dataMutex; static int get_race_query_url(char* target, size_t target_size) { if (target == NULL) return -1; @@ -45,8 +47,43 @@ static int get_race_query_url(char* target, size_t target_size) { } -int parse_session_json() { +int parse_session_json(JsonArray sessions, race_info_t session) { + JsonObject nextRaceJson = sessions[0]; + race_info_t localData; + const char* sessionName = nextRaceJson[F("session_name")]; + const char* dateStart = nextRaceJson[F("date_start")]; + const char* circuitName = nextRaceJson[F("circuit_short_name")]; + + localData.session_key = nextRaceJson[F("session_key")]; + if (localData.session_key == 0) return -1; + + localData.meeting_key = nextRaceJson[F("meeting_key")]; + if (localData.meeting_key == 0) return -1; + + localData.circuit_key = nextRaceJson[F("circuit_key")]; + if (localData.circuit_key == 0) return -1; + + if (sessionName != NULL) { + strlcpy(localData.session_name, sessionName, sizeof(localData.session_name)); + } else return -1; + if (dateStart != NULL) { + strlcpy(localData.date_start, dateStart, sizeof(localData.date_start)); + } else return -1; + if (circuitName != NULL) { + strlcpy(localData.circuit_short_name, circuitName, sizeof(localData.circuit_short_name)); + } else return -1; + + if (xSemaphoreTake(dataMutex, MUTEX_TIMEOUT_TICKS)) { + race_data = localData; + xSemaphoreGive(dataMutex); + } else { + Serial.print(""); + Serial.println("Unable to acquire mutex, API loop."); + return -1; + } + + return 0; } void get_next_race(void *pvParameters) { @@ -62,9 +99,6 @@ void get_next_race(void *pvParameters) { char query_url[103]; get_race_query_url(query_url, sizeof(query_url)); - Serial.print(""); - Serial.print("Query: "); - Serial.println(query_url); const bool requestReady = http.begin(query_url); if (!requestReady) { @@ -81,30 +115,7 @@ void get_next_race(void *pvParameters) { if (err == DeserializationError::Ok) { JsonArray sessions = json.as(); if (sessions.size() != 0) { - JsonObject nextRaceJson = sessions[0]; - const char* sessionName = nextRaceJson[F("session_name")]; - const char* dateStart = nextRaceJson[F("date_start")]; - const char* circuitName = nextRaceJson[F("circuit_short_name")]; - next_race.session_key = nextRaceJson[F("session_key")]; - next_race.meeting_key = nextRaceJson[F("meeting_key")]; - next_race.circuit_key = nextRaceJson[F("circuit_key")]; - if (sessionName != NULL) { - strlcpy(next_race.session_name, sessionName, sizeof(next_race.session_name)); - } - if (dateStart != NULL) { - strlcpy(next_race.date_start, dateStart, sizeof(next_race.date_start)); - } - if (circuitName != NULL) { - strlcpy(next_race.circuit_short_name, circuitName, sizeof(next_race.circuit_short_name)); - } - - Serial.print(""); - Serial.print("Next race: "); - Serial.print(next_race.session_name); - Serial.print(" at "); - Serial.print(next_race.circuit_short_name); - Serial.print(" on "); - Serial.println(next_race.date_start); + parse_session_json(sessions, race_data); } } else { Serial.print(""); diff --git a/src/main.cpp b/src/main.cpp index 35c6ca9..4faec28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "F1_api.h" #include "FreeRTOS.h" #include "task.h" +#include #include "config.h" @@ -21,7 +22,9 @@ static constexpr UWORD COUNTER_HEIGHT = 24; static constexpr UWORD COUNTER_Y = 20; static UBYTE counterBuffer[(COUNTER_WIDTH / 8) * COUNTER_HEIGHT]; static int counter = 0; -race_info next_race; + +race_info_t race_data; +SemaphoreHandle_t dataMutex; void wifi_connect() { WiFi.setHostname(DEVICE_HOSTNAME); @@ -78,6 +81,7 @@ bool readLocalTime(struct tm* result) { } void display_loop(void *pvParameters) { + static race_info_t local_data; while (true) { static unsigned long lastRefresh = 0; static char counterStr[32]; @@ -91,12 +95,22 @@ void display_loop(void *pvParameters) { counter++; - if (next_race.session_key == 0) { + 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 (race_data.session_key == 0) { snprintf(counterStr, sizeof(counterStr), "Counter: %d", counter); Serial.print(""); Serial.println(counterStr); } else { - snprintf(counterStr, sizeof(counterStr), "%s", next_race.circuit_short_name); + snprintf(counterStr, sizeof(counterStr), "%s", race_data.circuit_short_name); } Paint_Clear(WHITE); @@ -116,6 +130,12 @@ void display_loop(void *pvParameters) { 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;