Added LED encoder - functional

This commit is contained in:
Matthias Mitscherlich
2023-01-17 12:45:32 +01:00
parent 0dfa8fad2b
commit 58b63fb7a2
8 changed files with 272 additions and 32 deletions
+1
View File
@@ -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
+36
View File
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#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
+23 -9
View File
@@ -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.
+70 -9
View File
@@ -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(&currentTime);
localtime_r(&currentTime, &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);
}
}
+124
View File
@@ -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(&copy_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;
}
+5
View File
@@ -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,
+13 -9
View File
@@ -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);
}
}