#include <TFT_eSPI.h> // Hardware-specific library
#include <Wire.h>
#include <RTClib.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include "cloche.h"
#include "FreeSansBold.h"
#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
RTC_DS1307 rtc; // Create an RTC object
// Structure to hold time data
struct TimeData {
uint8_t hh;
uint8_t mm;
uint8_t ss;
uint8_t day;
uint8_t month;
uint16_t year;
char dayOfWeek[10];
};
// Global time data and mutex
TimeData timeData;
SemaphoreHandle_t timeMutex;
void setup(void) {
tft.init();
tft.setRotation(1);
tft.fillScreen(0xFFFF);
tft.setTextSize(1);
tft.setTextColor(TFT_BLACK, TFT_WHITE);
// Draw static elements
tft.setFreeFont(&FreeSans8pt7b);
tft.drawCentreString("IXLens", 160, 30, 1); // "IXLens" at the top-center
tft.pushImage(270, 26, 20, 20, cloche);
//tft.drawCentreString("815°F", 40, 220, 2); // Bottom-left text
//tft.drawCentreString("CODICOL AL", 280, 220, 2); // Bottom-right text
// Initialize I2C communication for the RTC
Wire.begin(21, 22); // SDA, SCL pins
if (!rtc.begin()) {
tft.drawCentreString("Couldn't find RTC", 160, 120, 2);
while (1);
}
// Set the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Create a mutex to protect access to the time data
timeMutex = xSemaphoreCreateMutex();
// Create FreeRTOS tasks
xTaskCreate(readRTCTask, "Read RTC", 2048, NULL, 1, NULL);
xTaskCreate(updateDisplayTask, "Update Display", 4096, NULL, 1, NULL);
}
void loop() {
// Nothing needed here as tasks are handled by FreeRTOS
}
// Task to read time from RTC
void readRTCTask(void *pvParameters) {
for (;;) {
DateTime now = rtc.now();
if (xSemaphoreTake(timeMutex, portMAX_DELAY) == pdTRUE) {
timeData.hh = now.hour();
timeData.mm = now.minute();
timeData.ss = now.second();
timeData.day = now.day();
timeData.month = now.month();
timeData.year = now.year();
snprintf(timeData.dayOfWeek, sizeof(timeData.dayOfWeek), "%s", dayOfTheWeek(now.dayOfTheWeek()));
xSemaphoreGive(timeMutex);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // Delay for 1 second
}
}
const char* dayOfTheWeek(uint8_t day) {
const char* days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
return days[day];
}
// Task to update the display
void updateDisplayTask(void *pvParameters) {
byte omm = 99, oss = 99;
uint8_t oldDay = 0, oldMonth = 0;
byte xcolon = 0, xsecs = 0;
unsigned int colour = 0;
for (;;) {
if (xSemaphoreTake(timeMutex, portMAX_DELAY) == pdTRUE) {
uint8_t hh = timeData.hh;
uint8_t mm = timeData.mm;
uint8_t ss = timeData.ss;
uint8_t day = timeData.day;
uint8_t month = timeData.month;
uint16_t year = timeData.year;
char dayOfWeek[10];
snprintf(dayOfWeek, sizeof(dayOfWeek), "%s", timeData.dayOfWeek);
xSemaphoreGive(timeMutex);
int xpos = 90;
int ypos = 85; // Top left corner of clock text, about half way down
int ysecs = ypos + 17;
if (omm != mm) { // Redraw hours and minutes time every minute
omm = mm;
tft.fillRect(0, ypos, tft.width(), 48, TFT_WHITE); // Clear previous time
tft.setTextColor(TFT_BLACK, TFT_WHITE);
tft.loadFont("NotoSansBold36"); // Load a custom font for time
// Draw hours and minutes
if (hh < 10) xpos += tft.drawChar('0', xpos, ypos, 6); // Add hours leading zero for 24 hr clock
xpos += tft.drawNumber(hh, xpos, ypos, 6); // Draw hours
xcolon = xpos; // Save colon coord for later to flash on/off later
xpos += tft.drawChar(':', xpos, ypos, 6);
if (mm < 10) xpos += tft.drawChar('0', xpos, ypos, 6); // Add minutes leading zero
xpos += tft.drawNumber(mm, xpos, ypos, 6); // Draw minutes
xsecs = xpos; // Save seconds 'x' position for later display updates
}
if (oss != ss) { // Redraw seconds time every second
oss = ss;
xpos = xsecs;
if (ss % 2) { // Flash the colons on/off
tft.setTextColor(TFT_GREY, TFT_WHITE); // Set colour to grey to dim colon
tft.drawChar(':', xcolon, ypos, 6); // Hour:minute colon
xpos += tft.drawChar(' ', xsecs, ysecs, 4); // Seconds colon
tft.setTextColor(TFT_BLACK, TFT_WHITE); // Set colour back to black
} else {
tft.drawChar(':', xcolon, ypos, 6); // Hour:minute colon
xpos += tft.drawChar(' ', xsecs, ysecs, 4); // Seconds colon
}
// Draw seconds
if (ss < 10) xpos += tft.drawChar('0', xpos, ysecs, 4); // Add leading zero
tft.drawNumber(ss, xpos, ysecs, 4); // Draw seconds
}
if (oldDay != day || oldMonth != month) { // Redraw date when it changes
oldDay = day;
oldMonth = month;
tft.fillRect(100, 220, 80, 30, TFT_WHITE); // Clear previous date
tft.setTextColor(TFT_BLACK, TFT_WHITE);
tft.loadFont("NotoSansBold15");
char dateStr[20];
snprintf(dateStr, sizeof(dateStr), "%02d %s %04d", day, monthToStr(month), year);
tft.drawCentreString(dateStr, 160, 220, 2); // Bottom-center date
}
tft.drawCentreString(dayOfWeek, (tft.width() / 2) - 10, ypos + 48, 4); // Draw day of the week
}
vTaskDelay(pdMS_TO_TICKS(500)); // Update display every 500 ms
}
}
const char* monthToStr(uint8_t month) {
const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
return months[month - 1];
}