#include "TFT_eSPI.h" #include "ChronoBLE.h" #include "ChronoReading.h" #include #include "Display.h" #include "ChronoReadingManager.h" #include "ChronoWebServer.h" #include "FileManager.h" #include #include #include //testing mode variables static bool testMode=false; static long testModeLastAdd=0; //general variables static char currentTime[64]; //chronograph setup static bool chronoStateConnected=false; static ChronoBLE chronoBLE; static ChronoWebServer webServer; void speedCallback(int fps){ addReading(fps); } void addReading(int fps){ ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); //add reading to manager chronoReadings.addReading(fps); //update display Display::updateEntireDisplay(); if (chronoReadings.getShotCount() % 10 == 0){ // Get filesystem information unsigned int totalBytes = LittleFS.totalBytes(); unsigned int usedBytes = LittleFS.usedBytes(); unsigned int freeBytes = totalBytes - usedBytes; Serial.printf("\t(%u) Available Disk / Memory: %u / %u\n", chronoReadings.getShotCount(), freeBytes, ESP.getFreeHeap()); } } void toggleTestMode(){ if (testMode){ Serial.println("disabling test mode...."); testMode=false; } else { Serial.println("enabling test mode...."); testMode=true; } } void setup() { Serial.begin(115200); Serial.println("starting......"); //initialize the file manager FileManager& files = FileManager::getInstance(); files.init(); //initialize web portal (also connects to WiFi) webServer.init(); webServer.setTestModeCallback(toggleTestMode); //sync time via NTP after WiFi is connected setDateTime(); //initialize display Display::init(); //initialize gun and projectile profile ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance(); chronoReadings.initializeProfiles(); //Display::updateProfile(chronoReadings.getProfile()); //initialize bluetooth chronoBLE.init(); chronoBLE.setSpeedCallback(speedCallback); } void setDateTime(){ // NTP server configuration configTime("EST5EDT,M3.2.0/2,M11.1.0/2", "pool.ntp.org", "time.nist.gov"); // Wait for time to be set time_t now; struct tm timeinfo; int retry = 0; const int maxRetry = 20; // 10 seconds max while (retry < maxRetry) { time(&now); localtime_r(&now, &timeinfo); // Check if we have a valid time (year > 2020) if (timeinfo.tm_year > 120) { // 120 = year 2020 Serial.println("Time synced via NTP"); break; } Serial.print("Waiting for NTP sync... "); Serial.println(retry); delay(500); retry++; } // If still not synced, fall back to a default date if (timeinfo.tm_year <= 120) { Serial.println("NTP sync failed, using fallback date"); timeinfo.tm_year = 2024 - 1900; timeinfo.tm_mon = 0; // January timeinfo.tm_mday = 1; timeinfo.tm_hour = 0; timeinfo.tm_min = 0; timeinfo.tm_sec = 0; timeinfo.tm_isdst = -1; now = mktime(&timeinfo); struct timeval tv = {.tv_sec = now}; settimeofday(&tv, NULL); } } void updateTime(){ time_t now; char strftime_buf[64]; struct tm timeinfo; time(&now); const char* TZ_EST = "EST5EDT,M3.2.0/2,M11.1.0/2"; setenv("TZ", TZ_EST, 1); tzset(); localtime_r(&now, &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%R", &timeinfo); if (strcmp(currentTime, strftime_buf) != 0) { strcpy(currentTime, strftime_buf); Display::updateTime(strftime_buf); Display::refreshDisplay(); } } void checkBLE(){ if (chronoBLE.isIdle()){ if (chronoStateConnected){ chronoStateConnected=false; Display::showChronographDisconnected(); Display::refreshDisplay(); } chronoBLE.startScan(); } else if (chronoBLE.isConnected()){ //update display if (!chronoStateConnected){ chronoStateConnected=true; Display::showChronographConnected(); Display::refreshDisplay(); } } else if (chronoBLE.foundDevice()){ chronoBLE.connectToDevice(); } } void loop() { //process BLE connection checkBLE(); //process web server webServer.process(); //update time updateTime(); ////////////////////////////////////////////////////// //run testmode commands if in test mode if (testMode){ if (testModeLastAdd==0){Display::showChronographConnected();} if (millis()>(testModeLastAdd+5000)){ long randomNumber = random(890, 920); addReading(randomNumber); testModeLastAdd=millis(); } } ////////////////////////////////////////////////////// //update display Display::refreshDisplay(); delay(2); }