123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /*
- 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 "led.h"
- #include "globdefs.h"
- #include "accessors.h"
- #include "config.h"
- #define MAX_LED 8
- #define BLOCKTIME 10 // up to portMAX_DELAY
- static const char *TAG = "led";
- static struct led_s {
- gpio_num_t gpio;
- bool on;
- int onstate;
- int ontime, offtime;
- int pwm;
- int channel;
- int pushedon, pushedoff;
- bool pushed;
- TimerHandle_t timer;
- } leds[MAX_LED];
- static struct {
- int gpio;
- int active;
- int pwm;
- } green = { .gpio = CONFIG_LED_GREEN_GPIO, .active = 0, .pwm = -1 },
- red = { .gpio = CONFIG_LED_RED_GPIO, .active = 0, .pwm = -1 };
-
- static int led_max = 2;
- /****************************************************************************************
- *
- */
- static void set_level(struct led_s *led, bool on) {
- if (led->pwm < 0) gpio_set_level(led->gpio, on ? led->onstate : !led->onstate);
- else {
- ledc_set_duty(LEDC_HIGH_SPEED_MODE, led->channel, on ? led->pwm : (led->onstate ? 0 : pwm_system.max));
- ledc_update_duty(LEDC_HIGH_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 (pwm:%d)", led->gpio, led->on, led->pwm);
- 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");
- 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 pwm) {
- if (pwm > 100) pwm = 100;
- leds[idx].pwm = pwm_system.max * powf(pwm / 100.0, 3);
- if (!leds[idx].onstate) leds[idx].pwm = pwm_system.max - leds[idx].pwm;
-
- ledc_set_duty(LEDC_HIGH_SPEED_MODE, leds[idx].channel, leds[idx].pwm);
- ledc_update_duty(LEDC_HIGH_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 onstate, int pwm) {
- if (gpio < 0) {
- ESP_LOGW(TAG,"LED GPIO -1 ignored");
- return false;
- }
-
- ESP_LOGD(TAG,"Index %d, GPIO %d, on state %s", idx, gpio, onstate>0?"On":"Off");
- if (idx >= MAX_LED) return false;
-
- leds[idx].gpio = gpio;
- leds[idx].onstate = onstate;
- leds[idx].pwm = -1;
- if (pwm < 0) {
- gpio_pad_select_gpio(gpio);
- gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
- } else {
- leds[idx].channel = pwm_system.base_channel++;
- leds[idx].pwm = pwm_system.max * powf(pwm / 100.0, 3);
- if (!onstate) leds[idx].pwm = pwm_system.max - leds[idx].pwm;
-
- ledc_channel_config_t ledc_channel = {
- .channel = leds[idx].channel,
- .duty = leds[idx].pwm,
- .gpio_num = gpio,
- .speed_mode = LEDC_HIGH_SPEED_MODE,
- .hpoint = 0,
- .timer_sel = pwm_system.timer,
- };
-
- ledc_channel_config(&ledc_channel);
- }
-
- set_level(leds + idx, false);
- ESP_LOGD(TAG,"PWM Index %d, GPIO %d, on state %s, pwm %d%%", idx, gpio, onstate > 0 ? "On" : "Off", pwm);
- return true;
- }
- /****************************************************************************************
- *
- */
- void set_led_gpio(int gpio, char *value) {
- char *p;
-
- if (strcasestr(value, "green")) {
- green.gpio = gpio;
- if ((p = strchr(value, ':')) != NULL) green.active = atoi(p + 1);
- } else if (strcasestr(value, "red")) {
- red.gpio = gpio;
- if ((p = strchr(value, ':')) != NULL) red.active = atoi(p + 1);
- }
- }
- void led_svc_init(void) {
- #ifdef CONFIG_LED_GREEN_GPIO_LEVEL
- green.active = CONFIG_LED_GREEN_GPIO_LEVEL;
- #endif
- #ifdef CONFIG_LED_RED_GPIO_LEVEL
- red.active = CONFIG_LED_RED_GPIO_LEVEL;
- #endif
- #ifndef CONFIG_LED_LOCKED
- parse_set_GPIO(set_led_gpio);
- #endif
- ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, green.gpio, green.active, green.pwm );
-
- char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"), *p;
- if (nvs_item) {
- if ((p = strcasestr(nvs_item, "green")) != NULL) green.pwm = atoi(strchr(p, '=') + 1);
- if ((p = strcasestr(nvs_item, "red")) != NULL) red.pwm = atoi(strchr(p, '=') + 1);
- free(nvs_item);
- }
- led_config(LED_GREEN, green.gpio, green.active, green.pwm);
- led_config(LED_RED, red.gpio, red.active, red.pwm);
- }
|