From e3d7077f9b2e62596475c47acf16f1aefbe3a1a3 Mon Sep 17 00:00:00 2001 From: jweigele Date: Sun, 14 Jan 2024 18:52:44 -0800 Subject: [PATCH] Very simple PWM control over OT for esp32 device * Works for first set of RGB LEDs (control over mosfet) * Configurable for GPIO but second set not active yet * Needs conditional logic for which GPIO is enabled + some gamma correction probably --- aqi/main/aqi.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/aqi/main/aqi.c b/aqi/main/aqi.c index 076ba56..2763596 100644 --- a/aqi/main/aqi.c +++ b/aqi/main/aqi.c @@ -28,6 +28,26 @@ typedef struct aqi_data_s { } aqi_data_t; +#ifdef CONFIG_PWM_ENABLED +#include "driver/ledc.h" +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_LOW_SPEED_MODE +#define R1_CHANNEL LEDC_CHANNEL_0 +#define R2_CHANNEL LEDC_CHANNEL_1 +#define G1_CHANNEL LEDC_CHANNEL_2 +#define G2_CHANNEL LEDC_CHANNEL_3 +#define B1_CHANNEL LEDC_CHANNEL_4 +#define B2_CHANNEL LEDC_CHANNEL_5 +#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits +#define LEDC_DUTY (4096) // Set duty to 50%. (2 ** 13) * 50% = 4096 +#define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz + +typedef struct pwm_data_s { + uint8_t msg[1024]; + int len; +} pwm_data_t; +#endif + typedef struct report_data_s { #ifdef CONFIG_UART_ENABLED uint16_t pm10; @@ -55,6 +75,10 @@ static int motion_pins[2] = {0, 0}; #endif +#ifdef CONFIG_PWM_ENABLED +static QueueHandle_t pwm_queue; +#endif + // for tracking and reporting device uptime static uint32_t device_uptime_seconds = 0; @@ -676,6 +700,122 @@ aqi_data_t get_average_pm25(uint8_t* data, int data_size){ } +#ifdef CONFIG_PWM_ENABLED +static void pwm_task(void* discard){ + + + // initialize PWM hardware + // Prepare and then apply the LEDC PWM timer configuration + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_MODE, + .timer_num = LEDC_TIMER, + .duty_resolution = LEDC_DUTY_RES, + .freq_hz = LEDC_FREQUENCY, // Set output frequency at 5 kHz + .clk_cfg = LEDC_AUTO_CLK + }; + ESP_LOGI(TAG, "configuring ledc timer"); + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + // Prepare and then apply the LEDC PWM channel configuration + ledc_channel_config_t ledc_channel = { + .speed_mode = LEDC_MODE, + .channel = R1_CHANNEL, + .timer_sel = LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = CONFIG_PWM_R1_GPIO, + .duty = 0, // Set duty to 0% + .hpoint = 0 + }; + ESP_LOGI(TAG, "configuring R1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + + + ledc_channel.channel = G1_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_G1_GPIO; + + ESP_LOGI(TAG, "configuring G1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + + ledc_channel.channel = B1_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_B1_GPIO; + + ESP_LOGI(TAG, "configuring B1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + + + + + + + //create a queue to handle gpio event from isr + // 1kb, should be enough for parsing? + pwm_queue = xQueueCreate(10, sizeof(pwm_data_t)); + pwm_data_t recv; + ESP_LOGI(TAG, "waiting for pwm events"); + cJSON* current_pwm; + cJSON* red_json; + cJSON* green_json; + cJSON* blue_json; + for(;;) { + if(xQueueReceive(pwm_queue, &recv, portMAX_DELAY)) { + ESP_LOGI(TAG, "received PWM data string %s len %d", recv.msg, recv.len); + current_pwm = cJSON_ParseWithLength(&recv.msg, recv.len); + if (cJSON_IsObject(current_pwm)){ + ESP_LOGI(TAG, "parsed successfully I think"); + char *json_string = cJSON_Print(current_pwm); + ESP_LOGI(TAG, "full json string decoded as %s", json_string); + red_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "red"); + if (cJSON_IsNumber(red_json)){ + ESP_LOGI(TAG, "parsed red float %f", red_json->valuedouble); + float red_duty_float = (float)(pow(2,13)) * red_json->valuedouble; + int red_duty_int = (int)red_duty_float; + + ESP_LOGI(TAG, "red duty int calculated as %d", red_duty_int); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, R1_CHANNEL, red_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, R1_CHANNEL)); + + } + + green_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "green"); + if (cJSON_IsNumber(green_json)){ + ESP_LOGI(TAG, "parsed green float %f", green_json->valuedouble); + float green_duty_float = (float)(pow(2,13)) * green_json->valuedouble; + int green_duty_int = (int)green_duty_float; + + ESP_LOGI(TAG, "green duty int calculated as %d", green_duty_int); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, G1_CHANNEL, green_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, G1_CHANNEL)); + + } + + + blue_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "blue"); + if (cJSON_IsNumber(blue_json)){ + ESP_LOGI(TAG, "parsed blue float %f", blue_json->valuedouble); + float blue_duty_float = (float)(pow(2,13)) * blue_json->valuedouble; + int blue_duty_int = (int)blue_duty_float; + + ESP_LOGI(TAG, "blue duty int calculated as %d", blue_duty_int); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, B1_CHANNEL, blue_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, B1_CHANNEL)); + + } + + } else { + ESP_LOGE(TAG, "failed to parse json successfully!"); + } + cJSON_Delete(current_pwm); + + } + } + + +} +#endif + #if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED) static void IRAM_ATTR gpio_isr_handler(void* arg) { @@ -962,6 +1102,15 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ mqtt_connected = true; mqtt_was_reinit = false; ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); +// need to subscribe to MQTT topic for updates +#ifdef CONFIG_PWM_ENABLED + int subret = esp_mqtt_client_subscribe(mqtt_client, CONFIG_PWM_TOPIC, 0); + if (subret == -1 ){ + ESP_LOGE(TAG, "error subscribing to %s", CONFIG_PWM_TOPIC); + } else { + ESP_LOGI(TAG, "subscribed to %s for PWM updates", CONFIG_PWM_TOPIC); + } +#endif break; case MQTT_EVENT_DISCONNECTED: if ( event->client != mqtt_client ){ @@ -985,6 +1134,15 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ ESP_LOGI(TAG, "MQTT_EVENT_DATA"); printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); printf("DATA=%.*s\r\n", event->data_len, event->data); + pwm_data_t sendpwm; + pwm_data_t* sendpwm_ptr = &sendpwm; //malloc(sizeof(pwm_data_t)); + memset(sendpwm_ptr, 0, 1024); + memcpy(sendpwm_ptr->msg, event->data, event->data_len); + sendpwm_ptr->len = event->data_len; + printf("sendpwm msg: %s\nlen: %d\n", sendpwm_ptr->msg, sendpwm_ptr->len); + + xQueueSend(pwm_queue, sendpwm_ptr, portMAX_DELAY); + break; case MQTT_EVENT_ERROR: if ( mqtt_client != NULL && event->client != mqtt_client ){ @@ -1129,6 +1287,10 @@ void app_main(void) //runit(); #endif +#ifdef CONFIG_PWM_ENABLED + ESP_LOGI(TAG, "installing pwm task"); + xTaskCreate(pwm_task, "pwm_task", 4096, NULL, 2, NULL); +#endif #ifdef CONFIG_OT_ENABLED esp_vfs_eventfd_config_t eventfd_config = { .max_fds = 3, -- 2.30.2