diff --git a/build-scripts/ESP32-A1S-sdkconfig.defaults b/build-scripts/ESP32-A1S-sdkconfig.defaults index 829a3216..1e160101 100644 --- a/build-scripts/ESP32-A1S-sdkconfig.defaults +++ b/build-scripts/ESP32-A1S-sdkconfig.defaults @@ -31,6 +31,8 @@ CONFIG_SPDIF_BCK_IO=27 CONFIG_SPDIF_WS_IO=26 CONFIG_SPDIF_DO_IO=-1 CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" +CONFIG_MUTE_GPIO=-1 +CONFIG_MUTE_GPIO_LEVEL=-1 CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET="esp32" diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 77ada011..0f034958 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -33,6 +33,8 @@ CONFIG_SDIF_NUM=0 CONFIG_SPDIF_BCK_IO=33 CONFIG_SPDIF_WS_IO=25 CONFIG_SPDIF_DO_IO=-1 +CONFIG_MUTE_GPIO=-1 +CONFIG_MUTE_GPIO_LEVEL=-1 CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET="esp32" diff --git a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults index ba59e827..f7bf892f 100644 --- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults @@ -31,9 +31,10 @@ CONFIG_BAT_SCALE="20.24" CONFIG_I2S_NUM=0 CONFIG_SDIF_NUM=0 CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15" -CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14" +CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET="esp32" +CONFIG_MUTE_GPIO_LEVEL=-1 # # SDK tool configuration diff --git a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults index e7c8bd81..3d98d0dc 100644 --- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults @@ -32,6 +32,7 @@ CONFIG_I2S_NUM=0 CONFIG_SDIF_NUM=0 CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15" CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14" +CONFIG_MUTE_GPIO_LEVEL=-1 CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET="esp32" diff --git a/components/config/config.c b/components/config/config.c index 65ee41ab..c5515209 100644 --- a/components/config/config.c +++ b/components/config/config.c @@ -611,9 +611,21 @@ void config_delete_key(const char *key){ } config_unlock(); } + void * config_alloc_get(nvs_type_t nvs_type, const char *key) { return config_alloc_get_default(nvs_type, key, NULL, 0); } + +void * config_alloc_get_str(const char *key, char *lead, char *fallback) { + if (lead && *lead) return strdup(lead); + char *value = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0); + if ((!value || !*value) && fallback) { + if (value) free(value); + value = strdup(fallback); + } + return value; +} + void * config_alloc_get_default(nvs_type_t nvs_type, const char *key, void * default_value, size_t blob_size) { void * value = NULL; diff --git a/components/config/config.h b/components/config/config.h index f83c7276..5f1fd8e5 100644 --- a/components/config/config.h +++ b/components/config/config.h @@ -34,6 +34,7 @@ void * config_alloc_get_default(nvs_type_t type, const char *key, void * default void config_delete_key(const char *key); void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size); void * config_alloc_get(nvs_type_t nvs_type, const char *key) ; +void * config_alloc_get_str(const char *key, char *lead, char *fallback); bool wait_for_commit(); char * config_alloc_get_json(bool bFormatted); esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value); diff --git a/components/display/display.c b/components/display/display.c index afc19ccc..25a98304 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -56,12 +56,7 @@ GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD */ void display_init(char *welcome) { bool init = false; - char *config = config_alloc_get(NVS_TYPE_STR, "display_config"); - - if (!config) { - ESP_LOGI(TAG, "no display"); - return; - } + char *config = config_alloc_get_str("display_config", CONFIG_DISPLAY_CONFIG, "N/A"); int width = -1, height = -1, backlight_pin = -1; char *p, *drivername = strstr(config, "driver"); diff --git a/components/services/accessors.c b/components/services/accessors.c index cd274476..1889c493 100644 --- a/components/services/accessors.c +++ b/components/services/accessors.c @@ -75,7 +75,7 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) { .quadhd_io_num = -1 }; - nvs_item = config_alloc_get(NVS_TYPE_STR, "spi_config"); + nvs_item = config_alloc_get_str("spi_config", CONFIG_SPI_CONFIG, NULL); if (nvs_item) { if ((p = strcasestr(nvs_item, "data")) != NULL) spi.mosi_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(nvs_item, "clk")) != NULL) spi.sclk_io_num = atoi(strchr(p, '=') + 1); diff --git a/components/services/led.c b/components/services/led.c index f203f299..cbf6dc46 100644 --- a/components/services/led.c +++ b/components/services/led.c @@ -231,7 +231,7 @@ void led_svc_init(void) { #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, red.gpio, red.active, red.pwm); + 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) { diff --git a/components/squeezelite/ac101/ac101.c b/components/squeezelite/ac101/ac101.c index 234dcff1..eba88654 100644 --- a/components/squeezelite/ac101/ac101.c +++ b/components/squeezelite/ac101/ac101.c @@ -52,7 +52,7 @@ static bool init(char *config, int i2c_port_num); static void deinit(void); static void speaker(bool active); static void headset(bool active); -static void volume(unsigned left, unsigned right); +static bool volume(unsigned left, unsigned right); static void power(adac_power_e mode); const struct adac_s dac_ac101 = { "AC101", init, deinit, power, speaker, headset, volume }; @@ -164,8 +164,9 @@ static void deinit(void) { /**************************************************************************************** * change volume */ -static void volume(unsigned left, unsigned right) { +static bool volume(unsigned left, unsigned right) { // nothing at that point, volume is handled by backend + return false; } /**************************************************************************************** diff --git a/components/squeezelite/adac.h b/components/squeezelite/adac.h index 5c13a62b..3e337c72 100644 --- a/components/squeezelite/adac.h +++ b/components/squeezelite/adac.h @@ -21,7 +21,7 @@ struct adac_s { void (*power)(adac_power_e mode); void (*speaker)(bool active); void (*headset)(bool active); - void (*volume)(unsigned left, unsigned right); + bool (*volume)(unsigned left, unsigned right); }; extern const struct adac_s dac_tas57xx; diff --git a/components/squeezelite/external/dac_external.c b/components/squeezelite/external/dac_external.c index 278ddccc..f443e983 100644 --- a/components/squeezelite/external/dac_external.c +++ b/components/squeezelite/external/dac_external.c @@ -12,22 +12,163 @@ #include #include #include +#include "driver/i2c.h" #include "esp_log.h" +#include "cJSON.h" #include "config.h" #include "adac.h" static const char TAG[] = "DAC external"; +static void deinit(void) { } +static void speaker(bool active) { } +static void headset(bool active) { } +static bool volume(unsigned left, unsigned right) { return false; } +static void power(adac_power_e mode); static bool init(char *config, int i2c_port_num); -static void deinit(void) { }; -static void speaker(bool active) { }; -static void headset(bool active) { } ; -static void volume(unsigned left, unsigned right) { }; -static void power(adac_power_e mode) { }; + +static bool i2c_json_execute(char *set); +static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val); +static uint8_t i2c_read_reg(uint8_t reg); const struct adac_s dac_external = { "i2s", init, deinit, power, speaker, headset, volume }; +static int i2c_port, i2c_addr; +static cJSON *i2c_json; -static bool init(char *config, int i2c_port_num) { - return true; +/**************************************************************************************** + * init + */ +static bool init(char *config, int i2c_port_num) { + char *p; + i2c_port = i2c_port_num; + + // configure i2c + i2c_config_t i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = -1, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = -1, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 250000, + }; + + if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1); + if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1); + if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1); + + p = config_alloc_get_str("dac_controlset", CONFIG_DAC_CONTROLSET, NULL); + i2c_json = cJSON_Parse(p); + + if (!i2c_addr || !i2c_json || i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) { + if (p) free(p); + ESP_LOGW(TAG, "No i2c controlset found"); + return true; + } + + ESP_LOGI(TAG, "DAC uses I2C @%d with sda:%d, scl:%d", i2c_addr, i2c_config.sda_io_num, i2c_config.scl_io_num); + + // we have an I2C configured + i2c_param_config(i2c_port, &i2c_config); + i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); + + if (!i2c_json_execute("init")) { + ESP_LOGE(TAG, "could not intialize DAC"); + return false; + } + + return true; +} + +/**************************************************************************************** + * power + */ +static void power(adac_power_e mode) { + if (mode == ADAC_STANDBY || mode == ADAC_OFF) i2c_json_execute("poweroff"); + else i2c_json_execute("poweron"); } +/**************************************************************************************** + * + */ +bool i2c_json_execute(char *set) { + cJSON *json_set = cJSON_GetObjectItemCaseSensitive(i2c_json, set); + cJSON *item; + + if (!json_set) return true; + + cJSON_ArrayForEach(item, json_set) + { + cJSON *reg = cJSON_GetObjectItemCaseSensitive(item, "reg"); + cJSON *val = cJSON_GetObjectItemCaseSensitive(item, "val"); + cJSON *mode = cJSON_GetObjectItemCaseSensitive(item, "mode"); + + if (!reg || !val) continue; + + if (!mode) { + i2c_write_reg(reg->valueint, val->valueint); + } else if (!strcasecmp(mode->valuestring, "or")) { + uint8_t data = i2c_read_reg(reg->valueint); + data |= (uint8_t) val->valueint; + i2c_write_reg(reg->valueint, data); + } else if (!strcasecmp(mode->valuestring, "and")) { + uint8_t data = i2c_read_reg(reg->valueint); + data &= (uint8_t) val->valueint; + i2c_write_reg(reg->valueint, data); + } + } + + return true; +} + +/**************************************************************************************** + * + */ +static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val) { + esp_err_t ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + + i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK); + i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); + i2c_master_write_byte(cmd, val, I2C_MASTER_NACK); + + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + + if (ret != ESP_OK) { + ESP_LOGW(TAG, "I2C write failed"); + } + + return ret; +} + +/**************************************************************************************** + * + */ +static uint8_t i2c_read_reg(uint8_t reg) { + esp_err_t ret; + uint8_t data = 0; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + + i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK); + i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_READ, I2C_MASTER_NACK); + i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK); + + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + + if (ret != ESP_OK) { + ESP_LOGW(TAG, "I2C read failed"); + } + + return data; +} + + diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 3ee4016f..6ac23cf4 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -93,7 +93,10 @@ static size_t dma_buf_frames; static pthread_t thread; static TaskHandle_t stats_task; static bool stats; -static int amp_gpio = -1; +static struct { + int gpio, active; +} amp_control = { -1, 1 }, + mute_control = { CONFIG_MUTE_GPIO, CONFIG_MUTE_GPIO_LEVEL }; DECLARE_ALL_MIN_MAX; @@ -129,14 +132,17 @@ static void jack_handler(bool inserted) { * amp GPIO */ static void set_amp_gpio(int gpio, char *value) { + char *p; + if (!strcasecmp(value, "amp")) { - amp_gpio = gpio; + amp_control.gpio = gpio; + if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1); - gpio_pad_select_gpio(amp_gpio); - gpio_set_direction(amp_gpio, GPIO_MODE_OUTPUT); - gpio_set_level(amp_gpio, 0); + gpio_pad_select_gpio(amp_control.gpio); + gpio_set_direction(amp_control.gpio, GPIO_MODE_OUTPUT); + gpio_set_level(amp_control.gpio, !amp_control.active); - LOG_INFO("setting amplifier GPIO %d", amp_gpio); + LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active); } } @@ -145,7 +151,7 @@ static void set_amp_gpio(int gpio, char *value) { */ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) { loglevel = level; - char *p, *dac_config, *spdif_config; + char *p; esp_err_t res; p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); @@ -186,12 +192,9 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch i2s_pin_config_t i2s_pin_config = { .bck_io_num = -1, .ws_io_num = -1, .data_out_num = -1, .data_in_num = -1 }; // get SPDIF configuration from NVS or compile -#ifdef CONFIG_SPDIF_CONFIG - spdif_config = strdup(CONFIG_SPDIF_CONFIG); -#else - spdif_config = config_alloc_get(NVS_TYPE_STR, "spdif_config"); - if (!spdif_config) spdif_config = strdup("bck=" STR(CONFIG_SPDIF_BCK_IO) ",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO)); -#endif + char *spdif_config = config_alloc_get_str("spdif_config", CONFIG_SPDIF_CONFIG, "bck=" STR(CONFIG_SPDIF_BCK_IO) + ",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO)); + if ((p = strcasestr(spdif_config, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1); // common I2S initialization @@ -237,12 +240,10 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch gpio_set_level(i2s_pin_config.data_out_num, 0); } -#ifdef CONFIG_DAC_CONFIG - dac_config = strdup(CONFIG_DAC_CONFIG); -#else - dac_config = config_alloc_get(NVS_TYPE_STR, "dac_config"); - if (!dac_config) dac_config = strdup("model=i2s,bck=" STR(CONFIG_I2S_BCK_IO) ",ws=" STR(CONFIG_I2S_WS_IO) ",do=" STR(CONFIG_I2S_DO_IO) ",sda=" STR(CONFIG_I2C_SDA) ",scl=" STR(CONFIG_I2C_SCL)); -#endif + char *dac_config = config_alloc_get_str("dac_config", CONFIG_DAC_CONFIG, "model=i2s,bck=" STR(CONFIG_I2S_BCK_IO) + ",ws=" STR(CONFIG_I2S_WS_IO) ",do=" STR(CONFIG_I2S_DO_IO) + ",sda=" STR(CONFIG_I2C_SDA) ",scl=" STR(CONFIG_I2C_SCL) + ",mute" STR(CONFIG_MUTE_GPIO)); char model[32] = "i2s"; if ((p = strcasestr(dac_config, "model")) != NULL) sscanf(p, "%*[^=]=%31[^,]", model); @@ -252,6 +253,13 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch if ((p = strcasestr(dac_config, "bck")) != NULL) i2s_pin_config.bck_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(dac_config, "ws")) != NULL) i2s_pin_config.ws_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(dac_config, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1); + if ((p = strcasestr(dac_config, "mute")) != NULL) { + char mute[8]; + sscanf(p, "%*[^=]=%7[^,]", mute); + mute_control.gpio = atoi(mute); + if ((p = strchr(mute, ':')) != NULL) mute_control.active = atoi(p + 1); + } + free(dac_config); i2s_config.sample_rate = output.current_sample_rate; @@ -263,9 +271,15 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch res |= i2s_driver_install(CONFIG_I2S_NUM, &i2s_config, 0, NULL); res |= i2s_set_pin(CONFIG_I2S_NUM, &i2s_pin_config); - - LOG_INFO("%s DAC using I2S bck:%d, ws:%d, do:%d", model, i2s_pin_config.bck_io_num, - i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num); + + if (res == ESP_OK && mute_control.gpio >= 0) { + gpio_pad_select_gpio(mute_control.gpio); + gpio_set_direction(mute_control.gpio, GPIO_MODE_OUTPUT); + gpio_set_level(mute_control.gpio, mute_control.active); + } + + LOG_INFO("%s DAC using I2S bck:%d, ws:%d, do:%d, mute:%d:%d (res:%d)", model, i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, + i2s_pin_config.data_out_num, mute_control.gpio, mute_control.active, res); } free(spdif_config); @@ -340,8 +354,8 @@ void output_close_i2s(void) { * change volume */ bool output_volume_i2s(unsigned left, unsigned right) { - adac->volume(left, right); - return false; + if (mute_control.gpio >= 0) gpio_set_level(mute_control.gpio, (left | right) ? !mute_control.active : mute_control.active); + return adac->volume(left, right); } /**************************************************************************************** @@ -422,8 +436,8 @@ static void *output_thread_i2s(void *arg) { LOG_INFO("Output state is %d", output.state); if (output.state == OUTPUT_OFF) { led_blink(LED_GREEN, 100, 2500); - if (amp_gpio != -1) gpio_set_level(amp_gpio, 0); - LOG_INFO("switching off amp GPIO %d", amp_gpio); + if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, !amp_control.active); + LOG_INFO("switching off amp GPIO %d", amp_control.gpio); } else if (output.state == OUTPUT_STOPPED) { adac->speaker(false); led_blink(LED_GREEN, 200, 1000); @@ -486,7 +500,7 @@ static void *output_thread_i2s(void *arg) { i2s_zero_dma_buffer(CONFIG_I2S_NUM); i2s_start(CONFIG_I2S_NUM); adac->power(ADAC_ON); - if (amp_gpio != -1) gpio_set_level(amp_gpio, 1); + if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, amp_control.active); } // this does not work well as set_sample_rates resets the fifos (and it's too early) diff --git a/components/squeezelite/tas57xx/dac_57xx.c b/components/squeezelite/tas57xx/dac_57xx.c index 4663d116..bf06d0d9 100644 --- a/components/squeezelite/tas57xx/dac_57xx.c +++ b/components/squeezelite/tas57xx/dac_57xx.c @@ -27,7 +27,7 @@ static bool init(char *config, int i2c_port_num); static void deinit(void); static void speaker(bool active); static void headset(bool active); -static void volume(unsigned left, unsigned right); +static bool volume(unsigned left, unsigned right); static void power(adac_power_e mode); const struct adac_s dac_tas57xx = { "TAS57xx", init, deinit, power, speaker, headset, volume }; @@ -61,7 +61,6 @@ static const struct tas57xx_cmd_s tas57xx_cmd[] = { static uint8_t tas57_addr; static int i2c_port; -static int mute_gpio = -1; static void dac_cmd(dac_cmd_e cmd, ...); static int tas57_detect(void); @@ -85,7 +84,6 @@ static bool init(char *config, int i2c_port_num) { if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1); - if ((p = strcasestr(config, "mute")) != NULL) mute_gpio = atoi(strchr(p, '=') + 1); i2c_param_config(i2c_port, &i2c_config); i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); @@ -113,20 +111,14 @@ static bool init(char *config, int i2c_port_num) { esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(i2c_cmd); - ESP_LOGI(TAG, "TAS57xx uses I2C sda:%d, scl:%d and mute: %d", i2c_config.sda_io_num, i2c_config.scl_io_num, mute_gpio); + ESP_LOGI(TAG, "TAS57xx uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num); - if (res == ESP_OK) { - if (mute_gpio >= 0) { - // init volume & mute - gpio_pad_select_gpio(mute_gpio); - gpio_set_direction(mute_gpio, GPIO_MODE_OUTPUT); - gpio_set_level(mute_gpio, 0); - } - return true; - } else { + if (res != ESP_OK) { ESP_LOGE(TAG, "could not intialize TAS57xx %d", res); return false; } + + return true; } /**************************************************************************************** @@ -139,10 +131,7 @@ static void deinit(void) { /**************************************************************************************** * change volume */ -static void volume(unsigned left, unsigned right) { - ESP_LOGI(TAG, "TAS57xx volume (L:%u R:%u)", left, right); - if (mute_gpio >= 0) gpio_set_level(mute_gpio, left || right); -} +static bool volume(unsigned left, unsigned right) { return false; } /**************************************************************************************** * power @@ -175,8 +164,7 @@ static void speaker(bool active) { /**************************************************************************************** * headset */ -static void headset(bool active) { -} +static void headset(bool active) { } /**************************************************************************************** * DAC specific commands diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 96016ff9..17f1bc25 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -21,6 +21,7 @@ menu "Squeezelite-ESP32" help Set logging level info|debug|sdebug endmenu + config JACK_LOCKED bool config BAT_LOCKED @@ -33,33 +34,59 @@ menu "Squeezelite-ESP32" bool config SPKFAULT_LOCKED bool + config MUTE_GPIO_LEVEL + int + default 0 + +# AGGREGATES - begin +# these parameters are "aggregates" that take precedence. The must have a default value config DAC_CONFIG string - default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14" if SQUEEZEAMP + default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP default "model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" if A1S + default "model=I2S,bck=26,ws=25,do=33,i2c=106,sda=21,scl=22" if TWATCH2020 + default "" config SPDIF_CONFIG string default "bck=33,ws=25,do=15" if SQUEEZEAMP - menu "Audio Output" - choice OUTPUT_TYPE - prompt "Output Type" - default BASIC_I2C_BT - help - Type of hardware platform - config SQUEEZEAMP - bool "SqueezeAMP" - select JACK_LOCKED - select BAT_LOCKED - select I2C_LOCKED - select LED_LOCKED - select SPKFAULT_LOCKED - config A1S - bool "ESP32-A1S module" - select I2C_LOCKED - config BASIC_I2C_BT - bool "Generic I2S & Bluetooth" - endchoice - + default "" + config SPI_CONFIG + string + default "dc=27,data=19,clk=18" if TWATCH2020 + default "" + config DISPLAY_CONFIG + string + default "SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip" if TWATCH2020 + default "" + config DAC_CONTROLSET + string + default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020 + default "" +# AGGREGATES - end + + choice OUTPUT_TYPE + prompt "Main system" + default BASIC_I2C_BT + help + Type of hardware platform + config SQUEEZEAMP + bool "SqueezeAMP" + select JACK_LOCKED + select BAT_LOCKED + select I2C_LOCKED + select LED_LOCKED + select SPKFAULT_LOCKED + config A1S + bool "ESP32-A1S module" + select I2C_LOCKED + config TWATCH2020 + bool "T-WATCH2020 by LilyGo" + select I2C_LOCKED + config BASIC_I2C_BT + bool "Generic I2S & Bluetooth" + endchoice + + menu "Audio settings" menu "DAC settings" visible if BASIC_I2C_BT menu "I2S settings" @@ -106,6 +133,10 @@ menu "Squeezelite-ESP32" default -1 help GPIO used to mute DAC (not used mostly, leave it to -1). + config MUTE_GPIO_LEVEL + int "Mute GPIO active level" + depends on MUTE_GPIO != -1 + default 1 endmenu menu "SPDIF settings" @@ -199,16 +230,17 @@ menu "Squeezelite-ESP32" endmenu menu "Display Screen" + depends on !TWATCH2020 config DISPLAY_CONFIG string "Screen configuraton" - default "" help Set parameters for display screen, leave empty for no screen - I2C,width=,height=[address=][,HFlip][,VFlip] - SPI,width=,height=,cs=[,HFlip][,VFlip] + I2C,driver=,width=,height=[address=][,HFlip][,VFlip][,rotate] + SPI,driver=,width=,height=,cs=[,HFlip][,VFlip][,rotate] endmenu menu "Various I/O" + visible if !TWATCH2020 config I2C_CONFIG string "I2C system configuration" default "" @@ -217,7 +249,6 @@ menu "Squeezelite-ESP32" sda=,scl=[,speed=][,port=<0|1>] config SPI_CONFIG string "SPI system configuration" - default "" help Set parameters of shared SPI interface data=,clk=[,d/c=][,host=<0|1|2>] @@ -226,7 +257,7 @@ menu "Squeezelite-ESP32" default "" help Set parameters of shared GPIO with special values. - =Vcc|GND|amp|jack[:0|1][,=Vcc|GND|amp|jack[:0|1]] + =Vcc|GND|amp[:0|1]|jack[:0|1][,=Vcc|GND|amp[:0|1]|jack[:0|1]] 'amp' => GPIO that is set when playback starts 'jack' => GPIO used for audio jack detection 'green', 'red' => GPIO for status LED @@ -236,39 +267,39 @@ menu "Squeezelite-ESP32" default "" help Set GPIO for rotary encoder (quadrature phase). See README on SqueezeESP32 project's GitHub for more details - A=,B=[,SW=gpio>[,volume][,longpress]] + A=,B=[,SW=gpio>[[,knobonly[=]|[,volume][,longpress]] endmenu menu "LED configuration" - visible if !SQUEEZEAMP + visible if !SQUEEZEAMP && !TWATCH2020 config LED_GREEN_GPIO int "Green led GPIO" - default -1 if !SQUEEZEAMP - default 12 if SQUEEZEAMP + default 12 if SQUEEZEAMP + default -1 help Set to -1 for no LED config LED_GREEN_GPIO_LEVEL int "Green led ON level" depends on LED_GREEN_GPIO != -1 default 0 if SQUEEZEAMP - default 1 if !SQUEEZEAMP + default 1 config LED_RED_GPIO int "Red led GPIO" - default -1 if !SQUEEZEAMP default 13 if SQUEEZEAMP + default -1 help Set to -1 for no LED config LED_RED_GPIO_LEVEL int "Red led ON level" depends on LED_RED_GPIO != -1 default 0 if SQUEEZEAMP - default 1 if !SQUEEZEAMP + default 1 endmenu menu "Audio JACK" - visible if !SQUEEZEAMP + visible if !SQUEEZEAMP && !TWATCH2020 config JACK_GPIO int "Jack insertion GPIO" - default -1 if !SQUEEZEAMP default 34 if SQUEEZEAMP + default -1 help GPIO to detect speaker jack insertion. Set to -1 for no detection. config JACK_GPIO_LEVEL @@ -277,11 +308,11 @@ menu "Squeezelite-ESP32" default 0 endmenu menu "Speaker Fault" - visible if !SQUEEZEAMP + visible if !SQUEEZEAMP && !TWATCH2020 config SPKFAULT_GPIO int "Speaker fault GPIO" - default -1 if !SQUEEZEAMP default 2 if SQUEEZEAMP + default -1 help GPIO to detect speaker fault condition. Set to -1 for no detection. config SPKFAULT_GPIO_LEVEL @@ -290,18 +321,18 @@ menu "Squeezelite-ESP32" default 0 endmenu menu "Battery measure" - visible if !SQUEEZEAMP + visible if !SQUEEZEAMP && !TWATCH2020 config BAT_CHANNEL int "Set channel (0..7)" - default -1 if !SQUEEZEAMP default 7 if SQUEEZEAMP + default -1 help Read a value every 10s on ADC1 on set Channel config BAT_SCALE string "Set scaling factor" depends on BAT_CHANNEL != -1 - default "" if !SQUEEZEAMP default "20.24" if SQUEEZEAMP + default "" help Set the scaling factor for this 12 bits ADC endmenu diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 27905c58..f6ac68d8 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -330,6 +330,9 @@ void register_default_nvs(){ ESP_LOGD(TAG,"Registering default value for key %s", "dac_config"); config_set_default(NVS_TYPE_STR, "dac_config", "", 0); + 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", "bat_config"); config_set_default(NVS_TYPE_STR, "bat_config", "", 0);