Files
snapclient/components/esp_peripherals/periph_led.c
Carlos 30d2e54dab - completely drop ADF but copy necessary parts
o copy component audio_board from ADF and create custom component from it
  o copy component audio_hal from ADF and create custom component from it
  o copy component audio_sal from ADF and create custom component from it
  o copy component esp_peripherals from ADF and create custom component from it
- add fLaC support through xiph's original repository as a git module
2021-09-05 20:20:36 +02:00

299 lines
9.0 KiB
C

/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_led.h"
#include "audio_mem.h"
#include "audio_mutex.h"
#include "audio_sys.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include <math.h>
#include <string.h>
#define MAX_LED_CHANNEL (8)
static const char *TAG = "PERIPH_LED";
#define VALIDATE_LED(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_LED)) \
{ \
ESP_LOGE (TAG, "Invalid LED periph, at line %d", __LINE__); \
return ret; \
}
typedef struct
{
int index;
int pin;
int high_level_ms;
int low_level_ms;
long long tick;
int loop;
bool is_high_level;
bool fade;
bool stop;
int level;
} periph_led_channel_t;
typedef struct periph_led
{
ledc_mode_t led_speed_mode;
ledc_timer_bit_t led_duty_resolution;
ledc_timer_t led_timer_num;
uint32_t led_freq_hz;
QueueHandle_t led_mutex;
periph_led_channel_t channels[MAX_LED_CHANNEL];
} periph_led_t;
static esp_err_t
_led_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
return ESP_OK;
}
static esp_err_t
_led_init (esp_periph_handle_t self)
{
VALIDATE_LED (self, ESP_FAIL);
periph_led_t *periph_led = esp_periph_get_data (self);
ledc_timer_config_t ledc_timer = {
.duty_resolution
= periph_led->led_duty_resolution, // resolution of PWM duty
.freq_hz = periph_led->led_freq_hz, // frequency of PWM signal
.speed_mode = periph_led->led_speed_mode, // timer mode
.timer_num = periph_led->led_timer_num // timer index
};
// Set configuration of timer0 for high speed channels
ledc_timer_config (&ledc_timer);
ledc_fade_func_install (0);
return ESP_OK;
}
static esp_err_t
_led_destroy (esp_periph_handle_t self)
{
periph_led_t *periph_led = esp_periph_get_data (self);
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
periph_led_channel_t *ch = &periph_led->channels[i];
if (ch->index > 0 && ch->pin > 0)
{
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
}
}
esp_periph_stop_timer (self);
ledc_fade_func_uninstall ();
mutex_destroy (periph_led->led_mutex);
audio_free (periph_led);
return ESP_OK;
}
esp_periph_handle_t
periph_led_init (periph_led_cfg_t *config)
{
esp_periph_handle_t periph = esp_periph_create (PERIPH_ID_LED, "periph_led");
// check periph
periph_led_t *periph_led = audio_calloc (1, sizeof (periph_led_t));
// check periph_led
periph_led->led_speed_mode = config->led_speed_mode;
periph_led->led_duty_resolution = config->led_duty_resolution;
periph_led->led_timer_num = config->led_timer_num;
periph_led->led_freq_hz = config->led_freq_hz;
periph_led->led_mutex = mutex_create ();
if (periph_led->led_freq_hz == 0)
{
periph_led->led_freq_hz = 5000;
}
memset (&periph_led->channels, -1, sizeof (periph_led->channels));
esp_periph_set_data (periph, periph_led);
esp_periph_set_function (periph, _led_init, _led_run, _led_destroy);
return periph;
}
static periph_led_channel_t *
_find_led_channel (periph_led_t *periph_led, int gpio_num)
{
periph_led_channel_t *ch = NULL;
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
if (periph_led->channels[i].pin == gpio_num)
{
ch = &periph_led->channels[i];
ch->index = i;
break;
}
else if (periph_led->channels[i].pin == -1)
{
ch = &periph_led->channels[i];
ch->index = i;
}
}
return ch;
}
static void
led_timer_handler (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
periph_led_t *periph_led = esp_periph_get_data (periph);
mutex_lock (periph_led->led_mutex);
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
periph_led_channel_t *ch = &periph_led->channels[i];
if (ch->pin < 0 || ch->stop == true)
{
continue;
}
if (ch->loop == 0)
{
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
esp_periph_send_event (periph, PERIPH_LED_BLINK_FINISH,
(void *)ch->pin, 0);
ch->stop = true;
continue;
}
if (!ch->is_high_level
&& audio_sys_get_time_ms () - ch->tick > ch->low_level_ms)
{
if (ch->loop > 0)
{
ch->loop--;
}
// now, switch on
if (ch->fade)
{
ledc_set_fade_with_time (periph_led->led_speed_mode, ch->index,
pow (2, periph_led->led_duty_resolution)
- 1,
ch->high_level_ms);
ledc_fade_start (periph_led->led_speed_mode, ch->index,
LEDC_FADE_NO_WAIT);
}
else
{
ledc_set_duty (periph_led->led_speed_mode, ch->index,
pow (2, periph_led->led_duty_resolution) - 1);
ledc_update_duty (periph_led->led_speed_mode, ch->index);
}
if (ch->low_level_ms > 0)
{
ch->is_high_level = true;
}
ch->tick = audio_sys_get_time_ms ();
}
else if (ch->is_high_level
&& audio_sys_get_time_ms () - ch->tick > ch->high_level_ms)
{
if (ch->loop > 0)
{
ch->loop--;
}
// switch off
if (ch->fade)
{
ledc_set_fade_with_time (periph_led->led_speed_mode, ch->index,
0, ch->low_level_ms);
ledc_fade_start (periph_led->led_speed_mode, ch->index,
LEDC_FADE_NO_WAIT);
}
else
{
ledc_set_duty (periph_led->led_speed_mode, ch->index, 0);
ledc_update_duty (periph_led->led_speed_mode, ch->index);
}
if (ch->high_level_ms > 0)
{
ch->is_high_level = false;
}
ch->tick = audio_sys_get_time_ms ();
}
}
mutex_unlock (periph_led->led_mutex);
}
esp_err_t
periph_led_blink (esp_periph_handle_t periph, int gpio_num, int time_on_ms,
int time_off_ms, bool fade, int loop,
periph_led_idle_level_t level)
{
periph_led_t *periph_led = esp_periph_get_data (periph);
periph_led_channel_t *ch = _find_led_channel (periph_led, gpio_num);
if (ch == NULL)
{
return ESP_FAIL;
}
ledc_channel_config_t ledc_channel_cfg = {
.channel = ch->index,
.duty = 0,
.gpio_num = gpio_num,
.speed_mode = periph_led->led_speed_mode,
.timer_sel = periph_led->led_timer_num,
};
ledc_channel_config (&ledc_channel_cfg);
ch->pin = gpio_num;
ch->tick = audio_sys_get_time_ms ();
ch->loop = loop;
ch->fade = fade;
if (level == PERIPH_LED_IDLE_LEVEL_LOW)
{
ch->is_high_level = false;
ch->high_level_ms = time_on_ms;
ch->low_level_ms = time_off_ms;
}
else
{
ch->is_high_level = true;
ch->high_level_ms = time_off_ms;
ch->low_level_ms = time_on_ms;
}
ch->stop = false;
ch->level = level;
esp_periph_start_timer (periph, portTICK_RATE_MS, led_timer_handler);
return ESP_OK;
}
esp_err_t
periph_led_stop (esp_periph_handle_t periph, int gpio_num)
{
periph_led_t *periph_led = esp_periph_get_data (periph);
periph_led_channel_t *ch = _find_led_channel (periph_led, gpio_num);
if (ch && (ch->pin < 0 || ch->index < 0))
{
return ESP_OK;
}
mutex_lock (periph_led->led_mutex);
ch->stop = true;
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
mutex_unlock (periph_led->led_mutex);
return ESP_OK;
}