#include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" // #include "freertos/FreeRTOSConfig.h" #include "sdkconfig.h" #include #include #include #include "soc/ledc_reg.h" #include "soc/ledc_struct.h" #include "esp_adc_cal.h" #include "esp_log.h" #include #include #include #include "system.h" #include "JsonConstrain.h" #include "common/fileSystem.h" #include "my_board.h" #include "global.h" #include "my_wifi.h" #include "my_buzzer.h" #include "my_tsensor.h" #include "my_buttons.h" #include "PWM_Output.h" #include "Ramp_Lights.h" #include "BleServer.h" #include "ATALights.h" #include "OnEveryN.h" #include "BLE_SP110E.h" #include "BleSettings.h" #define FREERTOs_DIAGNOSTICS 0 #define OLED_ENABLED 0 #define WIFI_ENABLED 0 #define STRIPS_ENABLED 1 #define LUMASTIK_ENABLED 0 #define PRINT_SYSTEM_STATUS 0 #if OLED_ENABLED #include "my_oled.h" #endif #if WIFI_ENABLED #include "my_wifi.h" #endif #if STRIPS_ENABLED #include "led_strip.h" #endif #if LUMASTIK_ENABLED #include "luma_master.h" #endif #if LUMASTIK_ENABLED #define LumaCountReset (20000 / 25) int LumaCountdown = LumaCountReset; LUMA_PACKET lumaPacket; #endif static const char *tag = "main"; SYS_SETTINGS sys_settings; PWM_Output *pwmOutputs[4]; RAMP_LIGHT *rampLight1; RAMP_LIGHT *rampLight2; bool UpgradeMode = false; void Init_ADC(void); float readBoardInputVoltage(void); void setupLogLevels(esp_log_level_t logLevel); void Get_Board_and_Booth_File_Paths(const char *, String &, String &); void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath); void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]); void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]); void checkLEDCChannels() { for (int i = 0; i < 8; i++) { if (LEDC.channel_group[0].channel[i].conf0.val != 0 || LEDC.channel_group[1].channel[i].conf0.val != 0) { ESP_LOGD(tag, "Channel %d is configured\n", i); } } } #define Button1Pin 8 void setup() { // Serial Port Serial.begin(115200); while (!Serial); // Initialize I2C Port for TSensor, ... Wire.begin(I2C_SDA1_Pin, I2C_SCL1_Pin); sys_settings.ledStripSettings[0] = &ledSettings[0]; sys_settings.ledStripSettings[1] = &ledSettings[1]; // Set Logging Levels // esp_log_level_t logLevel = ESP_LOG_INFO; // pinMode(Button1Pin, INPUT); // Button1 // if(!digitalRead(Button1Pin)){ // logLevel = ESP_LOG_VERBOSE; //} // setupLogLevels(logLevel); setupLogLevels(ESP_LOG_INFO); // chip id, mac, print_chip_info(); // Init LittleFS Init_File_System(); // Print all system files if (digitalRead(sys_settings.boardPins.btn[0]) == LOW){ printAllSystemFiles(); } String board_file_path, booth_file_path; Get_Board_and_Booth_File_Paths("/system/system.json", board_file_path, booth_file_path); // Load Board Pins Load_Board_Pins(sys_settings.boardPins, board_file_path); // Set status pins off setStatusPin1(false); setStatusPin2(false); // Load Booth Settings Load_Booth_Settings(sys_settings, booth_file_path); // Load Wifi Settings Wifi_Load_Settings("/system/wifi.json"); // config stat, relays, buttons Init_Board_Basic(sys_settings.boardPins); // Load tunes.json and initialize Init_Buzzer(sys_settings.boardPins.buzzer, "/system/tunes.json"); // Initialize PWM Outputs Init_PWM_Outputs(sys_settings.boardPins.relay, sys_settings.pwmOutSettings); // activate button clicks Init_ButtonEvents(sys_settings.boardPins.btn); // Initialize Ramp Lights Init_Ramp_Lights(sys_settings.rampLightSettings, boardButtons, pwmOutputs); // Initialize ADC Init_ADC(); // Initialize Temperature Sensor Init_TSensor(72); float val = readBoardInputVoltage(); ESP_LOGI(tag, "Input Volage = %f", val); // Initialize BLE Load_BLE_Settings("/system/ble.json"); if (digitalRead(sys_settings.boardPins.btn[0]) == LOW) { setStatusPin1(true); UpgradeMode = true; ESP_LOGW(tag, "Enabling BLE and Update Service"); Init_BleServer(true, true); ESP_LOGW(tag, "Enabling Wifi AP and Client"); Wifi_Init(); } else { ESP_LOGI(tag, "Enabling BLE, No Update Service"); Init_BleServer(true, false); // Dont start the Upgrade service } // If lightstick mode is enabled, start ble lightstick client task if (sys_settings.mode == BOOTH_MODE_STIK) { Init_BLE_LightStick_Client(); } #if OLED_ENABLED // Init OLED Init_OLED(sys_settings.oledSettings.width, sys_settings.oledSettings.height, sys_settings.boardPins.oled_mosi, sys_settings.boardPins.oled_sck, sys_settings.boardPins.oled_dc, sys_settings.boardPins.oled_rst, sys_settings.boardPins.oled_cs); #endif #if STRIPS_ENABLED Init_Lights_Task(); #endif Buzzer_Play_Tune(TUNE_BOOT, true, true); // TODO... Test if this is still necessary need to configure pin 0 for some reason // pinMode(0, INPUT); // button0/boot pin #if LUMASTIK_ENABLED Init_Luma_Master(); #endif vTaskDelay(100); Lights_Control_Task_Resume(); } void loop() { // Button Scanning ON_EVERY_N_MILLISECONDS(10) { for (int i = 0; i < 3; i++) { if (boardButtons[i] != NULL) { boardButtons[i]->tick(); } } } // Temperature Monitor ON_EVERY_N_MILLISECONDS(5000) { static float boardTemperature; // Read temperature if the sensor is enabled if (sys_settings.tSensorSettings.enabled) { boardTemperature = tSensor->readTemperatureF(); // ESP_LOGI(tag, "Board T: %F", boardTemperature); } // Fan Control if (sys_settings.tSensorSettings.enabled) { UpdateFanControl(boardTemperature, pwmOutputs[sys_settings.tSensorSettings.pwmIndex]); } } // Update Tune Playing //if (anyrtttl::nonblocking::isPlaying()) //{ // anyrtttl::nonblocking::play(); //} // Animation TestMode Timeout #if LEDS_ENABLED if (animStatus.EventTestCountdown) { if (--animStatus.EventTestCountdown == 0) { ESP_LOGD(tag, "Test Timeout trigger"); PostLastNormalEvent(); if (Strip1_Task_Handle) { xTaskNotifyGive(Strip1_Task_Handle); } // trigger exit of animation loop } }; #endif // Reboot requested #if WIFI_ENABLED if (RebootSystem) { if (--RebootSystem == 0) { for (int i = 0; i < 3; i++) { #if BUZZER_ENABLED Buzzer_Play_Tune(TUNE_BEEP, false); // blocking #endif vTaskDelay(200); } ESP_LOGW(tag, "Restarting..."); vTaskDelay(200); ESP.restart(); } } #endif // Toggle Status LED L2 ON_EVERY_N_MILLISECONDS(500) { if (sys_settings.boardPins.stat[1] >= 0) { static bool ledState = false; // digitalWrite(sys_settings.boardPins.stat[1], ledState = !ledState); setStatusPin2(ledState = !ledState); } } // Upgrade Mode Tune if(UpgradeMode){ ON_EVERY_N_MILLISECONDS(5000) { Buzzer_Play_Tune(TUNE_ACK, true, true); } } #if FREERTOs_DIAGNOSTICS ON_EVERY_N_MILLISECONDS(60000) { print_task_watermarks(); } #endif // Turn off white light after timeout ON_EVERY_N_MILLISECONDS(100) { // Only decrement if timeout is active if (whiteTimeout > 0) { whiteTimeout--; if (whiteTimeout == 0) { Lights_Set_White(0); ESP_LOGD(tag, "White light timeout triggered"); } } } } void setupLogLevels(esp_log_level_t logLevel) { // Options: ESP_LOG_ERROR,ESP_LOG_WARN,ESP_LOG_INFO,ESP_LOG_DEBUG,ESP_LOG_VERBOSE esp_log_level_set("*", logLevel); esp_log_level_set("fs", logLevel); esp_log_level_set("main", logLevel); esp_log_level_set("board", logLevel); esp_log_level_set("ramp", logLevel); esp_log_level_set("button", logLevel); esp_log_level_set("buzzer", logLevel); esp_log_level_set("global", logLevel); esp_log_level_set("jsCon", logLevel); esp_log_level_set("ble", logLevel); esp_log_level_set("pwmout", logLevel); esp_log_level_set("wifi", logLevel); esp_log_level_set("stiks", logLevel); esp_log_level_set("oled", logLevel); esp_log_level_set("trx433", logLevel); esp_log_level_set("tsensor", logLevel); } // TODO Restore original setOutput code.. #define RELAY_RES 10 void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) { for (int i = 0; i < 4; i++) { int chIndex = findUnusedLedcChannel(); if (chIndex < 0) { ESP_LOGE(tag, "No available LEDC channel for PWM Output%d", i); continue; } pwmOutputs[i] = new PWM_Output(pin[i], chIndex, RELAY_RES, pwmSettings[i].freq, pwmSettings[i].max, false); pwmOutputs[i]->setOutput(pwmSettings[i].def); // pwmOutputs[i]->setOutput(5.0); ESP_LOGI(tag, "PWM Output%d: Pin=%d, Freq=%d, ch=%d", i, pin[i], pwmSettings[i].freq, chIndex); } } void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]) { if (settings[0].enabled) { rampLight1 = new RAMP_LIGHT(btn[settings[0].btnIndex], pwm[settings[0].pwmOutIndex], 5.0, 100.0, 1.5); ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d", 1, settings[0].btnIndex, settings[0].pwmOutIndex); } if (settings[1].enabled) { rampLight2 = new RAMP_LIGHT(btn[settings[1].btnIndex], pwm[settings[1].pwmOutIndex], 5.0, 100.0, 1.5); ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d", 2, settings[1].btnIndex, settings[1].pwmOutIndex); } } // Get the files that should be used to setup the system void Get_Board_and_Booth_File_Paths(const char *sysPath, String &boardPath, String &boothPath) { File file = LittleFS.open(sysPath); if (!file) { ESP_LOGE(tag, "Error opening %s...", sysPath); return; } JsonDocument doc; DeserializationError error = deserializeJson(doc, file); file.close(); if (error) { ESP_LOGE(tag, "%s deserialize error!..", sysPath); return; } // get hardware version string boardPath = jsonConstrainString(tag, doc.as(), "boardfile", "/cfg/boards/board15.json"); boothPath = jsonConstrainString(tag, doc.as(), "configfile", "/cfg/booths/custom.json"); } void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) { File file = LittleFS.open(boothPath); if (!file) { ESP_LOGE(tag, "Error opening %s...", boothPath.c_str()); return; } JsonDocument doc; DeserializationError error = deserializeJson(doc, file); file.close(); if (error) { ESP_LOGE(tag, "%s deserialize error!..", boothPath.c_str()); return; } // ********** Mode *********** String modeStr = jsonConstrainString(tag, doc.as(), "mode", "booth"); if (modeStr == "roamer") { sys_settings.mode = BOOTH_MODE_ROAMER; } else if (modeStr == "stik") { sys_settings.mode = BOOTH_MODE_STIK; } else { sys_settings.mode = BOOTH_MODE_NONE; } // ********** PWM Out *********** JsonArray pwmJsonArray = doc["pwmout"]; if (!pwmJsonArray.isNull()) { int pwmIndex = 0; for (JsonObject obj : pwmJsonArray) { if (pwmIndex >= 4) break; sys_settings.pwmOutSettings[pwmIndex].enabled = jsonConstrainBool(tag, obj, "en", true); sys_settings.pwmOutSettings[pwmIndex].freq = jsonConstrain(tag, obj, "freq", 100, 5000, 250); sys_settings.pwmOutSettings[pwmIndex].min = jsonConstrain(tag, obj, "min", 0.0, 95.0, 0.0); sys_settings.pwmOutSettings[pwmIndex].max = jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); sys_settings.pwmOutSettings[pwmIndex].def = jsonConstrain(tag, obj, "default", 0.0, 100.0, 0.0); sys_settings.pwmOutSettings[pwmIndex].deltaRate = 1.0; // sys_settings.pwmOutSettings[pwmIndex]. = jsonConstrainBool(tag, obj, "vision", true); pwmIndex++; } ESP_LOGI(tag, "Loaded PWmOutput settings..."); } else { ESP_LOGE(tag, "Error!, %s key: pwmout not found..", boothPath); } // ********** Ramp Lights *********** JsonArray rampJsonArray = doc["ramp-lights"]; if (!rampJsonArray.isNull()) { int rampIndex = 0; for (JsonObject obj : rampJsonArray) { if (rampIndex >= 2) break; sys_settings.rampLightSettings[rampIndex].enabled = jsonConstrainBool(tag, obj, "en", true); sys_settings.rampLightSettings[rampIndex].vision = jsonConstrainBool(tag, obj, "vision", true); sys_settings.rampLightSettings[rampIndex].pwmOutIndex = jsonConstrain(tag, obj, "relay-index", 0, 1, 0); sys_settings.rampLightSettings[rampIndex].btnIndex = jsonConstrain(tag, obj, "button-index", 0, 1, 0); sys_settings.rampLightSettings[rampIndex].min = jsonConstrain(tag, obj, "min", 0.0, 100.0, 0.0); sys_settings.rampLightSettings[rampIndex].max = jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); sys_settings.rampLightSettings[rampIndex].step = jsonConstrain(tag, obj, "step", 0.01, 100.0, 1.5); rampIndex++; } ESP_LOGI(tag, "Loaded Ramp Lights settings..."); } else { ESP_LOGE(tag, "Error!, %s key: ramp-lights not found..", boothPath); } // ********** Fan *********** JsonObject sensorJson = doc["t-sensor"]; if (!sensorJson.isNull()) { sys_settings.tSensorSettings.enabled = jsonConstrainBool(tag, sensorJson, "en", true); sys_settings.tSensorSettings.pwmIndex = jsonConstrain(tag, sensorJson, "relay", 0, 3, 3); sys_settings.tSensorSettings.setpoint1 = jsonConstrain(tag, sensorJson, "sp1", 0.0, 100.0, 80.0); sys_settings.tSensorSettings.setpoint2 = jsonConstrain(tag, sensorJson, "sp2", 0.0, 100.0, 85.0); sys_settings.tSensorSettings.fanPower1 = jsonConstrain(tag, sensorJson, "fan-pwr1", 0.0, 100.0, 50.0); sys_settings.tSensorSettings.fanPower2 = jsonConstrain(tag, sensorJson, "fan-pwr2", 0.0, 100.0, 50.0); sys_settings.tSensorSettings.hyst = jsonConstrain(tag, sensorJson, "hyst", 1.0, 10.0, 1.0); sys_settings.tSensorSettings.intervalMs = jsonConstrain(tag, sensorJson, "interval", 1000, 30000, 5000); ESP_LOGI(tag, "Loaded TSensor settings..."); ESP_LOGD(tag, " SP1: %F, SP2 %F, Hyst: %F", sys_settings.tSensorSettings.setpoint1, sys_settings.tSensorSettings.setpoint2, sys_settings.tSensorSettings.hyst); } else { ESP_LOGE(tag, "Error!, %s key: t-sensor not found..", boothPath); } // ********** RGB Strips *********** JsonArray stripsJsonArray = doc["strips"]; if (!stripsJsonArray.isNull()) { int stripIndex = 0; for (JsonObject obj : stripsJsonArray) { if (stripIndex >= 2) break; sys_settings.ledStripSettings[stripIndex]->enabled = jsonConstrainBool(tag, obj, "en", true); sys_settings.ledStripSettings[stripIndex]->size = jsonConstrain(tag, obj, "size", 1, 250, 25); sys_settings.ledStripSettings[stripIndex]->chip = jsonConstrainString(tag, obj, "chip", "WS2812B"); sys_settings.ledStripSettings[stripIndex]->rgbOrder = jsonConstrainString(tag, obj, "rgb-order", "WS2812B"); sys_settings.ledStripSettings[stripIndex]->shift = jsonConstrain(tag, obj, "shift", -250, 250, 0); sys_settings.ledStripSettings[stripIndex]->offset = jsonConstrain(tag, obj, "offset", -250, 250, 0); sys_settings.ledStripSettings[stripIndex]->bright = jsonConstrain(tag, obj, "bright", 5, 255, 200); sys_settings.ledStripSettings[stripIndex]->powerDiv = 0; sys_settings.ledStripSettings[stripIndex]->i2sCh = 0; sys_settings.ledStripSettings[stripIndex]->core = jsonConstrain(tag, obj, "core", 0, 1, 0); stripIndex++; } sys_settings.ledStripSettings[0]->pin = sys_settings.boardPins.rgb1; sys_settings.ledStripSettings[1]->pin = sys_settings.boardPins.rgb2; ESP_LOGI(tag, "Loaded LED Strip settings..."); } else { ESP_LOGE(tag, "Error!, %s key: strips not found.."); } // ********** BLE *********** JsonObject bleJson = doc["ble"]; if (!bleJson.isNull()) { sys_settings.bleSettings.enabled = jsonConstrainBool(tag, bleJson, "en", true); sys_settings.bleSettings.name = jsonConstrainString(tag, bleJson, "name", "ATA_LIGHTS"); ESP_LOGI(tag, "Loaded BLE settings..."); } else { ESP_LOGE(tag, "Error!, %s key: ble not found..", boothPath); } // ********** RF Remote*********** /* JsonObject rfJson = doc["wifi-ap"]; if(!rfJson.isNull()){ //sys_settings.rampLights[0].enabled = jsonConstrainBool(tag, wifiApJson, "en", true); ESP_LOGI(tag, "Loaded RF Remote settings..."); }else{ ESP_LOGE(tag, "Error!, %s key: wifi-ap not found..", boothPath); } */ } void Init_ADC(void) { // Configure ADC analogReadResolution(12); // 12-bit ADC analogSetAttenuation(ADC_11db); if (sys_settings.boardPins.adc1 >= 0) { analogSetPinAttenuation(sys_settings.boardPins.adc1, ADC_11db); } // Enable ADC calibration esp_adc_cal_characteristics_t adc_chars; esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0, &adc_chars); // Check calibration success if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { ESP_LOGI(tag, "ADC calibration: Using Two Point values from eFuse"); } else if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { ESP_LOGI(tag, "ADC calibration: Using reference voltage from eFuse"); } else { ESP_LOGW(tag, "ADC calibration: Using default reference voltage"); } } float readBoardInputVoltage(void) { const int SAMPLES = 64; uint32_t reading = 0; if (sys_settings.boardPins.adc1 < 0) { ESP_LOGE(tag, "ADC Pin not valid"); return 0.0; } // Multiple readings for averaging for (int i = 0; i < SAMPLES; i++) { reading += analogRead(sys_settings.boardPins.adc1); delayMicroseconds(50); // Small delay between samples } reading /= SAMPLES; // Convert raw ADC to voltage using calibration uint32_t voltage_mv; esp_adc_cal_characteristics_t adc_chars; esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); voltage_mv = esp_adc_cal_raw_to_voltage(reading, &adc_chars); // Scale to 12V range float voltage = (voltage_mv / 1000.0f) * (10470.0f / 470.0f); return voltage; }