mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-06 11:36:59 +03:00
add buttons/rotary/ir/BT sink in sleep + battery low-voltage
This commit is contained in:
@@ -179,7 +179,7 @@ void display_init(char *welcome) {
|
||||
}
|
||||
|
||||
// and finally register ourselves to power off upon deep sleep
|
||||
services_sleep_sethook(display_sleep);
|
||||
services_sleep_setsuspend(display_sleep);
|
||||
}
|
||||
|
||||
free(config);
|
||||
|
||||
@@ -25,6 +25,8 @@ static const char * TAG = "bt_app_source";
|
||||
static const char * BT_RC_CT_TAG="RCCT";
|
||||
extern int32_t output_bt_data(uint8_t *data, int32_t len);
|
||||
extern void output_bt_tick(void);
|
||||
extern void output_bt_stop(void);
|
||||
extern void output_bt_start(void);
|
||||
extern char* output_state_str(void);
|
||||
extern bool output_stopped(void);
|
||||
extern bool is_recovery_running;
|
||||
@@ -803,6 +805,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
|
||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
||||
ESP_LOGI(TAG,"a2dp media started successfully.");
|
||||
output_bt_start();
|
||||
set_a2dp_media_state(APP_AV_MEDIA_STATE_STARTED);
|
||||
} else {
|
||||
// not started succesfully, transfer to idle state
|
||||
@@ -831,6 +834,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP &&
|
||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
||||
ESP_LOGI(TAG,"a2dp media stopped successfully...");
|
||||
output_bt_stop();
|
||||
set_a2dp_media_state(APP_AV_MEDIA_STATE_IDLE);
|
||||
} else {
|
||||
ESP_LOGI(TAG,"a2dp media stopping...");
|
||||
|
||||
@@ -40,7 +40,7 @@ static struct {
|
||||
.cells = 2,
|
||||
};
|
||||
|
||||
void (*battery_handler_svc)(float value);
|
||||
void (*battery_handler_svc)(float value, int cells);
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
@@ -66,7 +66,7 @@ static void battery_callback(TimerHandle_t xTimer) {
|
||||
if (++battery.count == 30) {
|
||||
battery.avg = battery.sum / battery.count;
|
||||
battery.sum = battery.count = 0;
|
||||
if (battery_handler_svc) (battery_handler_svc)(battery.avg);
|
||||
if (battery_handler_svc) (battery_handler_svc)(battery.avg, battery.cells);
|
||||
ESP_LOGI(TAG, "Voltage %.2fV", battery.avg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@
|
||||
#include "driver/rmt.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "buttons.h"
|
||||
#include "services.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "globdefs.h"
|
||||
|
||||
static const char * TAG = "buttons";
|
||||
|
||||
static EXT_RAM_ATTR int n_buttons;
|
||||
static EXT_RAM_ATTR uint32_t buttons_idle_since;
|
||||
|
||||
#define BUTTON_STACK_SIZE 4096
|
||||
#define MAX_BUTTONS 32
|
||||
@@ -156,18 +158,31 @@ static void buttons_handler(struct button_s *button, int level) {
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get inactivity callback
|
||||
*/
|
||||
static uint32_t buttons_idle_callback(void) {
|
||||
return pdTICKS_TO_MS(xTaskGetTickCount()) - buttons_idle_since;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Tasks that calls the appropriate functions when buttons are pressed
|
||||
*/
|
||||
static void buttons_task(void* arg) {
|
||||
ESP_LOGI(TAG, "starting button tasks");
|
||||
|
||||
buttons_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
services_sleep_setsleeper(buttons_idle_callback);
|
||||
|
||||
while (1) {
|
||||
QueueSetMemberHandle_t xActivatedMember;
|
||||
|
||||
// wait on button, rotary and infrared queues
|
||||
if ((xActivatedMember = xQueueSelectFromSet( common_queue_set, portMAX_DELAY )) == NULL) continue;
|
||||
|
||||
// mark the last activity
|
||||
buttons_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
|
||||
if (xActivatedMember == button_queue) {
|
||||
struct button_s button;
|
||||
button_event_e event;
|
||||
|
||||
@@ -22,7 +22,7 @@ extern bool jack_inserted_svc(void);
|
||||
extern void (*spkfault_handler_svc)(bool inserted);
|
||||
extern bool spkfault_svc(void);
|
||||
|
||||
extern void (*battery_handler_svc)(float value);
|
||||
extern void (*battery_handler_svc)(float value, int cells);
|
||||
extern float battery_value_svc(void);
|
||||
extern uint16_t battery_level_svc(void);
|
||||
|
||||
|
||||
@@ -47,9 +47,13 @@ static EXT_RAM_ATTR struct {
|
||||
uint64_t wake_gpio, wake_level;
|
||||
uint64_t rtc_gpio, rtc_level;
|
||||
uint32_t delay;
|
||||
} sleep_config;
|
||||
|
||||
static EXT_RAM_ATTR void (*sleep_hooks[16])(void);
|
||||
float battery_level;
|
||||
int battery_count;
|
||||
void (*idle_chain)(uint32_t now);
|
||||
void (*battery_chain)(float level, int cells);
|
||||
void (*suspend[10])(void);
|
||||
uint32_t (*sleeper[10])(void);
|
||||
} sleep_context;
|
||||
|
||||
static const char *TAG = "services";
|
||||
|
||||
@@ -102,6 +106,43 @@ static void sleep_gpio_handler(void *id, button_event_e event, button_press_e mo
|
||||
if (event == BUTTON_PRESSED) services_sleep_activate(SLEEP_ONGPIO);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void sleep_timer(uint32_t now) {
|
||||
static uint32_t last;
|
||||
|
||||
// first chain the calls to psudo_idle function
|
||||
if (sleep_context.idle_chain) sleep_context.idle_chain(now);
|
||||
|
||||
// only query callbacks every 30s if we have at least one sleeper
|
||||
if (!*sleep_context.sleeper || now < last + 30*1000) return;
|
||||
last = now;
|
||||
|
||||
// call all sleep hooks that might want to do something
|
||||
for (uint32_t (**sleeper)(void) = sleep_context.sleeper; *sleeper; sleeper++) {
|
||||
if ((*sleeper)() < sleep_context.delay) return;
|
||||
}
|
||||
|
||||
// if we are here, we are ready to sleep;
|
||||
services_sleep_activate(SLEEP_ONTIMER);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void sleep_battery(float level, int cells) {
|
||||
// chain if any
|
||||
if (sleep_context.battery_chain) sleep_context.battery_chain(level, cells);
|
||||
|
||||
// then assess if we have to stop because of low batt
|
||||
if (level < sleep_context.battery_level) {
|
||||
if (sleep_context.battery_count++ == 2) services_sleep_activate(SLEEP_ONBATTERY);
|
||||
} else {
|
||||
sleep_context.battery_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
@@ -110,10 +151,20 @@ static void sleep_init(void) {
|
||||
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));
|
||||
PARSE_PARAM(config, "delay", '=', sleep_context.delay);
|
||||
sleep_context.delay *= 60*1000;
|
||||
if (sleep_context.delay) {
|
||||
sleep_context.idle_chain = pseudo_idle_svc;
|
||||
pseudo_idle_svc = sleep_timer;
|
||||
ESP_LOGI(TAG, "Sleep inactivity of %d minute(s)", sleep_context.delay / (60*1000));
|
||||
}
|
||||
|
||||
// do we want battery safety
|
||||
PARSE_PARAM_FLOAT(config, "batt", '=', sleep_context.battery_level);
|
||||
if (sleep_context.battery_level != 0.0) {
|
||||
sleep_context.battery_chain = battery_handler_svc;
|
||||
battery_handler_svc = sleep_battery;
|
||||
ESP_LOGI(TAG, "Sleep on battery level of %.2f", sleep_context.battery_level);
|
||||
}
|
||||
|
||||
// get the wake criteria
|
||||
@@ -126,15 +177,15 @@ static void sleep_init(void) {
|
||||
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;
|
||||
sleep_context.wake_gpio |= 1LL << gpio;
|
||||
}
|
||||
if (sscanf(item, "%*[^:]:%d", &level)) sleep_config.wake_level |= level << gpio;
|
||||
if (sscanf(item, "%*[^:]:%d", &level)) sleep_context.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);
|
||||
if (sleep_context.wake_gpio) {
|
||||
ESP_LOGI(TAG, "Sleep wake-up gpio bitmap 0x%llx (active 0x%llx)", sleep_context.wake_gpio, sleep_context.wake_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,15 +199,15 @@ static void sleep_init(void) {
|
||||
if (!rtc_gpio_is_valid_gpio(gpio)) {
|
||||
ESP_LOGE(TAG, "invalid rtc GPIO %d", gpio);
|
||||
} else {
|
||||
sleep_config.rtc_gpio |= 1LL << gpio;
|
||||
sleep_context.rtc_gpio |= 1LL << gpio;
|
||||
}
|
||||
if (sscanf(item, "%*[^:]:%d", &level)) sleep_config.rtc_level |= level << gpio;
|
||||
if (sscanf(item, "%*[^:]:%d", &level)) sleep_context.rtc_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.rtc_gpio) {
|
||||
ESP_LOGI(TAG, "RTC forced gpio bitmap 0x%llx (active 0x%llx)", sleep_config.rtc_gpio, sleep_config.rtc_level);
|
||||
if (sleep_context.rtc_gpio) {
|
||||
ESP_LOGI(TAG, "RTC forced gpio bitmap 0x%llx (active 0x%llx)", sleep_context.rtc_gpio, sleep_context.rtc_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,49 +223,40 @@ static void sleep_init(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
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)();
|
||||
for (void (**suspend)(void) = sleep_context.suspend; *suspend; suspend++) (*suspend)();
|
||||
|
||||
// isolate all possible GPIOs, except the wake-up and RTC-maintaines ones
|
||||
esp_sleep_config_gpio_isolate();
|
||||
|
||||
// keep RTC domain up if we need to maintain pull-up/down of some GPIO from RTC
|
||||
if (sleep_config.rtc_gpio) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
if (sleep_context.rtc_gpio) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
for (int i = 0; i < GPIO_NUM_MAX; i++) {
|
||||
// must be a RTC GPIO
|
||||
if (!rtc_gpio_is_valid_gpio(i)) continue;
|
||||
|
||||
// do we need to maintain a pull-up or down of that GPIO
|
||||
if ((1LL << i) & sleep_config.rtc_gpio) {
|
||||
if ((sleep_config.rtc_level >> i) & 0x01) rtc_gpio_pullup_en(i);
|
||||
if ((1LL << i) & sleep_context.rtc_gpio) {
|
||||
if ((sleep_context.rtc_level >> i) & 0x01) rtc_gpio_pullup_en(i);
|
||||
else rtc_gpio_pulldown_en(i);
|
||||
// or is this not wake-up GPIO, just isolate it
|
||||
} else if (!((1LL << i) & sleep_config.wake_gpio)) {
|
||||
} else if (!((1LL << i) & sleep_context.wake_gpio)) {
|
||||
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 if (sleep_config.wake_gpio) {
|
||||
int gpio = __builtin_ctz(sleep_config.wake_gpio);
|
||||
int level = (sleep_config.wake_level >> gpio) & 0x01;
|
||||
if (sleep_context.wake_gpio & (sleep_context.wake_gpio - 1)) {
|
||||
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on multiple GPIO, any '1' wakes up 0x%llx", cause, sleep_context.wake_gpio);
|
||||
esp_sleep_enable_ext1_wakeup(sleep_context.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
} else if (sleep_context.wake_gpio) {
|
||||
int gpio = __builtin_ctz(sleep_context.wake_gpio);
|
||||
int level = (sleep_context.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);
|
||||
} else {
|
||||
@@ -226,16 +268,29 @@ void services_sleep_activate(sleep_cause_e cause) {
|
||||
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;
|
||||
static void register_method(void **store, size_t size, void *method) {
|
||||
for (int i = 0; i < size; i++, *store++) if (!*store) {
|
||||
*store = method;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void services_sleep_setsuspend(void (*hook)(void)) {
|
||||
register_method((void**) sleep_context.suspend, sizeof(sleep_context.suspend)/sizeof(*sleep_context.suspend), (void*) hook);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void services_sleep_setsleeper(uint32_t (*sleeper)(void)) {
|
||||
register_method((void**) sleep_context.sleeper, sizeof(sleep_context.sleeper)/sizeof(*sleep_context.sleeper), (void*) sleeper);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum { SLEEP_ONTIMER, SLEEP_ONKEY, SLEEP_ONGPIO, SLEEP_ONIR } sleep_cause_e;
|
||||
typedef enum { SLEEP_ONTIMER, SLEEP_ONKEY, SLEEP_ONGPIO, SLEEP_ONIR, SLEEP_ONBATTERY } 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);
|
||||
void services_sleep_setsuspend(void (*hook)(void));
|
||||
void services_sleep_setsleeper(uint32_t (*sleeper)(void));
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "squeezelite.h"
|
||||
#include "equalizer.h"
|
||||
#include "perf_trace.h"
|
||||
#include "platform_config.h"
|
||||
#include <assert.h>
|
||||
#include "services.h"
|
||||
#include "led.h"
|
||||
|
||||
extern struct outputstate output;
|
||||
extern struct buffer *outputbuf;
|
||||
@@ -39,6 +41,7 @@ static bool running = false;
|
||||
static uint8_t *btout;
|
||||
static frames_t oframes;
|
||||
static bool stats;
|
||||
static uint32_t bt_idle_since;
|
||||
|
||||
static int _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);
|
||||
@@ -61,8 +64,26 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
|
||||
DECLARE_ALL_MIN_MAX;
|
||||
|
||||
/****************************************************************************************
|
||||
* Get inactivity callback
|
||||
*/
|
||||
static uint32_t bt_idle_callback(void) {
|
||||
return output.state <= OUTPUT_STOPPED ? pdTICKS_TO_MS(xTaskGetTickCount()) - bt_idle_since : 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Init BT sink
|
||||
*/
|
||||
void output_init_bt(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
|
||||
loglevel = level;
|
||||
|
||||
// idle counter
|
||||
bt_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
services_sleep_setsleeper(bt_idle_callback);
|
||||
|
||||
// even BT has a right to use led :-)
|
||||
led_blink(LED_GREEN, 200, 1000);
|
||||
|
||||
running = true;
|
||||
output.write_cb = &_write_frames;
|
||||
hal_bluetooth_init(device);
|
||||
@@ -72,6 +93,9 @@ void output_init_bt(log_level level, char *device, unsigned output_buf_size, cha
|
||||
equalizer_set_samplerate(output.current_sample_rate);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Close BT sink
|
||||
*/
|
||||
void output_close_bt(void) {
|
||||
LOCK;
|
||||
running = false;
|
||||
@@ -80,6 +104,9 @@ void output_close_bt(void) {
|
||||
equalizer_close();
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Data framing callback
|
||||
*/
|
||||
static int _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) {
|
||||
|
||||
@@ -120,6 +147,9 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
|
||||
return (int)out_frames;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Data callback for BT stack
|
||||
*/
|
||||
int32_t output_bt_data(uint8_t *data, int32_t len) {
|
||||
int32_t iframes = len / BYTES_PER_FRAME, start_timer = 0;
|
||||
|
||||
@@ -153,6 +183,9 @@ int32_t output_bt_data(uint8_t *data, int32_t len) {
|
||||
return oframes * BYTES_PER_FRAME;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Tick for BT
|
||||
*/
|
||||
void output_bt_tick(void) {
|
||||
static time_t lastTime=0;
|
||||
|
||||
@@ -186,3 +219,18 @@ void output_bt_tick(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* BT playback stop
|
||||
*/
|
||||
void output_bt_stop(void) {
|
||||
led_blink(LED_GREEN, 200, 1000);
|
||||
bt_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* BT playback start
|
||||
*/
|
||||
void output_bt_start(void) {
|
||||
led_on(LED_GREEN);
|
||||
bt_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
}
|
||||
|
||||
@@ -103,11 +103,11 @@ const struct adac_s *adac = &dac_external;
|
||||
|
||||
static log_level loglevel;
|
||||
|
||||
static uint32_t stopped_time;
|
||||
static uint32_t i2s_idle_since;
|
||||
static void (*pseudo_idle_chain)(uint32_t);
|
||||
static bool (*slimp_handler_chain)(u8_t *data, int len);
|
||||
static bool jack_mutes_amp;
|
||||
static bool running, isI2SStarted, ended, i2s_stats;
|
||||
static bool running, isI2SStarted, ended;
|
||||
static i2s_config_t i2s_config;
|
||||
static u8_t *obuf;
|
||||
static frames_t oframes;
|
||||
@@ -128,7 +128,7 @@ DECLARE_ALL_MIN_MAX;
|
||||
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);
|
||||
static void output_thread_i2s(void *arg);
|
||||
static void i2s_idle(uint32_t now);
|
||||
static void i2s_stats(uint32_t now);
|
||||
|
||||
static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
|
||||
static void (*jack_handler_chain)(bool inserted);
|
||||
@@ -202,6 +202,13 @@ static void set_amp_gpio(int gpio, char *value) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************************
|
||||
* Get inactivity callback
|
||||
*/
|
||||
static uint32_t i2s_idle_callback(void) {
|
||||
return output.state <= OUTPUT_STOPPED ? pdTICKS_TO_MS(xTaskGetTickCount()) - i2s_idle_since : 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Set pin from config string
|
||||
*/
|
||||
@@ -418,11 +425,15 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
|
||||
// do we want stats
|
||||
p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
|
||||
i2s_stats = p && (*p == '1' || *p == 'Y' || *p == 'y');
|
||||
if (p && (*p == '1' || *p == 'Y' || *p == 'y')) {
|
||||
pseudo_idle_chain = pseudo_idle_svc;
|
||||
pseudo_idle_svc = i2s_stats;
|
||||
}
|
||||
free(p);
|
||||
|
||||
pseudo_idle_chain = pseudo_idle_svc;
|
||||
pseudo_idle_svc = i2s_idle;
|
||||
// register a callback for inactivity
|
||||
i2s_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
services_sleep_setsleeper(i2s_idle_callback);
|
||||
|
||||
// create task as a FreeRTOS task but uses stack in internal RAM
|
||||
{
|
||||
@@ -433,7 +444,6 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Terminate DAC output
|
||||
*/
|
||||
@@ -497,7 +507,6 @@ static void output_thread_i2s(void *arg) {
|
||||
uint32_t fullness = gettime_ms();
|
||||
bool synced;
|
||||
output_state state = OUTPUT_OFF - 1;
|
||||
stopped_time = pdMS_TO_TICKS(xTaskGetTickCount());
|
||||
|
||||
while (running) {
|
||||
|
||||
@@ -513,7 +522,7 @@ static void output_thread_i2s(void *arg) {
|
||||
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);
|
||||
} else if (output.state == OUTPUT_STOPPED) {
|
||||
stopped_time = pdMS_TO_TICKS(xTaskGetTickCount());
|
||||
i2s_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
adac->speaker(false);
|
||||
led_blink(LED_GREEN, 200, 1000);
|
||||
} else if (output.state == OUTPUT_RUNNING) {
|
||||
@@ -640,17 +649,14 @@ static void output_thread_i2s(void *arg) {
|
||||
/****************************************************************************************
|
||||
* stats output callback
|
||||
*/
|
||||
static void i2s_idle(uint32_t now) {
|
||||
static void i2s_stats(uint32_t now) {
|
||||
static uint32_t last;
|
||||
|
||||
// first chain to next handler
|
||||
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
|
||||
if (!i2s_stats || output.state <= OUTPUT_STOPPED || now < last + STATS_PERIOD_MS) return;
|
||||
if (output.state <= OUTPUT_STOPPED || now < last + STATS_PERIOD_MS) return;
|
||||
last = now;
|
||||
|
||||
LOG_INFO( "Output State: %d, current sample rate: %d, bytes per frame: %d", output.state, output.current_sample_rate, BYTES_PER_FRAME);
|
||||
|
||||
@@ -48,8 +48,8 @@ void ws2812_write_leds(struct led_state new_state);
|
||||
|
||||
static const char TAG[] = "muse";
|
||||
|
||||
static void (*battery_handler_chain)(float value);
|
||||
static void battery_svc(float value);
|
||||
static void (*battery_handler_chain)(float value, int cells);
|
||||
static void battery_svc(float value, int cells);
|
||||
static bool init(void);
|
||||
static void set_battery_led(float value);
|
||||
|
||||
@@ -81,11 +81,11 @@ static void set_battery_led(float value) {
|
||||
ws2812_write_leds(new_state);
|
||||
}
|
||||
|
||||
static void battery_svc(float value) {
|
||||
static void battery_svc(float value, int cells) {
|
||||
set_battery_led(value);
|
||||
ESP_LOGI(TAG, "Called for battery service with %f", value);
|
||||
|
||||
if (battery_handler_chain) battery_handler_chain(value);
|
||||
if (battery_handler_chain) battery_handler_chain(value, cells);
|
||||
}
|
||||
|
||||
// This is the buffer which the hw peripheral will access while pulsing the output pin
|
||||
|
||||
Reference in New Issue
Block a user