// Arduino CRT TV Clock by mircemk, September 2025

#include <TVout.h>
#include <fontALL.h>
#include "MyLogo.h"
#include <Wire.h>
#include <avr/pgmspace.h> // For PROGMEM

TVout TV;

#define DS3231_I2C_ADDRESS 0x68

long previousMillis = 0;
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
long interval = 1000; // Update every 1 second
byte lastDayOfWeek = 0; // To track changes in day of week
byte lastDayOfMonth = 0; // To track changes in date

// Array of day names in PROGMEM (1=Sunday, 2=Monday, ..., 7=Saturday)
const char day0[] PROGMEM = "Unknown";
const char day1[] PROGMEM = "Sunday";
const char day2[] PROGMEM = "Monday";
const char day3[] PROGMEM = "Tuesday";
const char day4[] PROGMEM = "Wednesday";
const char day5[] PROGMEM = "Thursday";
const char day6[] PROGMEM = "Friday";
const char day7[] PROGMEM = "Saturday";
const char *const dayNames[] PROGMEM = {day0, day1, day2, day3, day4, day5, day6, day7};

byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}

byte bcdToDec(byte val) {
  return ((val/16*10) + (val%16));
}

void getDateDs3231() {
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  second = bcdToDec(Wire.read() & 0x7f);
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read() & 0x3f);
  dayOfWeek = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}

void setup() {
  Wire.begin();
  getDateDs3231();
  TV.begin(PAL, 130, 96);
  TV.select_font(font8x8);
  TV.set_cursor(15, 13);
  TV.print("DIY Arduino");
  TV.set_cursor(22, 40);
  TV.print("CRT Clock");
  TV.draw_rect(20, 38, 75, 13, 1, -1);
  TV.draw_rect(17, 35, 81, 19, 1, -1);
  TV.set_cursor(8, 67);
  TV.print("TVout Library");
  TV.delay(5000);
  TV.clear_screen();
  intro();
  TV.set_cursor(12, 2);
  TV.print("Time & Date:");
  TV.draw_rect(6, 0, 105, 12, 1, 2);


  TV.draw_line(15, 39, 103, 39, 1);
  TV.draw_line(15, 61, 103, 61, 1);

  // Initial display of day and date
  
  TV.set_cursor(25, 45);
  char buffer[10];
  strcpy_P(buffer, (char *)pgm_read_word(&dayNames[dayOfWeek]));
  TV.print(buffer);
  TV.set_cursor(20, 68);
  TV.print(char(dayOfMonth/10 + 0x30));
  TV.print(char(dayOfMonth%10 + 0x30));
  TV.print("/");
  TV.print(char(month/10 + 0x30));
  TV.print(char(month%10 + 0x30));
  TV.print("/");
  TV.set_cursor(68, 68);
  TV.print("20");
  TV.print(char(year/10 + 0x30));
  TV.print(char(year%10 + 0x30));
  lastDayOfWeek = dayOfWeek;
  lastDayOfMonth = dayOfMonth;
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    getDateDs3231();
    #ifdef TVOUT_VBLANK
    TV.wait_for_vblank(); // Synchronize with vertical blanking if available
    #endif
    printTime();
  }
}

void printTime() {
  // Clear and print time (changes every second)
  TV.draw_rect(25, 25, 48, 8, 0, 1); // Clear time area (width for HH:MM:SS)
  TV.set_cursor(25, 25);
  TV.print(char(hour/10 + 0x30));
  TV.print(char(hour%10 + 0x30));
  TV.print(":");
  TV.print(char(minute/10 + 0x30));
  TV.print(char(minute%10 + 0x30));
  TV.print(":");
  TV.print(char(second/10 + 0x30));
  TV.print(char(second%10 + 0x30));

  // Print day of week only if it has changed
  if (dayOfWeek != lastDayOfWeek && dayOfWeek >= 1 && dayOfWeek <= 7) {
    TV.draw_rect(25, 45, 80, 8, 0, 1); // Clear day area (width for longest day name)
    TV.set_cursor(25, 45);
    char buffer[10];
    strcpy_P(buffer, (char *)pgm_read_word(&dayNames[dayOfWeek]));
    TV.print(buffer);
    lastDayOfWeek = dayOfWeek;
  }

  // Print date only if dayOfMonth has changed
  if (dayOfMonth != lastDayOfMonth) {
    TV.draw_rect(10, 68, 64, 8, 0, 1); // Clear date area (width for DD/MM/YYYY)
    TV.set_cursor(10, 68);
    TV.print(char(dayOfMonth/10 + 0x30));
    TV.print(char(dayOfMonth%10 + 0x30));
    TV.print("/");
    TV.print(char(month/10 + 0x30));
    TV.print(char(month%10 + 0x30));
    TV.print("/");
    TV.set_cursor(58, 68);
    TV.print("20");
    TV.print(char(year/10 + 0x30));
    TV.print(char(year%10 + 0x30));
    lastDayOfMonth = dayOfMonth;
  }
}

void intro() {
  unsigned char w, l, wb;
  int index;
  w = pgm_read_byte(MyLogo);
  l = pgm_read_byte(MyLogo+1);
  if (w & 7)
    wb = w/8 + 1;
  else
    wb = w/8;
  index = wb*(l-1) + 2;
  for (unsigned char i = 1; i < l; i++) {
    TV.bitmap((TV.hres() - w)/2, 0, MyLogo, index, w, i);
    index -= wb;
    TV.delay(50);
  }
  for (unsigned char i = 0; i < (TV.vres() - l); i++) {
    TV.bitmap((TV.hres() - w)/2, i, MyLogo);
    TV.delay(50);
  }
  TV.delay(3000);
  TV.clear_screen();
}