Files
wordclock/code/main/main.cpp
T

383 lines
13 KiB
C++

// --------------------------------------------------------------------------------------------------------------------
/// \file main.cpp
/// \brief Description
// --------------------------------------------------------------------------------------------------------------------
//
// vbchaos software design
//
// --------------------------------------------------------------------------------------------------------------------
/// $Revision: $
/// $Author: $
/// $Date: $
// (c) 2023 vbchaos
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Include files
// --------------------------------------------------------------------------------------------------------------------
#include <string.h>
#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<std::string> clockWordlist;
std::list<std::string> tempWordList;
uint32_t runninglightIndex = 0;
while(1)
{
if (!otaActive)
{
matrix.clearAll();
clk.generateWordlist(&clockWordlist);
std::list<std::string>::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;
}
}