| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 | 
							- /*
 
-    This example code is in the Public Domain (or CC0 licensed, at your option.)
 
-    Unless required by applicable law or agreed to in writing, this
 
-    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 
-    CONDITIONS OF ANY KIND, either express or implied.
 
- */
 
- #include <stdio.h>
 
- #include <stdlib.h>
 
- #include <unistd.h>
 
- #include <string.h>
 
- #include <math.h>
 
- #include "freertos/FreeRTOS.h"
 
- #include "freertos/task.h"
 
- #include "freertos/timers.h"
 
- #include "esp_system.h"
 
- #include "esp_log.h"
 
- #include "driver/gpio.h"
 
- #include "driver/ledc.h"
 
- #include "driver/rmt.h"
 
- #include "platform_config.h"
 
- #include "gpio_exp.h"
 
- #include "led.h"
 
- #include "globdefs.h"
 
- #include "accessors.h"
 
- #include "services.h"
 
- #define MAX_LED	8
 
- #define BLOCKTIME	10	// up to portMAX_DELAY
 
- #ifdef CONFIG_IDF_TARGET_ESP32S3
 
- #define LEDC_SPEED_MODE LEDC_LOW_SPEED_MODE
 
- #else
 
- #define LEDC_SPEED_MODE LEDC_HIGH_SPEED_MODE
 
- #endif
 
- static const char *TAG = "led";
 
- #define RMT_CLK (40/2)
 
- static int8_t led_rmt_channel = -1;
 
- static uint32_t scale24(uint32_t bright, uint8_t);
 
- static const struct rmt_led_param_s {
 
-     led_type_t type;
 
-     uint8_t bits;
 
-     // number of ticks in nanoseconds converted in RMT_CLK ticks
 
-     rmt_item32_t bit_0;
 
-     rmt_item32_t bit_1;
 
-     uint32_t green, red;
 
-     uint32_t (*scale)(uint32_t, uint8_t);
 
- } rmt_led_param[] =  {
 
-     { LED_WS2812, 24, {{{350 / RMT_CLK, 1, 1000 / RMT_CLK, 0}}}, {{{1000 / RMT_CLK, 1, 350 / RMT_CLK, 0}}}, 0xff0000, 0x00ff00, scale24 },
 
-     { .type = -1 } };
 
- static EXT_RAM_ATTR struct led_s {
 
- 	gpio_num_t gpio;
 
- 	bool on;
 
- 	uint32_t color;
 
- 	int ontime, offtime;
 
- 	int bright;
 
- 	int channel;
 
-     const struct rmt_led_param_s *rmt;
 
- 	int pushedon, pushedoff;
 
- 	bool pushed;
 
- 	TimerHandle_t timer;
 
- } leds[MAX_LED];
 
- // can't use EXT_RAM_ATTR for initialized structure
 
- static struct led_config_s {
 
- 	int gpio;
 
- 	int color;
 
- 	int bright;
 
-     led_type_t type;
 
- } green = { .gpio = CONFIG_LED_GREEN_GPIO, .color = 0, .bright = -1, .type = LED_GPIO },
 
-   red = { .gpio = CONFIG_LED_RED_GPIO, .color = 0, .bright = -1, .type = LED_GPIO };
 
- static int led_max = 2;
 
- /****************************************************************************************
 
-  *
 
-  */
 
- static uint32_t scale24(uint32_t color, uint8_t scale) {
 
-     uint32_t scaled = (((color & 0xff0000) >> 16) * scale / 100) << 16;
 
-     scaled |= (((color & 0xff00) >> 8) * scale / 100) << 8;
 
-     scaled |= (color & 0xff) * scale / 100;
 
-     return scaled;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- static void set_level(struct led_s *led, bool on) {
 
-     if (led->rmt) {
 
-         uint32_t data = on ? led->rmt->scale(led->color, led->bright) : 0;
 
-         uint32_t mask = 1 << (led->rmt->bits - 1);
 
-         rmt_item32_t buffer[led->rmt->bits];
 
-         for (uint32_t bit = 0; bit < led->rmt->bits; bit++) {
 
-             uint32_t set = data & mask;
 
-             buffer[bit] = set ? led->rmt->bit_1 : led->rmt->bit_0;
 
-             mask >>= 1;
 
-         }
 
-         rmt_write_items(led->channel, buffer, led->rmt->bits, false);
 
-     } else if (led->bright < 0 || led->gpio >= GPIO_NUM_MAX) {
 
-         gpio_set_level_x(led->gpio, on ? led->color : !led->color);
 
- 	} else {
 
- 		ledc_set_duty(LEDC_SPEED_MODE, led->channel, on ? led->bright : (led->color ? 0 : pwm_system.max));
 
- 		ledc_update_duty(LEDC_SPEED_MODE, led->channel);
 
- 	}
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- static void vCallbackFunction( TimerHandle_t xTimer ) {
 
- 	struct led_s *led = (struct led_s*) pvTimerGetTimerID (xTimer);
 
- 	if (!led->timer) return;
 
- 	led->on = !led->on;
 
- 	ESP_EARLY_LOGD(TAG,"led vCallbackFunction setting gpio %d level %d (bright:%d)", led->gpio, led->on, led->bright);
 
- 	set_level(led, led->on);
 
- 	// was just on for a while
 
- 	if (!led->on && led->offtime == -1) return;
 
- 	// regular blinking
 
- 	xTimerChangePeriod(xTimer, (led->on ? led->ontime : led->offtime) / portTICK_RATE_MS, BLOCKTIME);
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- bool led_blink_core(int idx, int ontime, int offtime, bool pushed) {
 
- 	if (!leds[idx].gpio || leds[idx].gpio < 0 ) return false;
 
- 	ESP_LOGD(TAG,"led_blink_core %d on:%d off:%d, pushed:%u", idx, ontime, offtime, pushed);
 
- 	if (leds[idx].timer) {
 
- 		// normal requests waits if a pop is pending
 
- 		if (!pushed && leds[idx].pushed) {
 
- 			leds[idx].pushedon = ontime;
 
- 			leds[idx].pushedoff = offtime;
 
- 			return true;
 
- 		}
 
- 		xTimerStop(leds[idx].timer, BLOCKTIME);
 
- 	}
 
- 	// save current state if not already pushed
 
- 	if (!leds[idx].pushed) {
 
- 		leds[idx].pushedon = leds[idx].ontime;
 
- 		leds[idx].pushedoff = leds[idx].offtime;
 
- 		leds[idx].pushed = pushed;
 
- 	}
 
- 	// then set new one
 
- 	leds[idx].ontime = ontime;
 
- 	leds[idx].offtime = offtime;
 
- 	if (ontime == 0) {
 
- 		ESP_LOGD(TAG,"led %d, setting reverse level", idx);
 
- 		set_level(leds + idx, false);
 
- 	} else if (offtime == 0) {
 
- 		ESP_LOGD(TAG,"led %d, setting level", idx);
 
- 		set_level(leds + idx, true);
 
- 	} else {
 
- 		if (!leds[idx].timer) {
 
- 			ESP_LOGD(TAG,"led %d, Creating timer", idx);
 
- 			leds[idx].timer = xTimerCreate("ledTimer", ontime / portTICK_RATE_MS, pdFALSE, (void *)&leds[idx], vCallbackFunction);
 
- 		}
 
-         leds[idx].on = true;
 
- 		set_level(leds + idx, true);
 
-         ESP_LOGD(TAG,"led %d, Setting gpio %d and starting timer", idx, leds[idx].gpio);
 
- 		if (xTimerStart(leds[idx].timer, BLOCKTIME) == pdFAIL) return false;
 
- 	}
 
- 	return true;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- bool led_brightness(int idx, int bright) {
 
- 	if (bright > 100) bright = 100;
 
-     if (leds[idx].rmt) {
 
-         leds[idx].bright = bright;
 
-     } else {
 
-         leds[idx].bright = pwm_system.max * powf(bright / 100.0, 3);
 
-         if (!leds[idx].color) leds[idx].bright = pwm_system.max - leds[idx].bright;
 
-         ledc_set_duty(LEDC_SPEED_MODE, leds[idx].channel, leds[idx].bright);
 
-         ledc_update_duty(LEDC_SPEED_MODE, leds[idx].channel);
 
-     }
 
- 	return true;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- bool led_unpush(int idx) {
 
- 	if (!leds[idx].gpio || leds[idx].gpio<0) return false;
 
- 	led_blink_core(idx, leds[idx].pushedon, leds[idx].pushedoff, true);
 
- 	leds[idx].pushed = false;
 
- 	return true;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- int led_allocate(void) {
 
- 	 if (led_max < MAX_LED) return led_max++;
 
- 	 return -1;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- bool led_config(int idx, gpio_num_t gpio, int color, int bright, led_type_t type) {
 
- 	if (gpio < 0) {
 
- 		ESP_LOGW(TAG,"LED GPIO -1 ignored");
 
- 		return false;
 
- 	}
 
- 	if (idx >= MAX_LED) return false;
 
-     if (bright > 100) bright = 100;
 
- 	leds[idx].gpio = gpio;
 
- 	leds[idx].color = color;
 
-     leds[idx].rmt = NULL;
 
-     leds[idx].bright = -1;
 
-     if (type != LED_GPIO) {
 
-         // first make sure we have a known addressable led
 
-         for (const struct rmt_led_param_s *p = rmt_led_param; !leds[idx].rmt && p->type >= 0; p++) if (p->type == type) leds[idx].rmt = p;
 
-         if (!leds[idx].rmt) return false;
 
-         if (led_rmt_channel < 0) led_rmt_channel = RMT_NEXT_TX_CHANNEL();
 
-         leds[idx].channel = led_rmt_channel;
 
- 		leds[idx].bright = bright > 0 ? bright : 100;
 
-         // set counter clock to 40MHz
 
-         rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, leds[idx].channel);
 
-         config.clk_div = 2;
 
-         rmt_config(&config);
 
-         rmt_driver_install(config.channel, 0, 0);
 
- 	} else if (bright < 0 || gpio >= GPIO_NUM_MAX) {
 
- 		gpio_pad_select_gpio_x(gpio);
 
- 		gpio_set_direction_x(gpio, GPIO_MODE_OUTPUT);
 
-     } else {
 
- 		leds[idx].channel = pwm_system.base_channel++;
 
- 		leds[idx].bright = pwm_system.max * powf(bright / 100.0, 3);
 
- 		if (!color) leds[idx].bright = pwm_system.max - leds[idx].bright;
 
- 		ledc_channel_config_t ledc_channel = {
 
-             .channel    = leds[idx].channel,
 
-             .duty       = leds[idx].bright,
 
-             .gpio_num   = gpio,
 
-             .speed_mode = LEDC_SPEED_MODE,
 
-             .hpoint     = 0,
 
-             .timer_sel  = pwm_system.timer,
 
-         };
 
- 		ledc_channel_config(&ledc_channel);
 
- 	}
 
- 	set_level(leds + idx, false);
 
- 	ESP_LOGD(TAG,"Index %d, GPIO %d, color/onstate %d / RMT %d, bright %d%%", idx, gpio, color, type, bright);
 
- 	return true;
 
- }
 
- /****************************************************************************************
 
-  *
 
-  */
 
- static void led_suspend(void) {
 
-     led_off(LED_GREEN);
 
-     led_off(LED_RED);
 
- }     
 
- /****************************************************************************************
 
-  *
 
-  */
 
- void set_led_gpio(int gpio, char *value) {
 
-     struct led_config_s *config;
 
- 	if (strcasestr(value, "green")) config = &green;
 
-     else if (strcasestr(value, "red"))config = &red;
 
-     else return;
 
-     config->gpio = gpio;
 
-     char *p = value;
 
-     while ((p = strchr(p, ':')) != NULL) {
 
-         p++;
 
-         if ((strcasestr(p, "ws2812")) != NULL) config->type = LED_WS2812;
 
-         else config->color = atoi(p);
 
-     }
 
-     if (config->type != LED_GPIO) {
 
-         for (const struct rmt_led_param_s *p = rmt_led_param; p->type >= 0; p++) {
 
-             if (p->type == config->type) {
 
-                 if (config == &green) config->color = p->green;
 
-                 else config->color = p->red;
 
-                 break;
 
-             }
 
-         }
 
-     }
 
- }
 
- void led_svc_init(void) {
 
- #ifdef CONFIG_LED_GREEN_GPIO_LEVEL
 
- 	green.color = CONFIG_LED_GREEN_GPIO_LEVEL;
 
- #endif
 
- #ifdef CONFIG_LED_RED_GPIO_LEVEL
 
- 	red.color = CONFIG_LED_RED_GPIO_LEVEL;
 
- #endif
 
- #ifndef CONFIG_LED_LOCKED
 
- 	parse_set_GPIO(set_led_gpio);
 
- #endif
 
- 	char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness");
 
- 	if (nvs_item) {
 
- 		PARSE_PARAM(nvs_item, "green", '=', green.bright);
 
- 		PARSE_PARAM(nvs_item, "red", '=', red.bright);
 
- 		free(nvs_item);
 
- 	}
 
- 	led_config(LED_GREEN, green.gpio, green.color, green.bright, green.type);
 
- 	led_config(LED_RED, red.gpio, red.color, red.bright, red.type);
 
-     
 
-     // make sure we switch off all leds (useful for gpio expanders)
 
-     services_sleep_setsuspend(led_suspend);
 
- 	ESP_LOGI(TAG,"Configuring LEDs green:%d (on:%d rmt:%d %d%% ), red:%d (on:%d rmt:%d %d%% )",
 
-                  green.gpio, green.color, green.type, green.bright,
 
-                  red.gpio, red.color, red.type, red.bright);
 
- }
 
 
  |