Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-esp32 into fix_led_vu

This commit is contained in:
Wizmo2
2023-09-15 20:28:18 -04:00
9 changed files with 222 additions and 32 deletions

View File

@@ -389,12 +389,13 @@ Where (all parameters are optionals except gpio)
Where `<action>` is either the name of another configuration to load (remap) or one amongst Where `<action>` is either the name of another configuration to load (remap) or one amongst
``` ```
ACTRLS_NONE, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_NONE, ACTRLS_SLEEP, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
BCTRLS_PS1, BCTRLS_PS2, BCTRLS_PS3, BCTRLS_PS4, BCTRLS_PS5, BCTRLS_PS6, BCTRLS_PS7, BCTRLS_PS8, BCTRLS_PS9, BCTRLS_PS10, BCTRLS_PS1, BCTRLS_PS2, BCTRLS_PS3, BCTRLS_PS4, BCTRLS_PS5, BCTRLS_PS6, BCTRLS_PS7, BCTRLS_PS8, BCTRLS_PS9, BCTRLS_PS10,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH, KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
``` ```
Note that ACTRLS_SLEEP is not an actual button that can be sent to LMS, but it's a hook to activate deep sleep mode (see [Sleeping](#sleeping)).
One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config
@@ -504,6 +505,29 @@ channel=0..7,scale=<scale>,cells=<1..3>[,atten=<0|1|2|3>]
``` ```
NB: Set parameter to empty to disable battery reading. For named configurations (SqueezeAMP, Muse ...), this is ignored (except for SqueezeAMP where number of cells is required) NB: Set parameter to empty to disable battery reading. For named configurations (SqueezeAMP, Muse ...), this is ignored (except for SqueezeAMP where number of cells is required)
### Sleeping
The esp32 can be put in deep sleep mode to save some power. How much really depends on the connected periperals, so best is to do your own measures. Waking-up from deep sleep is the equivalent of a reboot, but as the chip takes a few seconds to connect, it's still an efficient process.
The esp32 can enter deep sleep after an audio inactivity timeout, after a button has been pressed or after a GPIO is set to a given level. It wakes up only on GPIO events
The NVS parameter `sleep_config` is mostly used for setting sleep conditions
```
[delay=<mins>][,sleep=<gpio>[:0|1]][,wake=<gpio>[:0|1][|<gpio>[:0|1]...]
```
- delay is in **minutes**
- sleep is the GPIO that will put the system into sleep and it can be a level 0 or 1
- wake is a **list** of GPIOs that with cause it to wake up (reboot) with their respective values. In such list, GPIO's are separated by an actual '|'
Be mindful that if the same GPIO is used to go to sleep and wakeup with the *same* level, in other word it's a transition/edge that triggers the action, the above will not work and the esp32 will immediately restart. In such case, you case use a button definition. The benefit of buttons is that not only can you re-use one actual button (e.g. 'stop') to make it the sleep trigger (using a long-press or a shift-press) but by selecting the ACTRLS_SLEEP action upon 'release', you can got to sleep upon release (1-0-1 transition) but also wake up upon another press (0 level applied on GPIO) because you only go to sleep *after* the GPIO returned to 1.
Please see [buttons](#buttons) for detailed syntax.
The option to use multiple GPIOs is very limited on esp32 and the esp-idf 4.3.x we are using: it is only possible to wake-up when **any** of the defined GPIO is set to 1. The fact that you can specify different levels in the wake list is irrelevant for now, it's just a provision for future upgrades to more recent versions of esp-idf.
**Note that not all GPIOs can be used to wake-up the esp32**
- ESP32: 0, 2, 4, 12-15, 25-27, 32-39;
- ESP32-S3: 0-21.
# Configuration # Configuration
## Setup WiFi ## Setup WiFi

View File

@@ -15,6 +15,7 @@
#include "platform_config.h" #include "platform_config.h"
#include "tools.h" #include "tools.h"
#include "display.h" #include "display.h"
#include "services.h"
#include "gds.h" #include "gds.h"
#include "gds_default_if.h" #include "gds_default_if.h"
#include "gds_draw.h" #include "gds_draw.h"
@@ -73,7 +74,9 @@ static const char *known_drivers[] = {"SH1106",
"ILI9341", "ILI9341",
NULL NULL
}; };
static void displayer_task(void *args); static void displayer_task(void *args);
static void display_sleep(void);
struct GDS_Device *display; struct GDS_Device *display;
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect; extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect;
@@ -174,11 +177,21 @@ void display_init(char *welcome) {
if (height <= 64 && width > height * 2) displayer.artwork.offset = width - height - ARTWORK_BORDER; if (height <= 64 && width > height * 2) displayer.artwork.offset = width - height - ARTWORK_BORDER;
PARSE_PARAM(displayer.metadata_config, "artwork", ':', displayer.artwork.fit); PARSE_PARAM(displayer.metadata_config, "artwork", ':', displayer.artwork.fit);
} }
// and finally register ourselves to power off upon deep sleep
services_sleep_sethook(display_sleep);
} }
free(config); free(config);
} }
/****************************************************************************************
*
*/
static void display_sleep(void) {
GDS_DisplayOff(display);
}
/**************************************************************************************** /****************************************************************************************
* This is not thread-safe as displayer_task might be in the middle of line drawing * This is not thread-safe as displayer_task might be in the middle of line drawing
* but it won't crash (I think) and making it thread-safe would be complicated for a * but it won't crash (I think) and making it thread-safe would be complicated for a

View File

@@ -19,6 +19,7 @@
#include "buttons.h" #include "buttons.h"
#include "platform_config.h" #include "platform_config.h"
#include "accessors.h" #include "accessors.h"
#include "services.h"
#include "audio_controls.h" #include "audio_controls.h"
typedef esp_err_t (actrls_config_map_handler) (const cJSON * member, actrls_config_t *cur_config,uint32_t offset); typedef esp_err_t (actrls_config_map_handler) (const cJSON * member, actrls_config_t *cur_config,uint32_t offset);
@@ -57,7 +58,7 @@ static const actrls_config_map_t actrls_config_map[] =
// BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing // BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing
// along with the actrls_t controls in LMS_controls, bt_sink and raop_sink // along with the actrls_t controls in LMS_controls, bt_sink and raop_sink
#define EP(x) [x] = #x /* ENUM PRINT */ #define EP(x) [x] = #x /* ENUM PRINT */
static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY), static const char * actrls_action_s[ ] = { EP(ACTRLS_SLEEP),EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT), EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),
EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT), EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT),
EP(BCTRLS_PS0),EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),EP(BCTRLS_PS7),EP(BCTRLS_PS8),EP(BCTRLS_PS9), EP(BCTRLS_PS0),EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),EP(BCTRLS_PS7),EP(BCTRLS_PS8),EP(BCTRLS_PS9),
@@ -170,13 +171,6 @@ static void control_handler(void *client, button_event_e event, button_press_e p
actrls_config_t *key = (actrls_config_t*) client; actrls_config_t *key = (actrls_config_t*) client;
actrls_action_detail_t action_detail; actrls_action_detail_t action_detail;
// in raw mode, we just do normal action press *and* release, there is no longpress nor shift
if (current_raw_controls) {
ESP_LOGD(TAG, "calling action %u in raw mode", key->normal[0].action);
if (current_controls[key->normal[0].action]) (*current_controls[key->normal[0].action])(event == BUTTON_PRESSED);
return;
}
switch(press) { switch(press) {
case BUTTON_NORMAL: case BUTTON_NORMAL:
if (long_press) action_detail = key->longpress[event == BUTTON_PRESSED ? 0 : 1]; if (long_press) action_detail = key->longpress[event == BUTTON_PRESSED ? 0 : 1];
@@ -196,6 +190,13 @@ static void control_handler(void *client, button_event_e event, button_press_e p
// stop here if control hook served the request // stop here if control hook served the request
if (current_hook && (*current_hook)(key->gpio, action_detail.action, event, press, long_press)) return; if (current_hook && (*current_hook)(key->gpio, action_detail.action, event, press, long_press)) return;
// in raw mode, we just do normal action press *and* release, there is no longpress nor shift
if (current_raw_controls && action_detail.action != ACTRLS_SLEEP) {
ESP_LOGD(TAG, "calling action %u in raw mode", key->normal[0].action);
if (current_controls[key->normal[0].action]) (*current_controls[key->normal[0].action])(event == BUTTON_PRESSED);
return;
}
// otherwise process using configuration // otherwise process using configuration
if (action_detail.action == ACTRLS_REMAP) { if (action_detail.action == ACTRLS_REMAP) {
// remap requested // remap requested
@@ -216,6 +217,9 @@ static void control_handler(void *client, button_event_e event, button_press_e p
} else { } else {
ESP_LOGE(TAG,"Invalid profile name %s. Cannot remap buttons",action_detail.name); ESP_LOGE(TAG,"Invalid profile name %s. Cannot remap buttons",action_detail.name);
} }
} else if (action_detail.action == ACTRLS_SLEEP) {
ESP_LOGI(TAG, "Sleep button pressed");
services_sleep_activate(SLEEP_ONKEY);
} else if (action_detail.action != ACTRLS_NONE) { } else if (action_detail.action != ACTRLS_NONE) {
ESP_LOGD(TAG, "calling action %u", action_detail.action); ESP_LOGD(TAG, "calling action %u", action_detail.action);
if (current_controls[action_detail.action]) (*current_controls[action_detail.action])(event == BUTTON_PRESSED); if (current_controls[action_detail.action]) (*current_controls[action_detail.action])(event == BUTTON_PRESSED);

View File

@@ -11,7 +11,7 @@
#include "buttons.h" #include "buttons.h"
// BEWARE: this is the index of the array of action below (change actrls_action_s as well!) // BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER,ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, typedef enum { ACTRLS_NONE = -1, ACTRLS_SLEEP, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9, BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9,

View File

@@ -7,7 +7,11 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/ledc.h" #include "driver/ledc.h"
#include "driver/i2c.h" #include "driver/i2c.h"
@@ -20,6 +24,8 @@
#include "globdefs.h" #include "globdefs.h"
#include "accessors.h" #include "accessors.h"
#include "messaging.h" #include "messaging.h"
#include "buttons.h"
#include "services.h"
extern void battery_svc_init(void); extern void battery_svc_init(void);
extern void monitor_svc_init(void); extern void monitor_svc_init(void);
@@ -30,11 +36,19 @@ int i2c_system_speed = 400000;
int spi_system_host = SPI_SYSTEM_HOST; int spi_system_host = SPI_SYSTEM_HOST;
int spi_system_dc_gpio = -1; int spi_system_dc_gpio = -1;
int rmt_system_base_channel = RMT_CHANNEL_0; int rmt_system_base_channel = RMT_CHANNEL_0;
pwm_system_t pwm_system = { pwm_system_t pwm_system = {
.timer = LEDC_TIMER_0, .timer = LEDC_TIMER_0,
.base_channel = LEDC_CHANNEL_0, .base_channel = LEDC_CHANNEL_0,
.max = (1 << LEDC_TIMER_13_BIT), .max = (1 << LEDC_TIMER_13_BIT),
}; };
static EXT_RAM_ATTR struct {
uint64_t wake_gpio, wake_level;
uint32_t delay;
} sleep_config;
static EXT_RAM_ATTR void (*sleep_hooks[16])(void);
static const char *TAG = "services"; static const char *TAG = "services";
@@ -60,6 +74,9 @@ void set_chip_power_gpio(int gpio, char *value) {
if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value); if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value);
} }
/****************************************************************************************
*
*/
void set_exp_power_gpio(int gpio, char *value) { void set_exp_power_gpio(int gpio, char *value) {
bool parsed = true; bool parsed = true;
@@ -75,8 +92,113 @@ void set_exp_power_gpio(int gpio, char *value) {
} else parsed = false; } else parsed = false;
if (parsed) ESP_LOGI(TAG, "set expanded GPIO %u to %s", gpio, value); if (parsed) ESP_LOGI(TAG, "set expanded GPIO %u to %s", gpio, value);
}
/****************************************************************************************
*
*/
static void sleep_gpio_handler(void *id, button_event_e event, button_press_e mode, bool long_press) {
if (event == BUTTON_PRESSED) services_sleep_activate(SLEEP_ONGPIO);
}
/****************************************************************************************
*
*/
static void sleep_init(void) {
char *config = config_alloc_get(NVS_TYPE_STR, "sleep_config");
char *p;
// do we want delay sleep
PARSE_PARAM(config, "delay", '=', sleep_config.delay);
sleep_config.delay *= 60*1000;
if (sleep_config.delay) {
ESP_LOGI(TAG, "Sleep inactivity of %d minute(s)", sleep_config.delay / (60*1000));
} }
// get the wake criteria
if ((p = strcasestr(config, "wake"))) {
char list[32] = "", item[8];
sscanf(p, "%*[^=]=%31[^,]", list);
p = list - 1;
while (p++ && sscanf(p, "%7[^|]", item)) {
int level = 0, gpio = atoi(item);
if (!rtc_gpio_is_valid_gpio(gpio)) {
ESP_LOGE(TAG, "invalid wake GPIO %d (not in RTC domain)", gpio);
} else {
sleep_config.wake_gpio |= 1LL << gpio;
}
if (sscanf(item, "%*[^:]:%d", &level)) sleep_config.wake_level |= level << gpio;
p = strchr(p, '|');
}
// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can be done
if (sleep_config.wake_gpio) {
ESP_LOGI(TAG, "Sleep wake-up gpio bitmap 0x%llx (active 0x%llx)", sleep_config.wake_gpio, sleep_config.wake_level);
}
}
// then get the gpio that activate sleep (we could check that we have a valid wake)
if ((p = strcasestr(config, "sleep"))) {
int gpio, level = 0;
char sleep[8] = "";
sscanf(p, "%*[^=]=%7[^,]", sleep);
gpio = atoi(sleep);
if ((p = strchr(sleep, ':')) != NULL) level = atoi(p + 1);
ESP_LOGI(TAG, "Sleep activation gpio %d (active %d)", gpio, level);
button_create(NULL, gpio, level ? BUTTON_HIGH : BUTTON_LOW, true, 0, sleep_gpio_handler, 0, -1);
}
}
/****************************************************************************************
*
*/
void services_sleep_callback(uint32_t elapsed) {
if (sleep_config.delay && elapsed >= sleep_config.delay) {
services_sleep_activate(SLEEP_ONTIMER);
}
}
/****************************************************************************************
*
*/
void services_sleep_activate(sleep_cause_e cause) {
// call all sleep hooks that might want to do something
for (void (**hook)(void) = sleep_hooks; *hook; hook++) (*hook)();
// isolate all possible GPIOs, except the wake-up ones
esp_sleep_config_gpio_isolate();
for (int i = 0; i < GPIO_NUM_MAX; i++) {
if (!rtc_gpio_is_valid_gpio(i) || ((1LL << i) & sleep_config.wake_gpio)) continue;
rtc_gpio_isolate(i);
}
// is there just one GPIO
if (sleep_config.wake_gpio & (sleep_config.wake_gpio - 1)) {
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on multiple GPIO, any '1' wakes up 0x%llx", cause, sleep_config.wake_gpio);
esp_sleep_enable_ext1_wakeup(sleep_config.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
} else {
int gpio = __builtin_ctz(sleep_config.wake_gpio);
int level = (sleep_config.wake_level >> gpio) & 0x01;
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on GPIO %d level %d", cause, gpio, level);
esp_sleep_enable_ext0_wakeup(gpio, level);
}
// we need to use a timer in case the same button is used for sleep and wake-up and it's "pressed" vs "released" selected
if (cause == SLEEP_ONKEY) xTimerStart(xTimerCreate("sleepTimer", pdMS_TO_TICKS(1000), pdFALSE, NULL, (void (*)(void*)) esp_deep_sleep_start), 0);
else esp_deep_sleep_start();
}
/****************************************************************************************
*
*/
void services_sleep_sethook(void (*hook)(void)) {
for (int i = 0; i < sizeof(sleep_hooks)/sizeof(void(*)(void)); i++) {
if (!sleep_hooks[i]) {
sleep_hooks[i] = hook;
return;
}
}
}
/**************************************************************************************** /****************************************************************************************
* *
@@ -148,4 +270,5 @@ void services_init(void) {
led_svc_init(); led_svc_init();
battery_svc_init(); battery_svc_init();
monitor_svc_init(); monitor_svc_init();
sleep_init();
} }

View File

@@ -0,0 +1,16 @@
/*
* Squeezelite for esp32
*
* (c) Philippe G. 2019, philippe_44@outlook.com
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
*/
#pragma once
typedef enum { SLEEP_ONTIMER, SLEEP_ONKEY, SLEEP_ONGPIO, SLEEP_ONIR } sleep_cause_e;
void services_sleep_activate(sleep_cause_e cause);
void services_sleep_sethook(void (*hook)(void));
void services_sleep_callback(uint32_t elapsed);

View File

@@ -41,6 +41,7 @@ sure that using rate_delay would fix that
#include "adac.h" #include "adac.h"
#include "time.h" #include "time.h"
#include "led.h" #include "led.h"
#include "services.h"
#include "monitor.h" #include "monitor.h"
#include "platform_config.h" #include "platform_config.h"
#include "gpio_exp.h" #include "gpio_exp.h"
@@ -102,9 +103,11 @@ const struct adac_s *adac = &dac_external;
static log_level loglevel; static log_level loglevel;
static uint32_t stopped_time;
static void (*pseudo_idle_chain)(uint32_t);
static bool (*slimp_handler_chain)(u8_t *data, int len); static bool (*slimp_handler_chain)(u8_t *data, int len);
static bool jack_mutes_amp; static bool jack_mutes_amp;
static bool running, isI2SStarted, ended; static bool running, isI2SStarted, ended, i2s_stats;
static i2s_config_t i2s_config; static i2s_config_t i2s_config;
static u8_t *obuf; static u8_t *obuf;
static frames_t oframes; static frames_t oframes;
@@ -125,7 +128,8 @@ DECLARE_ALL_MIN_MAX;
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags, static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, u8_t flags,
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr); s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
static void output_thread_i2s(void *arg); static void output_thread_i2s(void *arg);
static void i2s_stats(uint32_t now); static void i2s_idle(uint32_t now);
static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count); static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
static void (*jack_handler_chain)(bool inserted); static void (*jack_handler_chain)(bool inserted);
@@ -412,6 +416,14 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
adac->headset(jack_inserted_svc()); adac->headset(jack_inserted_svc());
// do we want stats
p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
i2s_stats = p && (*p == '1' || *p == 'Y' || *p == 'y');
free(p);
pseudo_idle_chain = pseudo_idle_svc;
pseudo_idle_svc = i2s_idle;
// create task as a FreeRTOS task but uses stack in internal RAM // create task as a FreeRTOS task but uses stack in internal RAM
{ {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
@@ -419,14 +431,6 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
output_i2s_task = xTaskCreateStaticPinnedToCore( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE, output_i2s_task = xTaskCreateStaticPinnedToCore( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE,
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer, 0 ); NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer, 0 );
} }
// do we want stats
p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
if (p && (*p == '1' || *p == 'Y' || *p == 'y')) {
pseudo_idle_chain = pseudo_idle_svc;
pseudo_idle_svc = i2s_stats;
}
free(p);
} }
@@ -493,6 +497,7 @@ static void output_thread_i2s(void *arg) {
uint32_t fullness = gettime_ms(); uint32_t fullness = gettime_ms();
bool synced; bool synced;
output_state state = OUTPUT_OFF - 1; output_state state = OUTPUT_OFF - 1;
stopped_time = pdMS_TO_TICKS(xTaskGetTickCount());
while (running) { while (running) {
@@ -508,6 +513,7 @@ static void output_thread_i2s(void *arg) {
if (amp_control.gpio != -1) gpio_set_level_x(amp_control.gpio, !amp_control.active); if (amp_control.gpio != -1) gpio_set_level_x(amp_control.gpio, !amp_control.active);
LOG_INFO("switching off amp GPIO %d", amp_control.gpio); LOG_INFO("switching off amp GPIO %d", amp_control.gpio);
} else if (output.state == OUTPUT_STOPPED) { } else if (output.state == OUTPUT_STOPPED) {
stopped_time = pdMS_TO_TICKS(xTaskGetTickCount());
adac->speaker(false); adac->speaker(false);
led_blink(LED_GREEN, 200, 1000); led_blink(LED_GREEN, 200, 1000);
} else if (output.state == OUTPUT_RUNNING) { } else if (output.state == OUTPUT_RUNNING) {
@@ -632,16 +638,19 @@ static void output_thread_i2s(void *arg) {
} }
/**************************************************************************************** /****************************************************************************************
* Stats output thread * stats output callback
*/ */
static void i2s_stats(uint32_t now) { static void i2s_idle(uint32_t now) {
static uint32_t last; static uint32_t last;
// first chain to next handler // first chain to next handler
if (pseudo_idle_chain) pseudo_idle_chain(now); if (pseudo_idle_chain) pseudo_idle_chain(now);
// call the sleep mamanger
if (output.state <= OUTPUT_STOPPED) services_sleep_callback(now - stopped_time);
// then see if we need to act // then see if we need to act
if (output.state <= OUTPUT_STOPPED || now < last + STATS_PERIOD_MS) return; if (!i2s_stats || output.state <= OUTPUT_STOPPED || now < last + STATS_PERIOD_MS) return;
last = now; last = now;
LOG_INFO( "Output State: %d, current sample rate: %d, bytes per frame: %d", output.state, output.current_sample_rate, BYTES_PER_FRAME); LOG_INFO( "Output State: %d, current sample rate: %d, bytes per frame: %d", output.state, output.current_sample_rate, BYTES_PER_FRAME);

View File

@@ -270,6 +270,7 @@ void register_default_nvs(){
register_default_string_val( "i2c_config", CONFIG_I2C_CONFIG); register_default_string_val( "i2c_config", CONFIG_I2C_CONFIG);
register_default_string_val( "spi_config", CONFIG_SPI_CONFIG); register_default_string_val( "spi_config", CONFIG_SPI_CONFIG);
register_default_string_val( "set_GPIO", CONFIG_SET_GPIO); register_default_string_val( "set_GPIO", CONFIG_SET_GPIO);
register_default_string_val( "sleep_config", "");
register_default_string_val( "led_brightness", ""); register_default_string_val( "led_brightness", "");
register_default_string_val( "spdif_config", ""); register_default_string_val( "spdif_config", "");
register_default_string_val( "dac_config", ""); register_default_string_val( "dac_config", "");