diff --git a/code/.project b/code/.project index 1514a30..06fb76d 100644 --- a/code/.project +++ b/code/.project @@ -968,11 +968,6 @@ 1 /home/matthias/esp/esp-idf/components/vfs/vfs_uart.c - - build/ide/esp_idf_components/vfs/vfs_usb_serial_jtag.c - 1 - /home/matthias/esp/esp-idf/components/vfs/vfs_usb_serial_jtag.c - build/ide/esp_idf_components/wear_levelling/Partition.cpp 1 diff --git a/code/main/CMakeLists.txt b/code/main/CMakeLists.txt index eeaffee..4970044 100644 --- a/code/main/CMakeLists.txt +++ b/code/main/CMakeLists.txt @@ -7,6 +7,7 @@ idf_component_register( "src/gpio.cpp" "src/wifi.cpp" "src/logger.cpp" + "src/led_strip_encoder.c" INCLUDE_DIRS # optional, add here public include directories "inc" PRIV_INCLUDE_DIRS # optional, add here private include directories diff --git a/code/main/inc/led_strip_encoder.h b/code/main/inc/led_strip_encoder.h new file mode 100644 index 0000000..db5ef07 --- /dev/null +++ b/code/main/inc/led_strip_encoder.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "driver/rmt_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of led strip encoder configuration + */ +typedef struct { + uint32_t resolution; /*!< Encoder resolution, in Hz */ +} led_strip_encoder_config_t; + +/** + * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols + * + * @param[in] config Encoder configuration + * @param[out] ret_encoder Returned encoder handle + * @return + * - ESP_ERR_INVALID_ARG for any invalid arguments + * - ESP_ERR_NO_MEM out of memory when creating led strip encoder + * - ESP_OK if creating encoder successfully + */ +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder); + +#ifdef __cplusplus +} +#endif diff --git a/code/main/inc/logger.h b/code/main/inc/logger.h index 5429571..8ce00e4 100644 --- a/code/main/inc/logger.h +++ b/code/main/inc/logger.h @@ -56,21 +56,28 @@ * \memberof Logger */ #define LOGGER_ERROR(...) \ - Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + +/** + * Logs a success + * \memberof Logger + */ +#define LOGGER_SUCCESS(...) \ + Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_SUCCESS, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_WARNING(...) \ - Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) + Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_INFO(...) \ - Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) + Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) /** * Logs an error @@ -84,42 +91,49 @@ * \memberof Logger */ #define LOGGER_PRINT(...) \ - Logger_log("", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) + Logger::Logger_log("", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_ERROR_ISR(...) \ - Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) + +/** + * Logs a success + * \memberof Logger + */ +#define LOGGER_SUCCESS_ISR(...) \ + Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_WARNING_ISR(...) \ - Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) + Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_INFO_ISR(...) \ - Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) + Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_DEBUG_ISR(a, ...) \ - Logger_logISR(a, __FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__) + Logger::Logger_logISR(a, __FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__) /** * Logs an error * \memberof Logger */ #define LOGGER_PRINT_ISR(a, ...) \ - Logger_logISR(a, "", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) + Logger::Logger_logISR(a, "", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__) // -------------------------------------------------------------------------------------------------------------------- // Type definitions. diff --git a/code/main/main.cpp b/code/main/main.cpp index 2deb336..f1d2911 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -5,15 +5,18 @@ #include "esp_log.h" #include "esp_sntp.h" #include "esp_wifi.h" +#include "time.h" #include "nvs_flash.h" #include "driver/gpio.h" -#include "inc/gpio.h" +#include "driver/rmt_tx.h" #include "driver/uart_select.h" -#include "inc/wifi.h" +#include "inc/gpio.h" +#include "inc/led_strip_encoder.h" #include "inc/logger.h" +#include "inc/wifi.h" static const uart_port_t uartPort = UART_NUM_0; static TaskHandle_t devTaskHandle = NULL; @@ -22,6 +25,8 @@ static GPIO gpio0(4, GPIO_DIRECTION_OUTPUT); static GPIO gpio1(18, GPIO_DIRECTION_OUTPUT); static time_t currentTime; +#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define RMT_LED_STRIP_GPIO_NUM 8 extern "C" void app_main(void) { @@ -52,17 +57,54 @@ extern "C" void app_main(void) ESP_ERROR_CHECK(uart_set_pin(uartPort, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install(uartPort, 1024, 1024, 0, NULL, 0)); - uart_write_bytes(uartPort, "helloWorld", sizeof("helloworld")); - + //-------------------------------------------- + // LOGGER + // Logger logger(10, uartPort); - logger.Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_DEBUG, "Hello World from the Logger himself"); LOGGER_DEBUG("YEAHAAA"); + + //-------------------------------------------- + // RMT Channel + // + LOGGER_INFO("Create RMT TX channel"); + rmt_channel_handle_t led_chan = NULL; + rmt_tx_channel_config_t tx_chan_config; + memset(&tx_chan_config, 0, sizeof(tx_chan_config)); + + tx_chan_config.clk_src = RMT_CLK_SRC_DEFAULT; // select source clock + tx_chan_config.gpio_num = RMT_LED_STRIP_GPIO_NUM; + tx_chan_config.mem_block_symbols = 64; // increase the block size can make the LED less flickering + tx_chan_config.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ; + tx_chan_config.trans_queue_depth = 4; + + ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan)); + + LOGGER_INFO("Install led strip encoder"); + rmt_encoder_handle_t led_encoder = NULL; + led_strip_encoder_config_t encoder_config; + memset(&encoder_config, 0, sizeof(encoder_config)); + encoder_config.resolution = RMT_LED_STRIP_RESOLUTION_HZ; + + ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder)); + + LOGGER_INFO("Enable RMT TX channel"); + ESP_ERROR_CHECK(rmt_enable(led_chan)); + + rmt_transmit_config_t tx_config; + memset(&tx_config, 0, sizeof(tx_config)); + tx_config.loop_count = 0; + + + + + + // Create the development task if(xTaskCreate(devTask, "DevTask", 2048, NULL, 3, &devTaskHandle) != pdPASS) { - printf("Task not created"); + LOGGER_ERROR("Task not created"); } Wifi wifi; @@ -75,6 +117,9 @@ extern "C" void app_main(void) sntp_setservername(0, "pool.ntp.org"); sntp_init(); + + uint8_t led_strip_pixels[111 * 3]; + int counter = 0; while (true) { @@ -82,9 +127,24 @@ extern "C" void app_main(void) time(¤tTime); localtime_r(¤tTime, &tm); - printf("%lld\n\r", currentTime); - printf("%i:%i:%i\n\r", tm.tm_hour, tm.tm_min, tm.tm_sec); - vTaskDelay(1000); + LOGGER_INFO("%lld\n\r", currentTime); + LOGGER_INFO("%i:%i:%i\n\r", tm.tm_hour, tm.tm_min, tm.tm_sec); + + memset(&led_strip_pixels, 0, sizeof(led_strip_pixels)); + led_strip_pixels[counter * 3 + 0] = 0x3F; + led_strip_pixels[counter * 3 + 1] = 0x3F; + led_strip_pixels[counter * 3 + 2] = 0x3F; + + if (counter < 111) + { + counter++; + } + else + { + counter = 0; + } + rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config); + vTaskDelay(5); } } @@ -100,6 +160,7 @@ static void devTask(void* parameters) (void)gpio0.SetOutput((GPIO_Value_t)(counter % 2)); (void)gpio1.SetOutput((GPIO_Value_t)(counter % 7)); counter++; + vTaskDelay(100); } } diff --git a/code/main/src/led_strip_encoder.c b/code/main/src/led_strip_encoder.c new file mode 100644 index 0000000..aff7fee --- /dev/null +++ b/code/main/src/led_strip_encoder.c @@ -0,0 +1,124 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "led_strip_encoder.h" + +static const char *TAG = "led_encoder"; + +typedef struct { + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; +} rmt_led_strip_encoder_t; + +static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = 0; + rmt_encode_state_t state = 0; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 0; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; +} + +static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; +} + +static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = 0; + return ESP_OK; +} + +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) +{ + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + // different led strip might have its own timing requirements, following parameter is for WS2812 + rmt_bytes_encoder_config_t bytes_encoder_config = { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); + rmt_copy_encoder_config_t copy_encoder_config = {}; + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); + + uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us + led_encoder->reset_code = (rmt_symbol_word_t) { + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + *ret_encoder = &led_encoder->base; + return ESP_OK; +err: + if (led_encoder) { + if (led_encoder->bytes_encoder) { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) { + rmt_del_encoder(led_encoder->copy_encoder); + } + free(led_encoder); + } + return ret; +} diff --git a/code/main/src/logger.cpp b/code/main/src/logger.cpp index 72626c9..0558193 100644 --- a/code/main/src/logger.cpp +++ b/code/main/src/logger.cpp @@ -219,6 +219,10 @@ void Logger::loggerTask(void* parameters) { vt100Prefix = "\033[31m"; } + else if(logQueueItem.logType == LOGTYPE_SUCCESS) + { + vt100Prefix = "\033[32m"; + } #endif unsigned int seconds = 0; @@ -229,6 +233,7 @@ void Logger::loggerTask(void* parameters) vt100Prefix, (logQueueItem.logType == LOGTYPE_DEBUG) ? "DBG" : (logQueueItem.logType == LOGTYPE_INFO) ? "INF" : + (logQueueItem.logType == LOGTYPE_SUCCESS) ? "SCS" : (logQueueItem.logType == LOGTYPE_WARNING) ? "WRN" : "ERR", seconds, logQueueItem.fileName, diff --git a/code/main/src/wifi.cpp b/code/main/src/wifi.cpp index cd4ccca..550a57f 100644 --- a/code/main/src/wifi.cpp +++ b/code/main/src/wifi.cpp @@ -22,6 +22,8 @@ #include "wifi.h" +#include "logger.h" + // -------------------------------------------------------------------------------------------------------------------- // Constant and macro definitions // -------------------------------------------------------------------------------------------------------------------- @@ -46,8 +48,10 @@ // -------------------------------------------------------------------------------------------------------------------- -static const char* ssid = "Kowalski"; -static const char* pass = "madagascar"; +//static const char* ssid = "Kowalski"; +//static const char* pass = "madagascar"; +static const char* ssid = "vbchaos"; +static const char* pass = "mijninternet"; // -------------------------------------------------------------------------------------------------------------------- // Function declarations @@ -82,18 +86,18 @@ void Wifi::event_handler(void *arg, esp_event_base_t event_base, int32_t event_i { esp_wifi_connect(); s_retry_num++; - ESP_LOGI(TAG, "retry to connect to the AP"); + LOGGER_INFO("%s - retry to connect to the AP", TAG); } else { xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } - ESP_LOGI(TAG, "connect to the AP fail"); + LOGGER_ERROR("%S - connect to the AP fail", TAG); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t *event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + LOGGER_SUCCESS("%s - got ip: %d:%d:%d:%d", TAG, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } @@ -130,7 +134,7 @@ void Wifi::start_client(void) ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "wifi_init_sta finished."); + LOGGER_INFO("%s - wifi_init_sta finished", TAG); /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ @@ -144,15 +148,15 @@ void Wifi::start_client(void) * happened. */ if (bits & WIFI_CONNECTED_BIT) { - ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", ssid, pass); + LOGGER_SUCCESS("%s - connected to ap SSID:%s password:%s", TAG, ssid, pass); } else if (bits & WIFI_FAIL_BIT) { - ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", ssid, pass); + LOGGER_ERROR("%s - Failed to connect to SSID:%s, password:%s", TAG, ssid, pass); } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); + LOGGER_ERROR("%s - UNEXPECTED EVENT", TAG); } }