diff --git a/components/services/audio_controls.c b/components/services/audio_controls.c index 7d3029fb..20f96d28 100644 --- a/components/services/audio_controls.c +++ b/components/services/audio_controls.c @@ -88,7 +88,7 @@ void down(void *id, button_event_e event, button_press_e press, bool longpress) */ void actrls_init(int n, const actrls_config_t *config) { for (int i = 0; i < n; i++) { - button_create((void*) (config + i), config[i].gpio, config[i].type, config[i].pull, control_handler, config[i].long_press, config[i].shifter_gpio); + button_create((void*) (config + i), config[i].gpio, config[i].type, config[i].pull, config[i].debounce, control_handler, config[i].long_press, config[i].shifter_gpio); } } diff --git a/components/services/audio_controls.h b/components/services/audio_controls.h index dfba2358..6cbdb878 100644 --- a/components/services/audio_controls.h +++ b/components/services/audio_controls.h @@ -32,6 +32,7 @@ typedef struct { int gpio; int type; bool pull; + int debounce; int long_press; int shifter_gpio; actrls_action_e normal[2], longpress[2], shifted[2], longshifted[2]; // [0] keypressed, [1] keyreleased diff --git a/components/services/buttons.c b/components/services/buttons.c index a2ce1cb5..56123615 100644 --- a/components/services/buttons.c +++ b/components/services/buttons.c @@ -43,6 +43,7 @@ static int n_buttons = 0; static EXT_RAM_ATTR struct button_s { void *id; int gpio, index; + int debounce; button_handler handler; struct button_s *shifter; int long_press; @@ -63,7 +64,7 @@ static void IRAM_ATTR gpio_isr_handler(void* arg) struct button_s *button = (struct button_s*) arg; BaseType_t woken = pdFALSE; - if (xTimerGetPeriod(button->timer) > DEBOUNCE / portTICK_RATE_MS) xTimerChangePeriodFromISR(button->timer, DEBOUNCE / portTICK_RATE_MS, &woken); // does that restart the timer? + if (xTimerGetPeriod(button->timer) > button->debounce / portTICK_RATE_MS) xTimerChangePeriodFromISR(button->timer, button->debounce / portTICK_RATE_MS, &woken); // does that restart the timer? else xTimerResetFromISR(button->timer, &woken); // ESP_EARLY_LOGI(TAG, "INT gpio %u level %u", button->gpio, button->level); } @@ -149,7 +150,7 @@ void dummy_handler(void *id, button_event_e event, button_press_e press) { /**************************************************************************************** * Create buttons */ -void button_create(void *id, int gpio, int type, bool pull, button_handler handler, int long_press, int shifter_gpio) { +void button_create(void *id, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio) { static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static EXT_RAM_ATTR StackType_t xStack[BUTTON_STACK_SIZE] __attribute__ ((aligned (4))); @@ -159,7 +160,6 @@ void button_create(void *id, int gpio, int type, bool pull, button_handler handl if (!n_buttons) { button_evt_queue = xQueueCreate(10, sizeof(struct button_s)); - gpio_install_isr_service(0); xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons_thread", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer); } @@ -169,11 +169,12 @@ void button_create(void *id, int gpio, int type, bool pull, button_handler handl // set mandatory parameters buttons[n_buttons].id = id; buttons[n_buttons].gpio = gpio; + buttons[n_buttons].debounce = debounce ? debounce: DEBOUNCE; buttons[n_buttons].handler = handler; buttons[n_buttons].long_press = long_press; buttons[n_buttons].level = -1; buttons[n_buttons].type = type; - buttons[n_buttons].timer = xTimerCreate("buttonTimer", DEBOUNCE / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer); + buttons[n_buttons].timer = xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer); // little trick to find ourselves from queued copy buttons[n_buttons].index = n_buttons; diff --git a/components/services/buttons.h b/components/services/buttons.h index 1b7b9a8c..a40f214b 100644 --- a/components/services/buttons.h +++ b/components/services/buttons.h @@ -27,9 +27,10 @@ typedef enum { BUTTON_NORMAL, BUTTON_SHIFTED } button_press_e; typedef void (*button_handler)(void *id, button_event_e event, button_press_e mode, bool long_press); /* +set debounce to 0 for default (50ms) set long_press to 0 for no long-press set shifter_gpio to -1 for no shift NOTE: shifter buttons *must* be created before shiftee */ -void button_create(void *id, int gpio, int type, bool pull, button_handler handler, int long_press, int shifter_gpio); \ No newline at end of file +void button_create(void *id, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio); \ No newline at end of file diff --git a/components/services/monitor.c b/components/services/monitor.c index b17f102d..9942f297 100644 --- a/components/services/monitor.c +++ b/components/services/monitor.c @@ -15,12 +15,17 @@ #include "esp_system.h" #include "esp_log.h" #include "monitor.h" +#include "driver/gpio.h" +#include "buttons.h" +#define JACK_GPIO 34 #define MONITOR_TIMER (10*1000) static const char TAG[] = "monitor"; static TimerHandle_t monitor_timer; +void (*jack_handler_svc)(bool inserted); +bool jack_inserted_svc(void); /**************************************************************************************** * @@ -33,12 +38,39 @@ static void monitor_callback(TimerHandle_t xTimer) { heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); } +/**************************************************************************************** + * + */ +static void jack_handler_default(void *id, button_event_e event, button_press_e mode, bool long_press) { + ESP_LOGD(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed"); + if (jack_handler_svc) (*jack_handler_svc)(event == BUTTON_PRESSED); +} + +/**************************************************************************************** + * + */ +bool jack_inserted_svc (void) { +#ifdef JACK_GPIO + return !gpio_get_level(JACK_GPIO); +#else + return false; +#endif +} + /**************************************************************************************** * */ void monitor_svc_init(void) { ESP_LOGI(TAG, "Initializing monitoring"); +#ifdef JACK_GPIO + gpio_pad_select_gpio(JACK_GPIO); + gpio_set_direction(JACK_GPIO, GPIO_MODE_INPUT); + + // re-use button management for jack handler, it's a GPIO after all + button_create(NULL, JACK_GPIO, BUTTON_LOW, false, 250, jack_handler_default, 0, -1); +#endif + monitor_timer = xTimerCreate("monitor", MONITOR_TIMER / portTICK_RATE_MS, pdTRUE, NULL, monitor_callback); xTimerStart(monitor_timer, portMAX_DELAY); } diff --git a/components/services/monitor.h b/components/services/monitor.h index f6712855..d872aa26 100644 --- a/components/services/monitor.h +++ b/components/services/monitor.h @@ -20,3 +20,6 @@ #pragma once +extern void (*jack_handler_svc)(bool inserted); +extern bool jack_inserted_svc(void); + diff --git a/components/services/services.c b/components/services/services.c index 4704fe2d..6257bb8b 100644 --- a/components/services/services.c +++ b/components/services/services.c @@ -7,6 +7,8 @@ */ #include +#include "esp_log.h" +#include "driver/gpio.h" #include "battery.h" #include "led.h" #include "monitor.h" @@ -17,11 +19,24 @@ extern void led_svc_init(void); static const char TAG[] = "services"; +#ifdef CONFIG_SQUEEZEAMP +#define LED_GREEN_GPIO 12 +#define LED_RED_GPIO 13 +#endif + /**************************************************************************************** * */ void services_init(void) { + gpio_install_isr_service(0); + + ESP_LOGD(TAG,"Configuring LEDs"); + led_svc_init(); +#ifdef CONFIG_SQUEEZEAMP + led_config(LED_GREEN, LED_GREEN_GPIO, 0); + led_config(LED_RED, LED_RED_GPIO, 0); +#endif + battery_svc_init(); monitor_svc_init(); - led_svc_init(); } diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index cfc669d0..a33c00fc 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -49,6 +49,7 @@ sure that using rate_delay would fix that #include #include "time.h" #include "led.h" +#include "monitor.h" #define LOCK mutex_lock(outputbuf->mutex) #define UNLOCK mutex_unlock(outputbuf->mutex) @@ -121,7 +122,6 @@ static u8_t *obuf; static frames_t oframes; static bool spdif; static size_t dma_buf_frames; -static int jack_status = -1; // 0 = inserted DECLARE_ALL_MIN_MAX; @@ -132,6 +132,7 @@ static void *output_thread_i2s_stats(); static void dac_cmd(dac_cmd_e cmd, ...); static int tas57_detect(void); static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count); +static void (*jack_handler_chain)(bool inserted); #ifdef CONFIG_SQUEEZEAMP @@ -201,6 +202,19 @@ static u8_t tas57_addr; #endif +/**************************************************************************************** + * jack insertion handler + */ +static void jack_handler(bool inserted) { + // jack detection bounces a bit but that seems fine + if (jack_mutes_amp) { + LOG_INFO("switching amplifier %s", inserted ? "ON" : "OFF"); + if (inserted) dac_cmd(DAC_ANALOGUE_OFF); + else dac_cmd(DAC_ANALOGUE_ON); + } + if (jack_handler_chain) (jack_handler_chain)(inserted); +} + /**************************************************************************************** * Initialize the DAC output */ @@ -209,9 +223,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch #ifdef TAS57xx LOG_INFO("Initializing TAS57xx "); - gpio_pad_select_gpio(JACK_GPIO); - gpio_set_direction(JACK_GPIO, GPIO_MODE_INPUT); - + adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_0); @@ -335,6 +347,12 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch dac_cmd(DAC_STANDBY); + jack_handler_chain = jack_handler_svc; + jack_handler_svc = jack_handler; + + if (jack_mutes_amp && jack_inserted_svc()) dac_cmd(DAC_ANALOGUE_OFF); + else dac_cmd(DAC_ANALOGUE_ON); + esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); cfg.thread_name= "output_i2s"; @@ -451,19 +469,10 @@ static void *output_thread_i2s() { while (running) { TIME_MEASUREMENT_START(timer_start); -#ifdef TAS57xx - // handle jack insertion as a polling function (to avoid to have to do de-bouncing) - if (gpio_get_level(JACK_GPIO) != jack_status) { - jack_status = gpio_get_level(JACK_GPIO); - if (jack_mutes_amp) { - dac_cmd(jack_status ? DAC_ANALOGUE_ON : DAC_ANALOGUE_OFF); - LOG_INFO("Changing jack status %d", jack_status); - } - } -#endif + LOCK; - // manage led display + // manage led display & analogue if (state != output.state) { LOG_INFO("Output state is %d", output.state); if (output.state == OUTPUT_OFF) led_blink(LED_GREEN, 100, 2500); @@ -474,7 +483,7 @@ static void *output_thread_i2s() { led_blink(LED_GREEN, 200, 1000); } else if (output.state == OUTPUT_RUNNING) { #ifdef TAS57xx - if (!jack_mutes_amp || (jack_mutes_amp && jack_status)) dac_cmd(DAC_ANALOGUE_ON); + if (!jack_mutes_amp || !jack_inserted_svc()) dac_cmd(DAC_ANALOGUE_ON); #endif led_on(LED_GREEN); } diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index f4df961f..7c0c0a31 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -62,6 +62,7 @@ Contains the freeRTOS task and all necessary support #include "cJSON.h" #include "nvs_utilities.h" #include "cmd_system.h" +#include "monitor.h" #ifndef RECOVERY_APPLICATION #define RECOVERY_APPLICATION 0 @@ -70,12 +71,7 @@ Contains the freeRTOS task and all necessary support #ifndef SQUEEZELITE_ESP32_RELEASE_URL #define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases" #endif -#ifdef CONFIG_SQUEEZEAMP -#define JACK_GPIO 34 -#define JACK_LEVEL !gpio_get_level(JACK_GPIO)?"1":"0" -#else -#define JACK_LEVEL "N/A" -#endif + #define STR_OR_BLANK(p) p==NULL?"":p #define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} /* objects used to manipulate the main queue of events */ @@ -455,7 +451,7 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){ cJSON_AddNumberToObject(root,"recovery", RECOVERY_APPLICATION ); cJSON_AddItemToObject(root, "ota_dsc", cJSON_CreateString(ota_get_status())); cJSON_AddNumberToObject(root,"ota_pct", ota_get_pct_complete() ); - cJSON_AddItemToObject(root, "Jack", cJSON_CreateString(JACK_LEVEL)); + cJSON_AddItemToObject(root, "Jack", cJSON_CreateString(jack_inserted_svc() ? "1" : "0")); cJSON_AddNumberToObject(root,"Voltage", adc1_get_raw(ADC1_CHANNEL_7) / 4095. * (10+174)/10. * 1.1); cJSON_AddNumberToObject(root,"disconnect_count", num_disconnect ); cJSON_AddNumberToObject(root,"avg_conn_time", num_disconnect>0?(total_connected_time/num_disconnect):0 ); diff --git a/main/esp_app_main.c b/main/esp_app_main.c index b09188bb..90282b0b 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -65,13 +65,6 @@ static const char TAG[] = "esp_app_main"; #define DEFAULT_HOST_NAME "squeezelite" char * fwurl = NULL; -#ifdef CONFIG_SQUEEZEAMP -#define LED_GREEN_GPIO 12 -#define LED_RED_GPIO 13 -#else -#define LED_GREEN_GPIO -1 -#define LED_RED_GPIO -1 -#endif static bool bWifiConnected=false; extern const uint8_t server_cert_pem_start[] asm("_binary_github_pem_start"); extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end"); @@ -80,15 +73,15 @@ extern void services_init(void); static const actrls_config_t board_1[] = { // normal long shifted long shifted - { 4, BUTTON_LOW, true, 1000, -1, {ACTRLS_VOLUP, ACTRLS_NONE}, {ACTRLS_PREV, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE} }, - { 5, BUTTON_LOW, true, 1000, 4, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_TOGGLE, ACTRLS_NONE}, {BCTRLS_DOWN, ACTRLS_NONE} }, + { 4, BUTTON_LOW, true, 0, 1000, -1, {ACTRLS_VOLUP, ACTRLS_NONE}, {ACTRLS_PREV, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE} }, + { 5, BUTTON_LOW, true, 0, 1000, 4, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_TOGGLE, ACTRLS_NONE}, {BCTRLS_DOWN, ACTRLS_NONE} }, }; static const actrls_config_t board_2[] = { // normal long shifted long shifted - { 21, BUTTON_LOW, true, 1000, -1, {ACTRLS_TOGGLE, ACTRLS_NONE}, {ACTRLS_STOP, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE} }, - { 18, BUTTON_LOW, true, 1000, 21, {ACTRLS_VOLUP, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_FWD, ACTRLS_PLAY} }, - { 19, BUTTON_LOW, true, 1000, 21, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_PREV, ACTRLS_NONE}, {ACTRLS_REW, ACTRLS_PLAY} }, + { 21, BUTTON_LOW, true, 0, 1000, -1, {ACTRLS_TOGGLE, ACTRLS_NONE}, {ACTRLS_STOP, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE} }, + { 18, BUTTON_LOW, true, 0, 1000, 21, {ACTRLS_VOLUP, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_FWD, ACTRLS_PLAY} }, + { 19, BUTTON_LOW, true, 0, 1000, 21, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_PREV, ACTRLS_NONE}, {ACTRLS_REW, ACTRLS_PLAY} }, }; static const struct { @@ -372,6 +365,9 @@ void app_main() ESP_LOGI(TAG,"Setting up config subsystem."); config_init(); + ESP_LOGD(TAG,"Configuring services"); + services_init(); + ESP_LOGI(TAG,"Registering default values"); register_default_nvs(); @@ -383,7 +379,6 @@ void app_main() ESP_LOGD(TAG,"Getting firmware OTA URL (if any)"); fwurl = process_ota_url(); - ESP_LOGD(TAG,"Getting value for WM bypass, nvs 'bypass_wm'"); char * bypass_wm = config_alloc_get_default(NVS_TYPE_STR, "bypass_wm", "0", 0); if(bypass_wm==NULL) @@ -395,13 +390,6 @@ void app_main() bypass_wifi_manager=(strcmp(bypass_wm,"1")==0 ||strcasecmp(bypass_wm,"y")==0); } - services_init(); - - ESP_LOGD(TAG,"Configuring Green led"); - led_config(LED_GREEN, LED_GREEN_GPIO, 0); - ESP_LOGD(TAG,"Configuring Red led"); - led_config(LED_RED, LED_RED_GPIO, 0); - char *board_index = config_alloc_get_default(NVS_TYPE_STR, "board_index", NULL, 0); if (board_index) { ESP_LOGD(TAG,"Initializing audio control buttons index %u", atoi(board_index));