diff --git a/build-scripts/ESP32-A1S-sdkconfig.defaults b/build-scripts/ESP32-A1S-sdkconfig.defaults index 0a1cca2f..df35eb8b 100644 --- a/build-scripts/ESP32-A1S-sdkconfig.defaults +++ b/build-scripts/ESP32-A1S-sdkconfig.defaults @@ -115,7 +115,7 @@ CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1" CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 -CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30" +CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 4ff2980f..ae460f33 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -116,7 +116,7 @@ CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1" CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 -CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30" +CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y diff --git a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults index 802f3647..96d0fe43 100644 --- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults @@ -128,7 +128,7 @@ CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1" CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 -CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30" +CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y diff --git a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults index 0b99d875..cfae6f09 100644 --- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults @@ -127,7 +127,7 @@ CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1" CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 -CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30" +CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y diff --git a/components/services/audio_controls.c b/components/services/audio_controls.c index f2447993..43a31930 100644 --- a/components/services/audio_controls.c +++ b/components/services/audio_controls.c @@ -11,6 +11,8 @@ #include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" #include "esp_system.h" #include "esp_log.h" #include "cJSON.h" @@ -35,6 +37,7 @@ static esp_err_t actrls_process_action (const cJSON * member, actrls_config_t *c static esp_err_t actrls_init_json(const char *profile_name, bool create); static void control_rotary_handler(void *client, rotary_event_e event, bool long_press); +static void rotary_timer( TimerHandle_t xTimer ); static const actrls_config_map_t actrls_config_map[] = { @@ -70,6 +73,9 @@ static actrls_ir_handler_t *default_ir_handler, *current_ir_handler; static struct { bool long_state; bool volume_lock; + TimerHandle_t timer; + bool click_pending; + int left_count; } rotary; static const struct ir_action_map_s{ @@ -132,8 +138,16 @@ esp_err_t actrls_init(const char *profile_name) { if ((p = strcasestr(config, "A")) != NULL) A = atoi(strchr(p, '=') + 1); if ((p = strcasestr(config, "B")) != NULL) B = atoi(strchr(p, '=') + 1); if ((p = strcasestr(config, "SW")) != NULL) SW = atoi(strchr(p, '=') + 1); - if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true; - if ((p = strcasestr(config, "longpress")) != NULL) longpress = 1000; + if ((p = strcasestr(config, "knobonly")) != NULL) { + p = strchr(p, '='); + int double_press = p ? atoi(p + 1) : 350; + rotary.timer = xTimerCreate("knobTimer", double_press / portTICK_RATE_MS, pdFALSE, NULL, rotary_timer); + longpress = 500; + ESP_LOGI(TAG, "single knob navigation %d", double_press); + } else { + if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true; + if ((p = strcasestr(config, "longpress")) != NULL) longpress = 1000; + } // create rotary (no handling of long press) err = create_rotary(NULL, A, B, SW, longpress, control_rotary_handler) ? ESP_OK : ESP_FAIL; @@ -222,17 +236,42 @@ static void control_rotary_handler(void *client, rotary_event_e event, bool long switch(event) { case ROTARY_LEFT: - if (rotary.long_state) action = ACTRLS_PREV; + if (rotary.timer) { + if (rotary.left_count) { + action = KNOB_LEFT; + // need to add a left button the first time + if (rotary.left_count == 1) (*current_controls[KNOB_LEFT])(true); + } + xTimerStart(rotary.timer, 20 / portTICK_RATE_MS); + rotary.left_count++; + } + else if (rotary.long_state) action = ACTRLS_PREV; else if (rotary.volume_lock) action = ACTRLS_VOLDOWN; else action = KNOB_LEFT; break; case ROTARY_RIGHT: - if (rotary.long_state) action = ACTRLS_NEXT; + if (rotary.timer) { + if (rotary.left_count == 1) { + action = ACTRLS_PAUSE; + rotary.left_count = 0; + xTimerStop(rotary.timer, 0); + } else action = KNOB_RIGHT; + } + else if (rotary.long_state) action = ACTRLS_NEXT; else if (rotary.volume_lock) action = ACTRLS_VOLUP; else action = KNOB_RIGHT; break; case ROTARY_PRESSED: - if (long_press) rotary.long_state = !rotary.long_state; + if (rotary.timer) { + if (long_press) action = ACTRLS_PLAY; + else if (rotary.click_pending) { + action = BCTRLS_LEFT; + xTimerStop(rotary.timer, 0); + } + else xTimerStart(rotary.timer, 20 / portTICK_RATE_MS); + rotary.click_pending = !rotary.click_pending; + } + else if (long_press) rotary.long_state = !rotary.long_state; else if (rotary.volume_lock) action = ACTRLS_TOGGLE; else action = KNOB_PUSH; break; @@ -243,6 +282,19 @@ static void control_rotary_handler(void *client, rotary_event_e event, bool long if (action != ACTRLS_NONE) (*current_controls[action])(pressed); } +/**************************************************************************************** + * + */ +static void rotary_timer( TimerHandle_t xTimer ) { + if (rotary.click_pending) { + (*current_controls[KNOB_PUSH])(true); + rotary.click_pending = false; + } else if (rotary.left_count) { + if (rotary.left_count == 1) (*current_controls[KNOB_LEFT])(true); + rotary.left_count = 0; + } +} + /**************************************************************************************** * */ diff --git a/components/squeezelite/controls.c b/components/squeezelite/controls.c index 7c1ff03a..508e549d 100644 --- a/components/squeezelite/controls.c +++ b/components/squeezelite/controls.c @@ -49,6 +49,7 @@ struct IR_header { static in_addr_t server_ip; static u16_t server_hport; static u16_t server_cport; +static int cli_sock = -1; static u8_t mac[6]; static void (*chained_notify)(in_addr_t, u16_t, u16_t); static bool raw_mode; @@ -243,38 +244,44 @@ const actrls_t LMS_controls = { * */ static void cli_send_cmd(char *cmd) { - char packet[64]; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int len, sock = socket(AF_INET, SOCK_STREAM, 0); + char packet[96]; + int len; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = server_ip; - addr.sin_port = htons(server_cport); - - if (connect(sock, (struct sockaddr *) &addr, addrlen) < 0) { - LOG_ERROR("unable to connect to server %s:%hu with cli", inet_ntoa(server_ip), server_cport); - return; - } - len = sprintf(packet, "%02x:%02x:%02x:%02x:%02x:%02x %s\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], cmd); LOG_DEBUG("sending command %s at %s:%hu", packet, inet_ntoa(server_ip), server_cport); - if (send(sock, packet, len, 0) < 0) { + if (send(cli_sock, packet, len, MSG_DONTWAIT) < 0) { LOG_WARN("cannot send CLI %s", packet); } - - closesocket(sock); + + // need to empty the RX buffer otherwise we'll lock the TCP/IP stack + len = recv(cli_sock, packet, 96, MSG_DONTWAIT); } /**************************************************************************************** * Notification when server changes */ static void notify(in_addr_t ip, u16_t hport, u16_t cport) { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + server_ip = ip; server_hport = hport; server_cport = cport; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = server_ip; + addr.sin_port = htons(server_cport); + + // close existing CLI connection and open new one + if (cli_sock >= 0) closesocket(cli_sock); + cli_sock = socket(AF_INET, SOCK_STREAM, 0); + + if (connect(cli_sock, (struct sockaddr *) &addr, addrlen) < 0) { + LOG_ERROR("unable to connect to server %s:%hu with cli", inet_ntoa(server_ip), server_cport); + cli_sock = -1; + } + LOG_INFO("notified server %s hport %hu cport %hu", inet_ntoa(ip), hport, cport); if (chained_notify) (*chained_notify)(ip, hport, cport); diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index ed64fbaa..4af7afd8 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -646,12 +646,13 @@ static void grfb_handler(u8_t *data, int len) { pkt->brightness = htons(pkt->brightness); xSemaphoreTake(displayer.mutex, portMAX_DELAY); - - if (pkt->brightness < 0) { + + // LMS driver sends 0..5 value, we assume driver is highly log + if (pkt->brightness <= 0) { GDS_DisplayOff(display); } else { GDS_DisplayOn(display); - GDS_SetContrast(display, pkt->brightness); + GDS_SetContrast(display, 255 * powf(pkt->brightness / 5.0f, 3)); } xSemaphoreGive(displayer.mutex); diff --git a/components/squeezelite/equalizer.c b/components/squeezelite/equalizer.c index ac038ef9..f0364257 100644 --- a/components/squeezelite/equalizer.c +++ b/components/squeezelite/equalizer.c @@ -26,14 +26,16 @@ static struct { * open equalizer */ void equalizer_open(u32_t sample_rate) { + // in any case, need to clear update flag + equalizer.update = false; + if (sample_rate != 11025 && sample_rate != 22050 && sample_rate != 44100 && sample_rate != 48000) { LOG_WARN("equalizer only supports 11025, 22050, 44100 and 48000 sample rates, not %u", sample_rate); return; } equalizer.handle = esp_equalizer_init(2, sample_rate, EQ_BANDS, 0); - equalizer.update = false; - + if (equalizer.handle) { bool active = false; diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index bf065e7a..ab34d109 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -50,7 +50,7 @@ var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases var recovery = false; var enableAPTimer = true; var enableStatusTimer = true; -var commandHeader = 'squeezelite -b 500:2000 -d all=info '; +var commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W'; var pname, ver, otapct, otadsc; var blockAjax = false; var blockFlashButton = false; diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 8c235350..a2813831 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -232,7 +232,7 @@

Squeezelite command to run

- +
diff --git a/plugin/SqueezeESP32.zip b/plugin/SqueezeESP32.zip index f5f08c89..1d8b8c75 100644 Binary files a/plugin/SqueezeESP32.zip and b/plugin/SqueezeESP32.zip differ diff --git a/plugin/SqueezeESP32/Graphics.pm b/plugin/SqueezeESP32/Graphics.pm index 2597a557..b23cf95b 100644 --- a/plugin/SqueezeESP32/Graphics.pm +++ b/plugin/SqueezeESP32/Graphics.pm @@ -88,7 +88,7 @@ sub displayWidth { } sub brightnessMap { - return (65535, 10, 50, 100, 200); + return (0 .. 5); } =comment diff --git a/plugin/SqueezeESP32/install.xml b/plugin/SqueezeESP32/install.xml index a835ce52..7d20081e 100644 --- a/plugin/SqueezeESP32/install.xml +++ b/plugin/SqueezeESP32/install.xml @@ -10,6 +10,6 @@ PLUGIN_SQUEEZEESP32 PLUGIN_SQUEEZEESP32_DESC Plugins::SqueezeESP32::Plugin - 0.93 + 0.94 Philippe diff --git a/plugin/repo.xml b/plugin/repo.xml index 52afc5ca..f13e8830 100644 --- a/plugin/repo.xml +++ b/plugin/repo.xml @@ -1,10 +1,10 @@ - + https://github.com/sle118/squeezelite-esp32 Philippe - 42e9a5713355c5c7b8b318f4254a183e9bb86b8f + a9bf10b47d13508ba051e4067cdabc2c283f4824 philippe_44@outlook.com SqueezeESP32 additional player id (100) http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip