// -------------------------------------------------------------------------------------------------------------------- /// \file main.cpp /// \brief Description // -------------------------------------------------------------------------------------------------------------------- // // vbchaos software design // // -------------------------------------------------------------------------------------------------------------------- /// $Revision: $ /// $Author: $ /// $Date: $ // (c) 2023 vbchaos // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // Include files // -------------------------------------------------------------------------------------------------------------------- #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" // ESP includes #include "driver/uart.h" #include "esp_log.h" #include "nvs_flash.h" // HAL includes #include "esplog.h" #include "gpio.h" #include "i2c.h" #include "uart.h" // Platform includes #include "bmp280.h" #include "isl29125.h" #include "logger.h" #include "ledmatrix.h" #include "wifi.h" // Application includes #include "clock.h" #include "clockwordmap.h" #include "daywordmap.h" #include "messagewordmap.h" #include "ota.h" #include "temperature.h" #include "temperaturewordmap.h" // -------------------------------------------------------------------------------------------------------------------- // Constant and macro definitions // -------------------------------------------------------------------------------------------------------------------- #define ESP32C3_01M_KIT //#define ESP32C3_DEVKIT_M1 #if defined(ESP32C3_DEVKIT_M1) #define GPIO_I2C_SCK ((uint32_t)3) #define GPIO_I2C_SDA ((uint32_t)2) #define GPIO_LED_ONBOARD ((uint32_t)8) #define GPIO_LED_STRIP ((uint32_t)9) #elif defined(ESP32C3_01M_KIT) #define GPIO_I2C_SCK ((uint32_t)8) #define GPIO_I2C_SDA ((uint32_t)9) #define GPIO_LED_STRIP ((uint32_t)0) #else #error "No supported target platform defined" #endif #define MATRIX_NMBR_ROWS ((uint32_t)13) #define MATRIX_NMBR_COLUMS ((uint32_t)20) // -------------------------------------------------------------------------------------------------------------------- // Type definitions // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // File-scope variables // -------------------------------------------------------------------------------------------------------------------- static TaskHandle_t loggerTaskHandle; static TaskHandle_t otaTaskHandle; static bool otaActive = false; // -------------------------------------------------------------------------------------------------------------------- // Function declarations // -------------------------------------------------------------------------------------------------------------------- void loggerTask(void* parameters); void otaTask(void* parameters); static void otaCallback(struct ota::statusCallbackData* status); // -------------------------------------------------------------------------------------------------------------------- // Function definitions // -------------------------------------------------------------------------------------------------------------------- extern "C" void app_main(void) { esp_log_level_set("*", ESP_LOG_INFO); esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } // ----------------------------------------------------------------------------------------------------------------- // UART // uart_config_t uartConfig = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .rx_flow_ctrl_thresh = 0, .source_clk = UART_SCLK_DEFAULT }; uart_port_t debugUart = UART_NUM_0; ESP_ERROR_CHECK(uart_param_config(debugUart, &uartConfig)); ESP_ERROR_CHECK(uart_set_pin(debugUart, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install(debugUart, 1024, 1024, 0, NULL, 0)); // uart uartDebug = uart(&debugUart); // uartDebug.open(); // uartDebug.write(255, 255, (uint8_t*)"START", 5); esplog esplogger = esplog(); esplogger.open(); // ----------------------------------------------------------------------------------------------------------------- // System-wide Debug Logger // // logger debugLogger = logger(16, uartDebug); logger debugLogger = logger(20, esplogger); // Call the logger executable within a dedicated task and forget about it afterwards xTaskCreate(loggerTask, (const char*)"loggerTask", 3000, &debugLogger, 3, &loggerTaskHandle); LOGGER_PRINT("\n\r-----------------------------------------------------------------------\n\r"); LOGGER_PRINT("System Start\n\r"); LOGGER_PRINT("\n\r"); LOGGER_PRINT("WordClock\n\r"); LOGGER_PRINT("Release: %d.%d \n\r", MAJORRELEASE, MINORRELEASE); LOGGER_PRINT("Compiled on %s at %s\n\r\n\r\n\r", __DATE__, __TIME__); // ----------------------------------------------------------------------------------------------------------------- // I2C Masterbus for sensoring peripherals // i2c_port_t i2c_master_port = I2C_NUM_0; i2c_config_t i2cConfig = { .mode = I2C_MODE_MASTER, .sda_io_num = (int)GPIO_I2C_SDA, .scl_io_num = (int)GPIO_I2C_SCK, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master = 400000, .clk_flags = 0 }; ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &i2cConfig)); ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, i2cConfig.mode, 0, 0, 0)); i2c i2cSensor = i2c(&i2c_master_port); i2cSensor.open(); // // ----------------------------------------------------------------------------------------------------------------- // // I2C RGB Sensor on I2C MasterBus for sensors // // // isl29125 rgbSensor = isl29125(0x44, i2cSensor); // rgbSensor.initialize(); // vTaskDelay(100); // rgbSensor.setMode(isl29125::RGB); // rgbSensor.setRange(isl29125::HIGH); // rgbSensor.setResolution(isl29125::RES_16BIT); // vTaskDelay(100); // struct isl29125::rgb_t rgbValue; // rgbSensor.getRGB(&rgbValue); // ----------------------------------------------------------------------------------------------------------------- // I2C RGB Sensor on I2C MasterBus for sensors // bmp280 tempSensor = bmp280(0x76, i2cSensor); // Reset the sensor tempSensor.resetSensor(); // Make sure to apply a wait cycle between reset and continuous use - 2ms is advised as minimum vTaskDelay(10); // Initialize the BMP280 tempSensor.initialize(); // Set the temperature Oversampling tempSensor.setSensorTemperatureOversampling(bmp280::BMP280_Oversampling_t::X1); // Set the sensor to NORMAL mode tempSensor.setSensorMode(bmp280::BMP280_Mode_t::NORMAL); // ----------------------------------------------------------------------------------------------------------------- // Wifi create and connect // Wifi wifi = Wifi(); wifi.start_client(); // ----------------------------------------------------------------------------------------------------------------- // Programmable LEDs in a strip // ledmatrix matrix = ledmatrix(MATRIX_NMBR_ROWS, MATRIX_NMBR_COLUMS, GPIO_LED_STRIP); // Set the matrix orientation to ROW-based, from left to right, beginning on the upside matrix.setOrientation(ledmatrix::ORIENTATION_ROW_LEFT_UP); // ----------------------------------------------------------------------------------------------------------------- // The clock which also handles the NTP // Clock clk = Clock(Clock::Mode_t::TEN_BEFORE_HALF); // ----------------------------------------------------------------------------------------------------------------- // The Temperature class that calculates temperature string and colour // temperature temp = temperature(); // ----------------------------------------------------------------------------------------------------------------- // Wordmaps for clock(time), clock(day), temperature and one for other messages // ClockWordmap clockwords = ClockWordmap(&matrix); clockwords.setColour(0xFF, 0xFF, 0x20); DayWordmap daywords = DayWordmap(&matrix); daywords.setColour(0x00, 0xFF, 0xFF); temperaturewordmap tempwords = temperaturewordmap(&matrix); messagewordmap messagewords = messagewordmap(&matrix); messagewords.setColour(0xC0, 0x00, 0xC0); for (int cnt = 0; cnt < 10; cnt++) { for (uint32_t i = 0; i < MATRIX_NMBR_ROWS; i++) { matrix.clearAll(); matrix.setRow(i, i * 20, i * 30, i * 40); matrix.update(); vTaskDelay(2); } for (uint32_t i = 0; i < MATRIX_NMBR_COLUMS; i++) { matrix.clearAll(); matrix.setColumn(i, i * 20, i * 30, i * 40); matrix.update(); vTaskDelay(2); } } // ----------------------------------------------------------------------------------------------------------------- // OTA handler // ota otaUpdater = ota(); otaUpdater.usCallback = otaCallback; // Call the OTA executable within a dedicated task and forget about it afterwards xTaskCreate(otaTask, (const char*)"OTATask", 4000, &otaUpdater, 3, &otaTaskHandle); std::list clockWordlist; std::list tempWordList; uint32_t runninglightIndex = 0; while(1) { if (!otaActive) { matrix.clearAll(); clk.generateWordlist(&clockWordlist); std::list::iterator it; for(it = clockWordlist.begin(); it != clockWordlist.end(); it++) { clockwords.setWord(wordmap::Language_t::NL, *it, true); daywords.setWord(wordmap::Language_t::NL, *it, true); } // Get the temperature from sensor int currentTemperature = tempSensor.getTemperature() / 100; LOGGER_INFO("The current temperature is: %i (%s)", currentTemperature, std::to_string(21)); // Generate temperature wordlist temp.generateWordlist(currentTemperature, &tempWordList); for(it = tempWordList.begin(); it != tempWordList.end(); it++) { tempwords.setWord(wordmap::Language_t::NL, *it, true); } uint8_t tRed, tGreen, tBlue; temp.calculateRGB(currentTemperature, &tRed, &tGreen, &tBlue); tempwords.setColour(tRed, tGreen, tBlue); matrix.update(); } else { matrix.clearAll(); while (otaActive) { // Create a running light on the lowest row matrix.setPixel(MATRIX_NMBR_ROWS - 1, runninglightIndex, 0xFF - runninglightIndex * 10, runninglightIndex * 5, runninglightIndex * 10); matrix.update(); vTaskDelay(10); matrix.setPixel(MATRIX_NMBR_ROWS - 1, runninglightIndex, 0, 0, 0); matrix.update(); runninglightIndex < (MATRIX_NMBR_COLUMS - 1) ? runninglightIndex++ : runninglightIndex = 0; } } vTaskDelay(1000); } } void loggerTask(void* parameters) { logger* debugLogger = (logger*) parameters; while (1) { debugLogger->task(); vTaskDelay(2); } } void otaTask(void* parameters) { ota* otaHandler = (ota*) parameters; while (1) { otaHandler->task(); vTaskDelay(otaHandler->checkInterval_ms); } } void otaCallback(struct ota::statusCallbackData* status) { switch (status->status) { case ota::UpdateStatus_t::OTA_STATUS_IDLE: otaActive = false; break; case ota::UpdateStatus_t::OTA_STATUS_DOWNLOAD: LOGGER_INFO("Downloading OTA file from server"); otaActive = false; break; case ota::UpdateStatus_t::OTA_STATUS_VERIFY: LOGGER_INFO("Verifying OTA firmware file"); otaActive = false; break; case ota::UpdateStatus_t::OTA_STATUS_WRITE: // LOGGER_INFO("Writing OTA firmware file to FLASH - Current progress: %i \%", status->percentage); otaActive = true; break; case ota::UpdateStatus_t::OTA_STATUS_UPDATE: LOGGER_INFO("Updating the OTA partition"); otaActive = true; break; case ota::UpdateStatus_t::OTA_STATUS_SUCCESS: LOGGER_SUCCESS("The OTA firmware update was finished successfully"); otaActive = true; break; case ota::UpdateStatus_t::OTA_STATUS_FAIL: LOGGER_ERROR("The OTA firmware update failed"); otaActive = false; break; case ota::UpdateStatus_t::OTA_STATUS_RESTART: LOGGER_INFO("Restarting the device after OTA finished"); otaActive = false; break; } }