#include // Reserve FRAM address 0 - 1000 for ESPMegaPRO Internal Use // (34 Bytes) Address 0-33 for Built-in Digital Output Card // (266 Bytes) Address 34-300 for ESPMegaPRO IoT Module ESPMegaPRO::ESPMegaPRO() { } bool ESPMegaPRO::begin() { Wire.begin(14, 33); fram.begin(FRAM_ADDRESS); Serial.begin(115200); this->installCard(1, &outputs); outputs.bindFRAM(&fram,0); outputs.loadFromFRAM(); outputs.setAutoSaveToFRAM(true); if(!this->installCard(0, &inputs)) { ESP_LOGE("ESPMegaPRO", "Failed to initialize inputs"); ESP_LOGE("ESPMegaPRO", "Is this an ESPMegaPRO device?"); return false; } uint8_t pinMap[16] = {0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8}; inputs.loadPinMap(pinMap); return true; } void ESPMegaPRO::loop() { inputs.loop(); outputs.loop(); for (int i = 0; i < 255; i++) { if (cardInstalled[i]) { cards[i]->loop(); } } if(iotEnabled) { iot->loop(); } if(internalDisplayEnabled) { display->loop(); } } bool ESPMegaPRO::installCard(uint8_t slot, ExpansionCard* card) { if (slot > 255) return false; if (cardInstalled[slot]) { ESP_LOGE("ESPMegaPRO", "Card already installed at slot %d", slot); return false; } if (!card->begin()) { ESP_LOGE("ESPMegaPRO", "Failed to initialize card at slot %d", slot); return false; } cards[slot] = card; cardInstalled[slot] = true; cardCount++; return true; } bool ESPMegaPRO::updateTimeFromNTP() { struct tm timeinfo; if (getLocalTime(&timeinfo)) { rtctime_t rtctime = this->getTime(); if (rtctime.hours != timeinfo.tm_hour || rtctime.minutes != timeinfo.tm_min || rtctime.seconds != timeinfo.tm_sec || rtctime.day != timeinfo.tm_mday || rtctime.month != timeinfo.tm_mon + 1 || rtctime.year != timeinfo.tm_year + 1900) { this->setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900); } return true; } return false; } rtctime_t ESPMegaPRO::getTime() { tmElements_t timeElement; RTC.read(timeElement); rtctime_t time; time.hours = timeElement.Hour; time.minutes = timeElement.Minute; time.seconds = timeElement.Second; time.day = timeElement.Day; time.month = timeElement.Month; time.year = timeElement.Year + 1970; return time; } void ESPMegaPRO::setTime(int hours, int minutes, int seconds, int day, int month, int year) { tmElements_t timeElement; timeElement.Hour = hours; timeElement.Minute = minutes; timeElement.Second = seconds; timeElement.Day = day; timeElement.Month = month; timeElement.Year = year - 1970; RTC.write(timeElement); } void ESPMegaPRO::enableIotModule() { if (iotEnabled) return; this->iot = new ESPMegaIoT(); this->iot->bindFRAM(&fram); this->iot->intr_begin(cards); iotEnabled = true; } ExpansionCard* ESPMegaPRO::getCard(uint8_t slot) { if (slot > 255) return nullptr; if (!cardInstalled[slot]) return nullptr; return cards[slot]; } void ESPMegaPRO::enableInternalDisplay(HardwareSerial *serial) { if (internalDisplayEnabled) return; if (!iotEnabled) { ESP_LOGE("ESPMegaPRO", "Cannot enable internal display without IoT module enabled"); return; } ESP_LOGD("ESPMegaPRO", "Enabling Internal Display"); display = new InternalDisplay(serial); ESP_LOGD("ESPMegaPRO", "Binding Internal Display to IoT Module"); auto bindedGetTime = std::bind(&ESPMegaPRO::getTime, this); ESP_LOGD("ESPMegaPRO", "Binding Internal Display to Input/Output Cards"); display->bindInputCard(&inputs); display->bindOutputCard(&outputs); display->begin(this->iot,bindedGetTime); internalDisplayEnabled = true; ESP_LOGD("ESPMegaPRO", "Internal Display Enabled"); } void ESPMegaPRO::dumpFRAMtoSerial(uint16_t start, uint16_t end) { for (int i = start; i <=end; i++) { if (i % 16 == 0) { Serial.printf("\n%03d: ", i); } Serial.printf("%03d ", this->fram.read8(i)); } } void ESPMegaPRO::dumpFRAMtoSerialASCII(uint16_t start, uint16_t end) { for (int i = 0; i < 500; i++) { Serial.printf("%d: %c\n", i,this->fram.read8(i)); } }