From 86b64d0415e9d4dd15cfa00dba017368c6cab8db Mon Sep 17 00:00:00 2001 From: Philippe G Date: Sat, 15 Aug 2020 18:43:02 -0700 Subject: [PATCH] headphone, bass/treble, battery from LMS --- TODO | 3 ++- components/services/battery.c | 31 +++++++++++++++++-------- components/services/monitor.h | 1 + components/squeezelite/embedded.c | 9 ++++++++ components/squeezelite/embedded.h | 9 ++++++-- components/squeezelite/output_i2s.c | 36 +++++++++++++++++++++++++++++ components/squeezelite/slimproto.c | 2 +- components/squeezelite/slimproto.h | 6 +++++ main/esp_app_main.c | 5 ++-- 9 files changed, 87 insertions(+), 15 deletions(-) diff --git a/TODO b/TODO index 42303bfd..ba4abdbd 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ - in squeezelite some buffers (stream, output, header, recv) are allocated although they are almost static (expect output). This creates a risk of memory fragmentation, especially because the large output is re-allocated for -AirPlay \ No newline at end of file +AirPlay +- libflac in lpc.c can be unrolled - that gains 43k of code, at the expense of 4% CPU \ No newline at end of file diff --git a/components/services/battery.c b/components/services/battery.c index 45c99b20..6d2694b2 100644 --- a/components/services/battery.c +++ b/components/services/battery.c @@ -33,15 +33,27 @@ static struct { int channel; float sum, avg, scale; int count; + int cells; TimerHandle_t timer; -} battery; +} battery = { + .channel = CONFIG_BAT_CHANNEL, + .cells = 2, +}; /**************************************************************************************** * */ int battery_value_svc(void) { - return battery.avg; + return battery.avg; } + +/**************************************************************************************** + * + */ +uint8_t battery_level_svc(void) { + // TODO: this is totally incorrect + return battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0; +} /**************************************************************************************** * @@ -59,29 +71,30 @@ static void battery_callback(TimerHandle_t xTimer) { * */ void battery_svc_init(void) { - battery.channel = CONFIG_BAT_CHANNEL; #ifdef CONFIG_BAT_SCALE battery.scale = atof(CONFIG_BAT_SCALE); #endif -#ifndef CONFIG_BAT_LOCKED char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "n", 0); if (nvs_item) { - char *p; + char *p; +#ifndef CONFIG_BAT_LOCKED if ((p = strcasestr(nvs_item, "channel")) != NULL) battery.channel = atoi(strchr(p, '=') + 1); if ((p = strcasestr(nvs_item, "scale")) != NULL) battery.scale = atof(strchr(p, '=') + 1); +#endif + if ((p = strcasestr(nvs_item, "cells")) != NULL) battery.cells = atof(strchr(p, '=') + 1); free(nvs_item); } -#endif if (battery.channel != -1) { - ESP_LOGI(TAG, "Battery measure channel: %u, scale %f", battery.channel, battery.scale); - adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(battery.channel, ADC_ATTEN_DB_0); - + + battery.avg = adc1_get_raw(battery.channel) * battery.scale / 4095.0; battery.timer = xTimerCreate("battery", BATTERY_TIMER / portTICK_RATE_MS, pdTRUE, NULL, battery_callback); xTimerStart(battery.timer, portMAX_DELAY); + + ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, cells %u, avg %.2fV", battery.channel, battery.scale, battery.cells, battery.avg); } else { ESP_LOGI(TAG, "No battery"); } diff --git a/components/services/monitor.h b/components/services/monitor.h index 0b5c966e..e8aa1dd9 100644 --- a/components/services/monitor.h +++ b/components/services/monitor.h @@ -17,4 +17,5 @@ extern void (*spkfault_handler_svc)(bool inserted); extern bool spkfault_svc(void); extern int battery_value_svc(void); +extern uint8_t battery_level_svc(void); diff --git a/components/squeezelite/embedded.c b/components/squeezelite/embedded.c index 1ac32b01..c9a2c27b 100644 --- a/components/squeezelite/embedded.c +++ b/components/squeezelite/embedded.c @@ -14,6 +14,7 @@ #include "esp_system.h" #include "esp_timer.h" #include "esp_wifi.h" +#include "monitor.h" mutex_type slimp_mutex; @@ -60,3 +61,11 @@ u16_t get_RSSI(void) { if (wifidata.primary != 0) return 100 + wifidata.rssi + 30; else return 0xffff; } + +u16_t get_plugged(void) { + return jack_inserted_svc() ? PLUG_HEADPHONE : 0; +} + +u8_t get_battery(void) { + return (battery_level_svc() * 16) / 100; +} diff --git a/components/squeezelite/embedded.h b/components/squeezelite/embedded.h index 5cc5a56c..580b4059 100644 --- a/components/squeezelite/embedded.h +++ b/components/squeezelite/embedded.h @@ -66,8 +66,13 @@ extern mutex_type slimp_mutex; #define LOCK_P mutex_lock(slimp_mutex) #define UNLOCK_P mutex_unlock(slimp_mutex) -// must provide or define as 0xffff -u16_t get_RSSI(void); +// bitmap of plugs status +#define PLUG_LINE_IN 0x01 +#define PLUG_LINE_OUT 0x02 +#define PLUG_HEADPHONE 0x04 +u16_t get_RSSI(void); // must provide or define as 0xffff +u16_t get_plugged(void); // must provide or define as 0x0 +u8_t get_battery(void); // must provide 0..15 or define as 0x0 // to be defined to nothing if you don't want to support these extern struct visu_export_s { diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 8bd5d30c..7c8ecc87 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -31,6 +31,7 @@ sure that using rate_delay would fix that */ #include "squeezelite.h" +#include "slimproto.h" #include "esp_pthread.h" #include "driver/i2s.h" #include "driver/i2c.h" @@ -82,6 +83,7 @@ const struct adac_s *adac = &dac_external; static log_level loglevel; +static bool (*slimp_handler_chain)(u8_t *data, int len); static bool jack_mutes_amp; static bool running, isI2SStarted; static i2s_config_t i2s_config; @@ -108,6 +110,36 @@ static void (*jack_handler_chain)(bool inserted); #define I2C_PORT 0 +/**************************************************************************************** + * AUDO packet handler + */ +static bool handler(u8_t *data, int len){ + bool res = true; + + if (!strncmp((char*) data, "audo", 4)) { + struct audo_packet *pkt = (struct audo_packet*) data; + // 0 = headphone (internal speakers off), 1 = sub out, + // 2 = always on (internal speakers on), 3 = always off + + if (jack_mutes_amp != (pkt->config == 0)) { + jack_mutes_amp = pkt->config == 0; + config_set_value(NVS_TYPE_STR, "jack_mutes_amp", jack_mutes_amp ? "y" : "n"); + + if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false); + else adac->speaker(true); + } + + LOG_INFO("got AUDO %02x", pkt->config); + } else { + res = false; + } + + // chain protocol handlers (bitwise or is fine) + if (*slimp_handler_chain) res |= (*slimp_handler_chain)(data, len); + + return res; +} + /**************************************************************************************** * jack insertion handler */ @@ -164,6 +196,10 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch int silent_do = -1; char *p; esp_err_t res; + + // chain SLIMP handlers + slimp_handler_chain = slimp_handler; + slimp_handler = handler; p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); jack_mutes_amp = (strcmp(p,"1") == 0 ||strcasecmp(p,"y") == 0); diff --git a/components/squeezelite/slimproto.c b/components/squeezelite/slimproto.c index 300713a2..8064e4a6 100644 --- a/components/squeezelite/slimproto.c +++ b/components/squeezelite/slimproto.c @@ -190,6 +190,7 @@ static void sendSTAT(const char *event, u32_t server_timestamp) { packN(&pkt.bytes_received_L, (u64_t)status.stream_bytes & 0xffffffff); #if EMBEDDED packn(&pkt.signal_strength, get_RSSI()); + packn(&pkt.voltage, (get_battery() << 4) | get_plugged()); #else pkt.signal_strength = 0xffff; #endif @@ -197,7 +198,6 @@ static void sendSTAT(const char *event, u32_t server_timestamp) { packN(&pkt.output_buffer_size, status.output_size); packN(&pkt.output_buffer_fullness, status.output_full); packN(&pkt.elapsed_seconds, ms_played / 1000); - // voltage; packN(&pkt.elapsed_milliseconds, ms_played); pkt.server_timestamp = server_timestamp; // keep this is server format - don't unpack/pack // error_code; diff --git a/components/squeezelite/slimproto.h b/components/squeezelite/slimproto.h index e4af8040..56e79ff5 100644 --- a/components/squeezelite/slimproto.h +++ b/components/squeezelite/slimproto.h @@ -178,6 +178,12 @@ struct codc_packet { u8_t pcm_endianness; }; +// initially Boom +struct audo_packet { + char opcode[4]; + u8_t config; +}; + #ifndef SUN #pragma pack(pop) #else diff --git a/main/esp_app_main.c b/main/esp_app_main.c index c5d7dc6f..ecfdb6ea 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -287,8 +287,6 @@ void register_default_nvs(){ config_set_default(NVS_TYPE_STR, "a2dp_ctrld", STR(CONFIG_A2DP_CONTROL_DELAY_MS), 0); ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bt_sink_pin", STR(CONFIG_A2DP_CONTROL_DELAY_MS)); - - config_set_default(NVS_TYPE_STR, "bt_sink_pin", STR(CONFIG_BT_SINK_PIN), 0); ESP_LOGD(TAG,"Registering default value for key %s, value %s", "release_url", SQUEEZELITE_ESP32_RELEASE_URL); config_set_default(NVS_TYPE_STR, "release_url", SQUEEZELITE_ESP32_RELEASE_URL, 0); @@ -361,6 +359,9 @@ void register_default_nvs(){ ESP_LOGD(TAG,"Registering default value for key %s", "dac_controlset"); config_set_default(NVS_TYPE_STR, "dac_controlset", "", 0); + ESP_LOGD(TAG,"Registering default value for key %s", "jack_mutes_amp"); + config_set_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); + ESP_LOGD(TAG,"Registering default value for key %s", "bat_config"); config_set_default(NVS_TYPE_STR, "bat_config", "", 0);