diff --git a/EVOG2.ino b/EVOG2.ino new file mode 100644 index 0000000..7e87a54 --- /dev/null +++ b/EVOG2.ino @@ -0,0 +1,1327 @@ +// V505 Change P48 min value to allow for negative numbers +// C506 ADD Lidar v979 +// 506 add parm 16 lock circuit +// 507 set parm 24 to 1 to use NC interlock on spare 1 +// 997 add wifi +// 984 add slave adjust for current balancing +// 980 add log file stuff +// 979 add LiDar +// 508 ..979 release +// 509 ..add wdt chip test +// v510 fix multi sensor *10 bug added long and short wdt test +// v511 fixed tone function, was causing reset. added serial command I to read unused inputs +// v512 add parm 69 to monitor rtc +// v514 add BOOT button to show motor status +// v515 add exit button check for pgm screen exit +// v550 multi door .. in process +// v516 fix access code question +// v517 add parm[15] as bug screen channel +// v518 add remote bug screen +// v519 add LIDAR test mode +// v520 kill lidar test screen timeout +// v521 add ioExpander relays to run Somfy bug screen +// v522 ad ioExpander relay test TR 00x +// v523 add WAITING FOR COMMAND recovery/ 2 motor feature +// v524 SSID and PASS update +// v525 parm 29 splash screen timeout to blank screen 0 = off +// v526 turn on fault engine +// v527 fix BOOTBUTTON OTA +// fix low batt error on startup +// v528 Fixed FTP name for OTA +// Added serial number for label printer +// Fixed high voltage reading on start up +// v529 Updated code to use parms.write instead of parm[xx] = xx +// Fixed check sum error. change bte to uint8_t +// v530 Fixed LidarTimer in 485 file. Stopped reseting timer after seeing obstruction bit +// v531 Changed default value of parm[18] to 1253 +// Added display information for bug screen +// v532 Moved no display fault restore to 602 to prevent spamming of fault +// Extended condition to run 'wifiService()' in absence of a display, originally only active in the logo screen. +// v533 Added serial check for \n or \r +// Increased Parm 69 for rtc +// Removed NTP code added check for BOOGYTIME +// Bug fix - added etime to at_QtempData when pushing to cloud +// v534 Added extra Clarity screens/functions +// v535 Fixed parm 1 and 76 limits +// v536 New motor error +// Added parms for motor timeouts +// v537 Added Clarity text for older display versions +// v538 Bug fix - Changed motor timeout to parm 31 +// Added function to use previous parms from an SD card when upgrading +//**********************************************************************************************/ + +#include +//V111 +//Removed #SD Include +//Added FileLib.h & HTTPSHandler.h +#include "FS.h" +#include "SD.h" +#include "SPI_ADI.h" +#include "HTTPSHandler.h" +#include "Timers_ADI.h" +#include "FileLib.h" +#include "IO_ADI.h" +#include "Parms_ADI.h" +#include "RF_Keys.h" +#include + +bool VB = 0; // verbose mode + +#define HEARTBEATLED 33 +#define myVersion 117 // 525 //974 +// 507 //delivered 505 protoype at Renlita + +#ifndef ADI_ESP32_DEV +#error Incorrect platform definition +#endif + +#define myCHAN parm[15] +#define BALANCEDEADBAND 300 // v984 + +bool obstructionIsSensed = 0; +bool lastObstructionPin = 0; +bool onesecond; +int addrcase; +int wiFiOK = 0; + +int logicCase = 0; +int forwardCase = 0; +int DOOROPEN = 0; +int DOORCLOSE = 0; +int DOORSTOP = 0; +int DOORTOGGLE = 0; +int cDOOROPEN = 0; +int cDOORCLOSE = 0; +int cDOORSTOP = 0; + +bool LASTDIRECTION = 0; + +int lastCase = -1; + +// float voltageNow; +// float currentNow; +char tmpstr[80]; +int runLogic = 0; // start it later +int runCAN = 1; + +int doorState = 0; +int lastDoorState = 1; + +float voltageNow; +int displayServiceCounter = 0; +unsigned long displayMillis; + +int lastBootPin; + +//Added Lines & Cert For HTTPS Connection +const char *HTTPS_HOST = "appdig.com"; +const char *BIN_SOURCE = "/EVOG2Test/EVOTEST.bin"; +const char *UPLOAD_PARMS_DEST = "/EVOG2Test/upload.php"; +const char *AUTH_HEADER = "X-Authorization: Basic YXBwZGlnOnB3ZA =="; +const char *UPDATE_BIN = "/Update.bin"; + +const char *serverCert = + "-----BEGIN CERTIFICATE-----\n" +"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\n" + "-----END CERTIFICATE-----\n"; + +HTTPSHandler https(serverCert); + +uint16_t faultNum, faultData, faultAB; +int16_t lastDisplayedGraphic = -1; + +//V111 +//Added File LibClass For Parms SD/SPIFF +FileLibClass fileLibSPIFFS(FL_SPIFFS); // Instance for SPIFFS +FileLibClass fileLibSD(FL_SD); + +ParmsLibClass parms(fileLibSPIFFS); + +void setup() +{ + Serial.begin(115200); + delay(500); + Serial.println("Serial Initialized"); + + pinMode(HEARTBEATLED, OUTPUT); // heartbeat LED + digitalWrite(HEARTBEATLED, HIGH); + delay(2000); + + init_timers(); + initFaults(); // v525 + + spiInit(); + oled_init(); + + //Init SPIFFS AND SD & Validate They Work + Serial.print("Version:"); Serial.println(myVersion); // Initialize SPIFFS + if (!fileLibSPIFFS.begin()) { + Serial.println("Failed to initialize SPIFFS"); + } else { + Serial.println("SPIFFS initialized"); + } + + fileLibSD.setVerbose(1); + + if (!fileLibSD.begin()) { + Serial.println("SD FAILED TO MOUNT"); + } + else { + Serial.println("SD Card initialized"); + } + + // delay(1000); + // Serial.println(rtcGetTime()); + // print_time(); + + parms.write(33, 0); // always turn off exercise + // parm[16] = 0; + + parms.setVerbose(1); + parms.loadFromFS(); + parms.setVerbose(0); + + if(parms.read(14) != myVersion) //New Version + parms.write(14,myVersion); + + initIO(); + serviceIO(); + serviceIO(); + serviceIO(); + voltageNow = io_array[BATT_V]; + + init485(); + + if (runCAN) + motorInit(); + + delay(1000); + initRF(); + displayText("RF Init OK"); + delay(1000); + // sprintf(tmpstr, "Ver: %d-%d %d", myVersion, parm[1], parm[64]); + // displayText(tmpstr); + // Serial.println(tmpstr); + ShowSerialScreen(); + + delay(3000); + displayText("Setup Finished"); + + initWiFi(); + + // esp_task_wdt_init(10, true); //enable panic so ESP32 restarts 10 seconds + // esp_task_wdt_add(NULL); //add current thread to WDT watch + + SD_LogWrite("Power Up"); + + qualifyFault(0, 0); // push startup +} + +void loop() +{ + // Heartbeat + onesecond = 0; + if (Timers[HEARTBEAT] == 0) + digitalWrite(HEARTBEATLED, 1); + if (Timers[HEARTBEAT] == 2) + digitalWrite(HEARTBEATLED, 0); + if (Timers[HEARTBEAT] == 3) + digitalWrite(HEARTBEATLED, 1); + if (Timers[HEARTBEAT] == 4) + digitalWrite(HEARTBEATLED, 0); + if (Timers[HEARTBEAT] >= 9) + { + Timers[HEARTBEAT] = 0; + onesecond = 1; + if (isDoorIdle() == 0) + displayVoltage(); + } + + if (onehundredmstick != 0) + { + onehundredmstick = 0; + timer_update(); + } + + /* + if (onesecond) + { + + Serial.println(); + //uint8_t ip = readMCP23S08(IOEXP_CS, 9); + for (int ip = 0; ip < 8; ip++) + Serial.printf(" %X", io_array[ip]); + Serial.println(); + } + */ + + // if(onesecond) Serial.printf("\n ADDR = %d\n",io_array[ADDRBUTTON]); + // if(onesecond) Serial.printf(" Pin17 = %d\n",digitalRead(17)); + + // setting address + /* + switch (addrcase) + { + case 0: + if (io_array[ADDRBUTTON] > 10) // + addrcase++; + break; + + case 1: + if (io_array[ADDRBUTTON] == 0) //released it + { + showAddrScreen(); + + addrcase++; + Timers[BOOTPINTIMER] = 0; + } + break; + + case 2: + if (Timers[BOOTPINTIMER] > 200) + ESP.restart(); + + if (digitalRead(0) == 0) //BOOT pressed, save and leave + { + SD_ParmWrite(); + ESP.restart(); + } + + if (io_array[ADDRBUTTON] > 10) + { + if (++parm[1] > 4) parm[1] = 0; + addrcase++; + } + break; + + case 3: + if (io_array[ADDRBUTTON] == 0) //released it + { + addrcase = 1; + } + break; + } +*/ + + if (digitalRead(0) == 0) + { + if (Timers[BOOTPINTIMER] == -1) + Timers[BOOTPINTIMER] = 0; + if (onesecond) + { + sprintf(tmpstr, "Boot button: %d\n", Timers[BOOTPINTIMER]); + displayText(String(tmpstr)); + } + if (Timers[BOOTPINTIMER] > 200) + { + if (io_array[3] == 0) // Address Setup Button + parms.factoryReset(); + else + beginOTA(); + + Timers[BOOTPINTIMER] = -1; + } + } + else + { + Timers[BOOTPINTIMER] = -1; + } + + if (lastBootPin == 1) // transition + if (digitalRead(0) == 0) + { + displayVoltage(); + } + lastBootPin = digitalRead(0); + + if (lastObstructionPin == 0) + { + if (digitalRead(OBSTRUCTIONPIN) == 1) + { + obstructionCounter++; + } + } + lastObstructionPin = digitalRead(OBSTRUCTIONPIN); + + if (Timers[OBSTRUCTION] >= 5) // check obstruction every .5 sec. + { + // Serial.print("Obstruction: "); + // Serial.println(obstructionCounter); + Timers[OBSTRUCTION] = 0; + obstructionIsSensed = 0; + // noInterrupts(); + if (obstructionCounter < 50) + { + obstructionIsSensed = 1; + } + obstructionCounter = 0; + // interrupts(); + } + + if (runLogic == 1) + { + doorLogic(); + if (parm[28] == 1) + screenLogic(); // v521 + } + + if (parm[26] == 1) // v518 remote screen operation + { + + if (exOptoTransition[2] == 1) + { + displayText("HA Screen UP"); + rfSendKey(RF_KEY_UP, myCHAN); + exOptoTransition[2] == 0; + } + if (exOptoTransition[3] == 1) + { + displayText("HA Screen DOWN"); + rfSendKey(RF_KEY_DN, myCHAN); + exOptoTransition[3] == 0; + } + } + + serviceIO(); + voltageNow = io_array[BATT_V]; + + // drop motor watchdog + if (motorGetPosition(0) != 9999) + if (motorGetPosition(1) != 9999) + io_array[POWER_RLY] ^= 1; + + // comms dropped on a motor + if (motorGetPosition(0) == 9999) + setMotorFault(0); + if (motorGetPosition(1) == 9999) + setMotorFault(1); + + if (runCAN) + motorTask(); + + if (parm[1] == 0) + inSerial2(); + else + runSlave(); + + if (millis() - displayMillis >= 20) // 988 50 + { + if (parm[1] == 0) + serviceDisplay(); // master + + displayMillis = millis(); + } + + /* + + if (Timers[DISPLAYSERVICETIMER] >= 1) + { + Timers[DISPLAYSERVICETIMER] = 0; + serviceDisplay(); + } + */ + if (Timers[TENSECOND] >= 100) + { + + Timers[TENSECOND] = 0; + runLogic = 1; + + sprintf(tmpstr, "********************* M0: %d M1: %d\n", motorGetPosition(0), motorGetPosition(1)); + Serial.println(tmpstr); + sprintf(tmpstr, "Obstruction: %d\n", obstructionIsSensed); + Serial.println(tmpstr); + + Serial.printf("Voltage: %d, %d\n", io_array[BATT_V], analogRead(BATTERYINPUTPIN)); + + Serial.print("Logic Case: "); + Serial.println(logicCase); + } + + if (Timers[AT200DATA] >= parm[23]) // check in + { + Timers[AT200DATA] = 0; + pushCheckin(); + pushDoorStatus(); + } + + rfTask(); + checkSerial(); + + if (Timers[VOLTAGETIMER] >= 100) // 10 seconds into travel + { + Timers[VOLTAGETIMER] = -1; + pushCheckin(); + } + + if (doorState != lastDoorState) + { + pushDoorStatus(); + lastDoorState = doorState; + + sprintf(tmpstr, "Max Current M: %d.%d S: %d.%d\n", getMaxCurrent(0) / 10, getMaxCurrent(0) % 10, getMaxCurrent(1) / 10, getMaxCurrent(1) % 10); + Serial.print(tmpstr); + SD_LogWrite(tmpstr); + pushMaxCurrents(); + } + + if (isDoorIdle() == 0) // door is busy + Timers[ISIDLETIMER] = 0; + + if (Timers[ISIDLETIMER] > 10) + if (Timers[ISIDLETIMER] < 12) + { + motorStop(); + displayText("Motor Stop"); + Timers[ISIDLETIMER] = 13; + } + + //******WiFi Service master + + if (parm[1] == 0) // master + { + wiFiOK = 0; + if (Timers[ISIDLETIMER] > 100) // been idle more than 10 seconds + if (parm[9] == 1) // WiFi enabled + { + if (lastDisplayedGraphic == 8) + { + wiFiOK = 1; // LOGOSCREEN? + } + + // In logo screen or no display screen + if (currentDisplayCase() == 22 || currentDisplayCase() == 23 || currentDisplayCase() == 600 || currentDisplayCase() == 602) + { + if (Timers[WIFISERVICE] >= parm[22]) + { + wifiService(); + Timers[WIFISERVICE] = 0; + } + if (Timers[AT200DATA] >= parm[23]) // check in + { + Timers[AT200DATA] = 0; + pushCheckin(); + pushDoorStatus(); + } + } + } + } + + //******WiFi Service slave + if (parm[1] != 0) // slave + { + if (Timers[ISIDLETIMER] > 100) // been idle more than 10 seconds + if (parm[9] == 1) // WiFi enabled + if (wiFiOK == 1) + { + if (Timers[WIFISERVICE] >= parm[22]) + { + wifiService(); + Timers[WIFISERVICE] = 0; + } + if (Timers[AT200DATA] >= parm[23]) // check in + { + Timers[AT200DATA] = 0; + pushCheckin(); + pushDoorStatus(); + } + } + } + + if (onesecond) + if (VB) + Serial.printf("WiFiOK -> %d, ISIDLETIMER -> %d\n", wiFiOK, Timers[ISIDLETIMER]); + + // if (onesecond) Serial.printf("Voltage Timer: %d\n", Timers[VOLTAGETIMER]); + if (Timers[OLEDBLANKTIMER] > 1200) // v1653 to blank oled + { + displayText(""); + Timers[OLEDBLANKTIMER] = 0; + } + + if (Timers[OLEDHOLDTIMER] > 30000) + Timers[OLEDHOLDTIMER] = 2000; +} + +int isDoorIdle(void) +{ + if ( + (logicCase == 1) || + (logicCase == 2) || + (logicCase == 20) || + (logicCase == 10)) + return (1); + return (0); +} + +void doorLogic(void) +{ + if (parm[25] == 0) // v995 + { + DOOROPEN = 0; + DOORCLOSE = 0; + DOORSTOP = 0; + DOORTOGGLE = 0; + } + + if (parm[26] == 1) + { + DOOROPEN = exOpto[0]; + DOORCLOSE = exOpto[1]; + } + else + { + DOOROPEN = 0; + DOORCLOSE = 0; + } + + if (parm[25]) + if (onesecond) + Serial.printf("ioExpander %d %d %d %d\n", exOpto[0], exOpto[1], exOpto[2], exOpto[3]); + + if (io_array[RF_KEYPAD] > 10) // door toggle + DOORTOGGLE = 1; + + DOORTOGGLE = 0; // dstest + /* + if (io_array[JOG_EXTEND] < 50) + { + logicCase = 50; + } + if (io_array[JOG_RETRACT] < 50) + { + logicCase = 51; + } + */ + + if (LowBattery() == 0) + if (parm[33] >= 6000) + runExercise(); + + if (parm[16] == 1) + io_array[SPARE_OUT] = 0; // v506 + + // v507 add interlock spare1 + if ((parm[24] != 0) && (io_array[SPARE_IN] == 0)) + logicCase = 0; + + switch (logicCase) + { + //********** + case 0: // init + logicCase++; + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 0; + + motorStop(); + // doorState = 0; + break; + + case 1: // make sure all buttons are clear + + if ((DOOROPEN == 0) && + (DOORCLOSE == 0) && + (cDOOROPEN == 0) && + (cDOORCLOSE == 0) && + (cDOORSTOP == 0)) + logicCase++; + break; + + case 2: // idle //don't know where we are + // doorState = 0; //v987 + + if ((DOOROPEN) || (cDOOROPEN)) // door open + logicCase = 30; + if ((DOORCLOSE) || (cDOORCLOSE)) // door close + logicCase = 40; + /* + if (DOORTOGGLE) //door toggle from Spare_IN1 input + { + if (!LASTDIRECTION) logicCase = 30; + if (LASTDIRECTION) logicCase = 40; + } + */ + break; + + //****OPEN + case 30: // we gonna open + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + displayText("OPENING"); + logicCase = 31; + io_array[COMPRESSOR] = 0; // release compressor + Timers[GASKETTIMER] = 1; + + // if (io_array[EXT_LIMIT] != 0) + // logicCase = 10; //duh, already open + setCurrentBalance(0); + break; + + case 31: // + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + if (Timers[GASKETTIMER] > parm[2]) // wait for COMPRESSOR delay + logicCase = 32; + break; + + case 32: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + Timers[DOORTRAVELTIMER] = 1; // start max timer for overall travel + logicCase = 33; + + // parms.write(11, parm[11] + 1); //cycle counter + // SD_ParmWrite(); + + break; + + case 33: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + Serial.println("Begin Open"); + Timers[VOLTAGETIMER] = 0; + // MOVEDIRECTION = 1; + + // if (motorGetPosition(0) > parm[40]) MOVEDIRECTION = 0; //we above it.. need to travel down + motorMove(2999); + + // io_array[EXTEND] = 1;//let's open it + logicCase = 34; + LASTDIRECTION = 1; + break; + + case 34: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + logicCase++; + /* + if (Timers[DOORTRAVELTIMER] > parm[5]) //must be fully open + { + logicCase = 35; + } + */ + if ((DOORSTOP) || (cDOORSTOP)) + logicCase = 0; + if (DOORTOGGLE) + logicCase = 0; + + break; + + case 35: // + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 0;//let's close it + Timers[DOORTRAVELTIMER] = 1; + // logicCase = 60; + // forwardCase = 36; + + logicCase++; + break; + + case 36: + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 1;//let's close it to stop + + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + logicCase = 37; + + break; + + case 37: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + if (Timers[DOORTRAVELTIMER] > parm[6]) // just in case + { + logicCase = 0; + Serial.println("Open Travel Timeout"); + displayText("Open Timeout"); + pushDoorStatus(); + } + + // v984 balance current while running + if (motorGetPosition(0) < (parm[40] - BALANCEDEADBAND)) + { + setCurrentBalance(parm[49]); + } + else + { + setCurrentBalance(0); + } + + // finished + if (motorGetPosition(0) >= parm[40]) + { + logicCase = 10; + Serial.printf("Open Limit reached %d - %d\n", motorGetPosition(0), parm[40]); + displayText("Open Limit reached"); + motorStop(); + parms.write(11, parm[11] + 1); // cycle counter + } + + /* + if (io_array[EXT_LIMIT] > 5)//v108 .. was 10 + { + logicCase = 10; + Serial.println("Limit reached"); + } + */ + + if ((DOORSTOP) || (cDOORSTOP)) + logicCase = 0; + if (DOORTOGGLE) + logicCase = 0; + break; + + //****CLOSE + case 40: // we gonna close + + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + logicCase = 42; + displayText("CLOSING"); + Serial.println("CLOSING"); + + /* if (io_array[RET_LIMIT] > 10) + logicCase = 20; //duh, already closed + */ + + break; + + case 42: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + Timers[DOORTRAVELTIMER] = 1; // start max timer for overall travel + logicCase = 43; + break; + + case 43: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + // io_array[RETRACT] = 1;//let's close it + Serial.println("Begin Close"); + Timers[VOLTAGETIMER] = 0; + motorMove(10); + logicCase = 46; + LASTDIRECTION = 0; + break; + + case 46: + forwardCase = 30; + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + if (Timers[DOORTRAVELTIMER] > parm[5]) // just in case + { + logicCase = 20; + pushDoorStatus(); + displayText("Close Timeout"); + } + + // v984 balance current while running + + if (motorGetPosition(0) > (parm[39] + BALANCEDEADBAND)) + { + setCurrentBalance(parm[50]); + } + else + { + setCurrentBalance(0); + } + + if (motorGetPosition(0) <= parm[39]) + { + logicCase = 20; + motorStop(); + displayText("Limit reached"); + Serial.println("Limit reached"); + } + + if (parm[54] == 0) // no LiDar v979 + if ((DOORSTOP) || (cDOORSTOP) || ((cDOORCLOSE == 0) && (DOORCLOSE == 0))) // v995 + { + // forwardCase = 30; //to reverse + // logicCase = 60; + logicCase = 0; + } + + if (parm[54] == 1) // use LiDar v979 + if ((DOORSTOP) || (cDOORSTOP)) + { + logicCase = 0; + } + + if (parm[4] != 0) + { + if (obstructionIsSensed == 1) + { + forwardCase = 30; + logicCase = 60; + Serial.println("Photo Obstruction!! Change Direction"); + showObstructionScreen(); + faultNum = 1; + faultAB = 0; + faultData = 0; + } + } + + if (Timers[LIDARTIMER] > 30) + { + if (parm[54] != 0) // use Lidar + { + + // check for deadzones at ends + if (motorGetPosition(0) <= (parm[39] + parm[66])) + clearLidarObstruction(); // 200 up from closed + if (motorGetPosition(0) >= (parm[40] - parm[65])) + clearLidarObstruction(); // 400 down from open + + if (checkLidarObstruction()) + { + forwardCase = 30; + logicCase = 60; + Serial.println("Lidar Obstruction!! Change Direction"); + qualifyFault(35, 0); + restoreFault(35); + showObstructionScreen(); + faultNum = 5; + faultAB = 0; + faultData = 0; + } + } + } + else + { + clearLidarObstruction(); + } + + if (DOORTOGGLE) + { + forwardCase = 30; + logicCase = 60; + } + break; + + case 60: // Reverse delay + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + Timers[DOORTRAVELTIMER] = 0; + displayText("Reverse"); + motorStop(); + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 0; + logicCase++; + break; + + case 61: + if (parm[16] == 1) // v506 + io_array[SPARE_OUT] = 1; + + if (Timers[DOORTRAVELTIMER] > 10) + logicCase = forwardCase; + break; + + //*********** + case 10: // door is open + doorState = 1000; + logicCase = 0; + + // if ((DOORCLOSE) || (cDOORCLOSE))logicCase = 40; + // if (DOORTOGGLE) logicCase = 40; + + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 0; + break; + + //*********** + case 20: // door is closed + doorState = 0; + logicCase = 0; + io_array[COMPRESSOR] = 1; // compressor on + + if ((DOOROPEN) || (cDOOROPEN)) + logicCase = 30; + if (DOORTOGGLE) + logicCase = 30; + // io_array[EXTEND] = 0; + // io_array[RETRACT] = 0; + break; + + default: + logicCase = 0; + + Serial.println("entered door logic default case"); + break; + } + + if (isDoorIdle() == 0) + if (parm[27] != 0) // turn on current limit + if (Timers[DOORTRAVELTIMER] > 30) // if we have been running over 3 seconds + { + if (motorGetCurrent(0) > parm[27]) + { + sprintf(tmpstr, "M Overcurrent %d", motorGetCurrent(0)); + displayText(String(tmpstr)); + motorStop(); + parms.write(33, 0); + logicCase = 0; + // delay(1000); + } + if (motorGetCurrent(1) > parm[27]) + { + sprintf(tmpstr, "S Overcurrent %d", motorGetCurrent(1)); + displayText(String(tmpstr)); + motorStop(); + parms.write(33, 0); + logicCase = 0; + // delay(1000); + } + } + + // if (VB) + if (lastCase != logicCase) + { + Serial.print("Logic Case: "); + Serial.println(logicCase); + lastCase = logicCase; + } +} + +void runExercise(void) +{ + if (Timers[EXERCISETIMER] < 0) + Timers[EXERCISETIMER] = 0; // start it + if (Timers[EXERCISETIMER] > parm[33]) + Timers[EXERCISETIMER] = 0; // start over + + if (cDOORSTOP != 0) // cancel the whole thing + { + Timers[EXERCISETIMER] = -1; // stop it + parms.write(33, 0); + return; + } + + // open + cDOOROPEN = 0; + if (Timers[EXERCISETIMER] > 20) + if (Timers[EXERCISETIMER] < 30) // let's open + cDOOROPEN = 1; + + // close + cDOORCLOSE = 0; + if (Timers[EXERCISETIMER] > (parm[33] / 2)) // let's close halfway through timeout + if (Timers[EXERCISETIMER] < (parm[33] - 30)) + cDOORCLOSE = 1; + + if (onesecond) + Serial.printf("Exercise timer: %d\n", Timers[EXERCISETIMER]); +} + +void checkSerial() +{ + static String fromSerial; // needs to keep its value between calls + int pnum; + uint32_t pdata, edata; + + // if something is available - make sure you have line feed enabled + if (Serial.available()) + { + char c = Serial.read(); + if (c == '\n' || c == '\r') + { + if (fromSerial.length() > 0) + { + Serial.println(fromSerial); // for debugging, just echo back what you got + fromSerial = ""; // Clear the string for the next line + } + } + else + { + fromSerial += c; // Append the received character to the string + } + + // parm write PW ppp 1234567 + if (fromSerial[0] == 'P' && fromSerial[1] == 'W' && fromSerial.length() == 14) + { // writing parm - must match length + + // first pull down the string, convert from ASCII to decimal, and combine the bytes + pnum = ((fromSerial[3] - 48) * 100) + ((fromSerial[4] - 48) * 10) + ((fromSerial[5] - 48) * 1); + + pdata = ((fromSerial[7] - 48) * 1000000) + + ((fromSerial[8] - 48) * 100000) + + ((fromSerial[9] - 48) * 10000) + + ((fromSerial[10] - 48) * 1000) + + ((fromSerial[11] - 48) * 100) + + ((fromSerial[12] - 48) * 10) + + ((fromSerial[13] - 48) * 1); + + if (VB == 1) + { + Serial.print("Attempt Parm# "); + Serial.print(pnum); + Serial.print(" = "); + Serial.println(pdata); + } + + parms.write(pnum, pdata); + } + + // parm read PR ppp + if (fromSerial[0] == 'P' && fromSerial[1] == 'R' && fromSerial.length() == 6) + { // reading parm - must match length + + // first pull down the string, convert from ASCII to decimal, and combine the bytes + pnum = ((fromSerial[3] - 48) * 100) + ((fromSerial[4] - 48) * 10) + ((fromSerial[5] - 48) * 1); + + Serial.print("Parm# "); + Serial.print(pnum); + Serial.print(" = "); + Serial.println(parm[pnum]); + + if (pnum == 64) // serial# for label printer + Serial.printf("serial: %d\n", parm[64]); + + delay(2000); + } + + // toggle ioExpander relays + if (fromSerial[0] == 'T' && fromSerial[1] == 'R' && fromSerial.length() == 6) + { // reading parm - must match length + + // first pull down the string, convert from ASCII to decimal, and combine the bytes + pnum = ((fromSerial[3] - 48) * 100) + ((fromSerial[4] - 48) * 10) + ((fromSerial[5] - 48) * 1); + + if (pnum < 8) + { + if (exRly[pnum]) + exRly[pnum] = 0; + else + exRly[pnum] = 1; + + Serial.printf("ioExpander Relay %d = %d\n", pnum, exRly[pnum]); + } + else + Serial.println("Invalid relay#"); + + delay(2000); + } + + if (fromSerial[0] == 'I') // V511 read unused inputs + { + Serial.printf("Retract Switch %d\n", io_array[RET_LIMIT]); + Serial.printf("Extend Switch %d\n", io_array[EXT_LIMIT]); + Serial.printf("Open Limit Switch %d\n", io_array[OPEN_LIMIT]); + Serial.printf("RF Keypad %d\n", io_array[RF_KEYPAD]); + Serial.printf("Spare Input %d\n", io_array[SPARE_IN]); + } + + /* + //List Directory + if (fromSerial[0] == 'L' && fromSerial[1] == 'D') + listDir("/", 3); + + //Create Directory + if (fromSerial[0] == 'C' && fromSerial[1] == 'D') + createDir("/data"); + + //Move File + if (fromSerial[0] == 'M' && fromSerial[1] == 'F') + renameFile("/update.bin", "/data/update.old"); + + //Save Queue + // if (fromSerial[0] == 'S' && fromSerial[1] == 'Q') + // save_aQbuffer(); + + //Battery A2D + //if (fromSerial[0] == 'B' && fromSerial[1] == 'D') + //{ + // Serial.print("Battery A2D: "); + // Serial.println(analogRead(BATTERYINPUTPIN)); + //} + + + //Upload Data + if (fromSerial[0] == 'U' && fromSerial[1] == 'D') + { + if(uploadFtpFile("/50-4-10-13-25-35.atQ","/httpdocs/aQData","50-4-10-13-25-35.atQ")) + renameFile("/50-4-10-13-25-35.atQ", "/data/50-4-10-13-25-35.uld"); // effectivley.. this moves it to another dir as well + } + */ + // Toggle Spare + if (fromSerial[0] == 'T' && fromSerial[1] == 'S' && fromSerial.length() == 2) + { // reading + if (io_array[SPARE_OUT]) + io_array[SPARE_OUT] = 0; + else + io_array[SPARE_OUT] = 1; + + Serial.printf(" Spare = %d\n", io_array[SPARE_OUT]); + } + + // Epoch read ER + if (fromSerial[0] == 'E' && fromSerial[1] == 'R' && fromSerial.length() == 2) + { // reading + Serial.printf("RTC Epoch Time: %u\n", getEpochRtc()); + } + + // Timer Read + if (fromSerial[0] == 'T' && fromSerial[1] == 'R' && fromSerial.length() == 6) + { // reading parm - must match length + + // first pull down the string, convert from ASCII to decimal, and combine the bytes + pnum = ((fromSerial[3] - 48) * 100) + ((fromSerial[4] - 48) * 10) + ((fromSerial[5] - 48) * 1); + + Serial.print("Timer# "); + Serial.print(pnum); + Serial.print(" = "); + Serial.println(Timers[pnum]); + } + + // Epoch write EW 1234567890 + if (fromSerial[0] == 'E' && fromSerial[1] == 'W' && fromSerial.length() == 13) + { + edata = + ((fromSerial[3] - 48) * 1000000000) + + ((fromSerial[4] - 48) * 100000000) + + ((fromSerial[5] - 48) * 10000000) + + ((fromSerial[6] - 48) * 1000000) + + ((fromSerial[7] - 48) * 100000) + + ((fromSerial[8] - 48) * 10000) + + ((fromSerial[9] - 48) * 1000) + + ((fromSerial[10] - 48) * 100) + + ((fromSerial[11] - 48) * 10) + + ((fromSerial[12] - 48) * 1); + + setEpochRtc(edata); + } + } +} + +// v521 screen stuff + +int screenCase = 0; +bool SCREENOPEN = 0; +bool SCREENCLOSE = 0; +bool SCREENSTOP = 0; + +#define SCREEN_UP 0 +#define SCREEN_DN 1 +#define SCREEN_STP 2 + +void screenLogic(void) +{ + // Serial.print(screenCase); Serial.print(" "); Serial.println(Timers[SCREENTIMER]); + switch (screenCase) + { + case 0: + screenCase = 1; + exRly[SCREEN_UP] = 0; + exRly[SCREEN_DN] = 0; + exRly[SCREEN_STP] = 0; + SCREENOPEN = 0; + SCREENCLOSE = 0; + SCREENSTOP = 0; + break; + + case 1: // idle + if (SCREENOPEN) + { + exRly[SCREEN_UP] = 1; + Timers[SCREENTIMER] = 1; + screenCase = 2; + } + if (SCREENCLOSE) + { + exRly[SCREEN_DN] = 1; + Timers[SCREENTIMER] = 1; + screenCase = 2; + } + if (SCREENSTOP) + { + exRly[SCREEN_STP] = 1; + Timers[SCREENTIMER] = 1; + screenCase = 2; + } + break; + + case 2: + { + if (Timers[SCREENTIMER] > parm[3]) // screen button timeout + screenCase = 0; + } + break; + + default: + screenCase = 0; + break; + } +} + +int relayTest; +void ioTest(void) +{ + int ii; + + for (ii = 0; ii < 4; ii++) + { + exRly[ii] = 0; + } + exRly[relayTest] = 1; + if (++relayTest >= 4) + relayTest = 0; + for (ii = 0; ii < 4; ii++) + { + Serial.print(" In"); + Serial.print(exOpto[ii]); + Serial.print(" Out"); + Serial.print(exRly[ii]); + } + Serial.println(); +} + +void tone(byte pin, int freq, int duration) +{ + int CHANNEL = 1; + ledcSetup(CHANNEL, freq, 8); // V511 was ledcSetup(pin,freq,8) + ledcAttachPin(pin, CHANNEL); + ledcWrite(CHANNEL, 128); // 50% duty cycle + delay(duration); + ledcWrite(CHANNEL, 0); // turn off pwm + ledcDetachPin(pin); +} diff --git a/EVOG2.ino.elf b/EVOG2.ino.elf new file mode 100644 index 0000000..77e614f Binary files /dev/null and b/EVOG2.ino.elf differ diff --git a/EVOG2.ino.esp32.bin b/EVOG2.ino.esp32.bin new file mode 100644 index 0000000..3d662ad Binary files /dev/null and b/EVOG2.ino.esp32.bin differ diff --git a/Faults_ADI.ino b/Faults_ADI.ino new file mode 100644 index 0000000..fe674dd --- /dev/null +++ b/Faults_ADI.ino @@ -0,0 +1,206 @@ +/* + 0 No Flow fault + 1 Flow fault (leak) + 2 Power Up + 3 Expansion comms fault + 4 Display Ping fault + 5 Wifi Timeout + 6 No AT200 RX Timeout +*/ + +#define MAXFAULTS 100 +int faultCount[MAXFAULTS]; +const int faultLimits[MAXFAULTS] = // how many consective faults befor it's real + { + 1, // 0 powerup + 2, // 1 SD card error + 1, // 2 low battery + 4, // 3 + 1, // 4 + 1, // 5 + 1, // 6 + 1, + 1, + 1, + 1, // 10 + 1, + 1, + 1, + 1, + 1, // 15 + 1, + 1, + 1, + 1, + 1, // 20 + 1, + 1, + 1, + 1, // 24 + 1, // 25 Obstruction Fault + 1, + 1, + 1, + 1, + 1, // 30 + 1, + 1, + 1, // 33 Get motor error + 1, // 34 motor fault + 1, // 35 Lidar obstruction fault + 1, // 36 No display 1 + 1, + 1, + 1, + 1, // 40 + 1, + 1, + 1, + 1, + 1, // 45 + 1, + 1, + 1, + 1, // 49 + 1, // 50 + 1, + 1, + 1, + 1, + 1, // 55 + 1, + 1, + 1, + 1, + 1, // 60 + 1, + 1, + 1, + 1, + 1, // 65 + 1, + 1, + 1, + 1, // 69 + 1, // 70 + 1, + 1, + 1, + 1, + 1, // 75 + 1, + 1, + 1, + 1, + 1, // 80 + 1, + 1, + 1, + 1, + 1, // 85 + 1, + 1, + 1, + 1, // 89 + 1, // 90 + 1, + 1, + 1, + 1, + 1, // 95 + 1, + 1, + 1, + 1 // 99 +}; + +#define fault_QSIZ 40 +struct faultQ +{ + uint16_t faultnum; + uint32_t etime; + int32_t data[6]; +} fault_Q[fault_QSIZ], fault_Qtempdata; + +int fault_Qhead = 0; +int fault_Qtail = 0; + +#define RENLITAOFFSET 400 // Renlita fault num offset in cloud + +void initFaults(void) +{ + // int fi; + // for (fi = 0; fi < MAXFAULTS; fi++) faultCount[fi] = 0; + memset(faultCount, 0, sizeof(faultCount)); + memset(fault_Q, 0, sizeof(fault_Q)); + fault_Qhead = 0; + fault_Qtail = 0; +} + +void qualifyFault(int fnum, int32_t fdat) +{ + + if (fnum < MAXFAULTS) + { + if (faultCount[fnum] < faultLimits[fnum]) // no fault last time + if (++faultCount[fnum] >= faultLimits[fnum]) // no previous fault + { + faultQ_push(fnum + RENLITAOFFSET, fdat); + } + } +} + +void restoreFault(int fnum) +{ + + if (fnum < MAXFAULTS) + if (faultCount[fnum] > 0) + { + faultCount[fnum] = 0; + Serial.print("Fault Restored "); + Serial.println(fnum); + } +} + +void faultQ_push(int fnum, int32_t fdat) // load tempdata struct first.. pointer sits on next one to add +{ + + fault_Q[fault_Qhead].faultnum = fnum; + fault_Q[fault_Qhead].etime = getEpochRtc(); + fault_Q[fault_Qhead].data[0] = fdat; + + Serial.println("Fault Push"); + Serial.println(fnum); + + if (++fault_Qhead >= fault_QSIZ) + fault_Qhead = 0; // if at end then wrap + + if (fault_Qhead == fault_Qtail) + fault_Qtail++; // if hit other pointer then we full + if (fault_Qtail == fault_QSIZ) + fault_Qtail = 0; // if at end then wrap +} + +void faultQ_pull(void) // dumps into tempdata struct pointer sits on next on to pull +{ + int f; + fault_Qtempdata.faultnum = fault_Q[fault_Qtail].faultnum; + fault_Qtempdata.etime = fault_Q[fault_Qtail].etime; + + for (f = 0; f < 6; f++) + fault_Qtempdata.data[f] = fault_Q[fault_Qtail].data[f]; + + Serial.println("Fault Pull"); + Serial.println(fault_Qtempdata.faultnum); + + if (++fault_Qtail == fault_QSIZ) + fault_Qtail = 0; // if at end then wrap +} + +int faultQ_size(void) +{ + if (fault_Qhead >= fault_Qtail) + return (fault_Qhead - fault_Qtail); + else + return ((fault_QSIZ - fault_Qtail) + fault_Qhead); +} diff --git a/FileLib.h b/FileLib.h new file mode 100644 index 0000000..815e7da --- /dev/null +++ b/FileLib.h @@ -0,0 +1,191 @@ +#ifndef FILE_LIB_H +#define FILE_LIB_H + +#include +#include +#include +#include +#include + +/** + * @enum StorageType + */ +enum StorageType +{ + /** + * Use onboard SPIFFS + */ + FL_SPIFFS, + /** + * Use the SD library + */ + FL_SD, + /** + * Use the SD_MMC library + */ + FL_MMC +}; + +/** + * @class FileLibClass + * @brief Wrapper for SPIFFS and SD file systems + */ +class FileLibClass +{ +private: + fs::FS *_filesystem = nullptr; + SPIClass _spi = SPIClass(VSPI); + StorageType _type; + + bool _verbose = false; + + /** + * Print out message, if verbose mode is enabled + */ + void _printMessage(const char *message, ...); + +public: + /** + * Constructor + * @param type StorageType::SPIFFS or StorageType::SD + */ + FileLibClass(StorageType type); + + /** + * Destructor + */ + ~FileLibClass(); + + /** + * Begin the file system + * @param csPin Optional, default 5. Chip select pin for SD card + * @param misoPin Optional, default 19. MISO pin for SD card + * @param mosiPin Optional, default 23. MOSI pin for SD card + * @param sckPin Optional, default 18. SCK pin for SD card + * + * @return True if successful + */ + bool begin(uint8_t csPin = 5, uint8_t misoPin = 19, uint8_t mosiPin = 23, uint8_t sckPin = 18); + + /** + * Enable or disable verbose mode + * @param verbose True to enable verbose mode + */ + void setVerbose(bool verbose) { _verbose = verbose; } + + /** + * Open the file + * @param fileName Path and filename to open + * + * @return File object + */ + File openForWriting(const char *fileName); + + /** + * Open the file + * @param fileName Filename to open + * + * @return File object + */ + File open(const char *fileName, const char *mode = FILE_READ); + + /** + * List the contents of a directory + * @param dirName Path to the directory + * @param levels Optional, default 0. How many levels deep to list + */ + void listDir(const char *dirName, uint8_t levels = 0); + + /** + * Read from a file. This opens the file and reads + * the data into a buffer. Clears the buffer before reading + * by default. + * @param fileName Path and filename to read from + * @param buffer Buffer to read to. + * @param bufferSzie Size of the buffer. + * @param clearBuffer Optional, default true. If true, the buffer will be cleared before reading + * + * @return True if successful + */ + bool read(const char *fileName, uint8_t *buffer, uint16_t bufferSize, bool clearBuffer = true); + + /** + * Write to a file. This opens the file and + * writes the bytes to the file. + * @param fileName Path and filename to write to + * @param data What will be written to the file + * @param dataSize Size of the data + * @param append Optional, default false. If true, the data will be appended to the file + * + * @return True if successful + */ + bool write(const char *fileName, const uint8_t *data, size_t dataSize, bool append = false); + + /** + * Write to a file. This opens the file and + * writes string data to the file. This is a wrapper + * for write(). + * @param fileName Path and filename to write to + * @param data What will be written to the file + * @param dataSize Size of the data + * @param append Optional, default false. If true, the data will be appended to the file + * + * @return True if successful + */ + bool writeString(const char *fileName, const uint8_t *data, bool append = false); + + /** + * Delete a file + * @param fileName Path and filename to delete + * + * @return True if successful + */ + bool remove(const char *fileName); + + /** + * Rename a file + * @param fileName Path and filename to rename + * @param newName New path and filename + * @param overwrite Optional, default false. If true, the new file will overwrite an existing file + * + * @return True if successful + */ + bool rename(const char *fileName, const char *newName, bool overwrite = false); + + /** + * Create a directory. Spiff currently doesn't support this. + * @param path Path to the directory + * + * @return True if successful + */ + bool mkdir(const char *path); + + /** + * Get free space on the file system. Return + * + * @return Free space in bytes + */ + uint64_t getFreeSpace(); + + /** + * Copy a file from a source to a destination + * + * @param source File object to copy from + * @param dest File object to copy to + */ + bool copy(File &source, File &dest); + + /** + * Read a portion of a file + * + * @param fileName Path and filename to read from + * @param startPos Starting position to read from + * @param buffer Buffer to read to + * @param bufferSize Size of the buffer + */ + bool readPartial(const char *fileName, uint32_t startPos, uint8_t *buffer, uint16_t bufferSize); + + bool exists(const char* fileName); +}; + +#endif