diff --git a/.gitmodules b/.gitmodules
index 928a2595..2dfa609a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,7 @@
[submodule "components/lws-esp32"]
path = components/lws-esp32
url = https://github.com/huming2207/lws-esp32.git
+[submodule "components/telnet/libtelnet"]
+ path = components/telnet/libtelnet
+ url = https://github.com/seanmiddleditch/libtelnet
+ branch = develop
diff --git a/README.md b/README.md
index e2584a8e..0e34b595 100644
--- a/README.md
+++ b/README.md
@@ -47,8 +47,20 @@ The NVS parameter "metadata_config" sets how metadata is displayed for AirPlay a
- 'format' can contain free text and any of the 3 keywords %artist%, %album%, %title%. Using that format string, the keywords are replaced by their value to build the string to be displayed. Note that the plain text following a keyword that happens to be empty during playback of a track will be removed. For example, if you have set format=%artist% - %title% and there is no artist in the metadata then only
will be displayed not " - ".
-### Vcc GPIO
-The parameter "Vcc_GPIO" is a comma-separated list of GPIO that will be configured as output with their value set to 1 (Vcc) at boot. Be careful because there is no conflict checks being made wrt which GPIO you're changing, so you might damage your board or create a conflict here.
+### Set GPIO
+The parameter "set_GPIO" is use to set assign GPIO to various functions.
+
+GPIO can be set to GND provide or Vcc at boot. This is convenient to power devices that consume less than 40mA from the side connector. Be careful because there is no conflict checks being made wrt which GPIO you're changing, so you might damage your board or create a conflict here.
+
+This parameter can use used as well to assign a GPIO that will be set to 1 when playback starts and wil be reset to 0 when squeezelite becomes idle. The idle timeout is set on the squeezelite command line through -C \
+
+Finally, if you have an audio jack that supports insertion (set to GND when inserted), you can specify whch GPIO it's connected to. Using the parameter jack_mutes_amp allows to mute the amp when headset (e.g.) is inserted.
+
+Syntax is:
+
+```
+=Vcc|GND|amp|jack[,=Vcc|GND|amp|jack]
+```
### Buttons
Buttons are described using a JSON string with the following syntax
@@ -81,7 +93,7 @@ Where (all parameters are optionals except gpio)
- "shifted": action to take when a button is pressed/released and shifted (see above/below)
- "longshifted": action to take when a button is long-pressed/released and shifted (see above/below)
-Where is either the name of another configuration to load or one amongst
+Where \ is either the name of another configuration to load or one amongst
ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT
@@ -95,7 +107,7 @@ For example a config named "buttons" :
```
Defines two buttons
- first on GPIO 4, active low. When pressed, it triggers a volume down command. When pressed more than 1000ms, it changes the button configuration for the one named "buttons_remap"
-- second on GPIO 5, acive low. When pressed it triggers a volume up command. If first button is pressed together with this button, then a play/pause toggle command is generated.
+- second on GPIO 5, active low. When pressed it triggers a volume up command. If first button is pressed together with this button, then a play/pause toggle command is generated.
While the config named "buttons_remap"
```
diff --git a/build-scripts/16M-sdkconfig.defaults b/build-scripts/16M-sdkconfig.defaults
index 21c797ea..a20ceb7f 100644
--- a/build-scripts/16M-sdkconfig.defaults
+++ b/build-scripts/16M-sdkconfig.defaults
@@ -144,4 +144,4 @@ CONFIG_DEFAULT_AP_PASSWORD="squeezelite"
CONFIG_DEFAULT_AP_IP="192.168.4.1"
CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1"
CONFIG_DEFAULT_AP_NETMASK="255.255.255.0"
-CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
diff --git a/build-scripts/I2S-16MFlash-sdkconfig.defaults b/build-scripts/I2S-16MFlash-sdkconfig.defaults
index f982c87c..1f6bdeca 100644
--- a/build-scripts/I2S-16MFlash-sdkconfig.defaults
+++ b/build-scripts/I2S-16MFlash-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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
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 2d3a107e..9379b3c9 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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/NonOTA-16M-sdkconfig.defaults b/build-scripts/NonOTA-16M-sdkconfig.defaults
index ce26095f..f58dbbaf 100644
--- a/build-scripts/NonOTA-16M-sdkconfig.defaults
+++ b/build-scripts/NonOTA-16M-sdkconfig.defaults
@@ -140,4 +140,4 @@ CONFIG_DEFAULT_AP_PASSWORD="squeezelite"
CONFIG_DEFAULT_AP_IP="192.168.4.1"
CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1"
CONFIG_DEFAULT_AP_NETMASK="255.255.255.0"
-CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
diff --git a/build-scripts/NonOTA-I2S-16MFlash-sdkconfig.defaults b/build-scripts/NonOTA-I2S-16MFlash-sdkconfig.defaults
index 5283b14d..1a1db3e7 100644
--- a/build-scripts/NonOTA-I2S-16MFlash-sdkconfig.defaults
+++ b/build-scripts/NonOTA-I2S-16MFlash-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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults
index 6a3e3196..6cf46920 100644
--- a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults
+++ b/build-scripts/NonOTA-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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults
index 37e8ad92..554740b2 100644
--- a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults
+++ b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults
@@ -104,7 +104,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
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 087d38c4..0282d8f4 100644
--- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults
+++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults
@@ -104,7 +104,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
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 36c9c8cb..1104c151 100644
--- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults
+++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults
@@ -71,7 +71,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
diff --git a/build-scripts/squeezelite-esp32-16M-sdkconfig.defaults b/build-scripts/squeezelite-esp32-16M-sdkconfig.defaults
index 7af4b57e..762373f5 100644
--- a/build-scripts/squeezelite-esp32-16M-sdkconfig.defaults
+++ b/build-scripts/squeezelite-esp32-16M-sdkconfig.defaults
@@ -138,4 +138,4 @@ CONFIG_DEFAULT_AP_PASSWORD="squeezelite"
CONFIG_DEFAULT_AP_IP="192.168.4.1"
CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1"
CONFIG_DEFAULT_AP_NETMASK="255.255.255.0"
-CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info"
diff --git a/build-scripts/squeezelite-esp32-I2S-16MFlash-sdkconfig.defaults b/build-scripts/squeezelite-esp32-I2S-16MFlash-sdkconfig.defaults
index 8c15698c..14870371 100644
--- a/build-scripts/squeezelite-esp32-I2S-16MFlash-sdkconfig.defaults
+++ b/build-scripts/squeezelite-esp32-I2S-16MFlash-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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/squeezelite-esp32-I2S-4MFlash-NOAirplay-sdkconfig.defaults b/build-scripts/squeezelite-esp32-I2S-4MFlash-NOAirplay-sdkconfig.defaults
index 7165d208..3cf20999 100644
--- a/build-scripts/squeezelite-esp32-I2S-4MFlash-NOAirplay-sdkconfig.defaults
+++ b/build-scripts/squeezelite-esp32-I2S-4MFlash-NOAirplay-sdkconfig.defaults
@@ -112,7 +112,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/squeezelite-esp32-I2S-4MFlash-sdkconfig.defaults b/build-scripts/squeezelite-esp32-I2S-4MFlash-sdkconfig.defaults
index add723cc..90cf3dd7 100644
--- a/build-scripts/squeezelite-esp32-I2S-4MFlash-sdkconfig.defaults
+++ b/build-scripts/squeezelite-esp32-I2S-4MFlash-sdkconfig.defaults
@@ -132,7 +132,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/build-scripts/squeezelite-esp32-SqueezeAmp-sdkconfig.defaults b/build-scripts/squeezelite-esp32-SqueezeAmp-sdkconfig.defaults
index 86a5244d..d2035933 100644
--- a/build-scripts/squeezelite-esp32-SqueezeAmp-sdkconfig.defaults
+++ b/build-scripts/squeezelite-esp32-SqueezeAmp-sdkconfig.defaults
@@ -103,7 +103,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 "
+CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
diff --git a/components/cmd_nvs/cmd_nvs.c b/components/cmd_nvs/cmd_nvs.c
index 3c763757..bbd59600 100644
--- a/components/cmd_nvs/cmd_nvs.c
+++ b/components/cmd_nvs/cmd_nvs.c
@@ -29,7 +29,7 @@ extern "C" {
static const char *ARG_TYPE_STR = "type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob";
-static const char * TAG = "platform_esp32";
+static const char * TAG = "cmd_nvs";
static struct {
struct arg_str *key;
diff --git a/components/driver_bt/bt_app_core.c b/components/driver_bt/bt_app_core.c
index 48f57e2f..aa628f27 100644
--- a/components/driver_bt/bt_app_core.c
+++ b/components/driver_bt/bt_app_core.c
@@ -18,7 +18,7 @@
#include "freertos/queue.h"
#include "freertos/task.h"
-static const char * TAG = "platform_esp32";
+static const char * TAG = "btappcore";
static void bt_app_task_handler(void *arg);
static bool bt_app_send_msg(bt_app_msg_t *msg);
diff --git a/components/driver_bt/bt_app_sink.c b/components/driver_bt/bt_app_sink.c
index 56cd4ca3..cff29501 100644
--- a/components/driver_bt/bt_app_sink.c
+++ b/components/driver_bt/bt_app_sink.c
@@ -162,7 +162,7 @@ static bool cmd_handler(bt_sink_cmd_t cmd, ...) {
va_end(args);
return false;
}
-
+
// now handle events for display
switch(cmd) {
case BT_SINK_AUDIO_STARTED:
@@ -175,7 +175,7 @@ static bool cmd_handler(bt_sink_cmd_t cmd, ...) {
displayer_control(DISPLAYER_TIMER_RUN);
break;
case BT_SINK_STOP:
- // not sure of difference between pause and stop for displayer
+ // not sure of difference between pause and stop for displayer
case BT_SINK_PAUSE:
displayer_control(DISPLAYER_TIMER_PAUSE);
break;
@@ -397,7 +397,7 @@ void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_param
bt_av_playback_changed();
break;
case ESP_AVRC_RN_PLAY_POS_CHANGED:
- ESP_LOGI(BT_AV_TAG, "Play position changed: %d-ms", event_parameter->play_pos);
+ ESP_LOGD(BT_AV_TAG, "Play position changed: %d (ms)", event_parameter->play_pos);
(*bt_app_a2d_cmd_cb)(BT_SINK_PROGRESS, event_parameter->play_pos, -1);
bt_av_play_pos_changed();
break;
@@ -440,7 +440,7 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
break;
}
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
- ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
+ ESP_LOGD(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
break;
}
diff --git a/components/raop/raop.c b/components/raop/raop.c
index 1f06810f..565e281c 100644
--- a/components/raop/raop.c
+++ b/components/raop/raop.c
@@ -542,7 +542,7 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
ctx->rtp = rtp.ctx;
- if (cport * tport * rtp.cport * rtp.tport * rtp.aport && rtp.ctx) {
+ if ( (cport * tport * rtp.cport * rtp.tport * rtp.aport) != 0 && rtp.ctx) {
char *transport;
asprintf(&transport, "RTP/AVP/UDP;unicast;mode=record;control_port=%u;timing_port=%u;server_port=%u", rtp.cport, rtp.tport, rtp.aport);
LOG_DEBUG("[%p]: audio=(%hu:%hu), timing=(%hu:%hu), control=(%hu:%hu)", ctx, 0, rtp.aport, tport, rtp.tport, cport, rtp.cport);
@@ -630,9 +630,10 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
} else if (body && (p = strcasestr(body, "progress")) != NULL) {
int start, current, stop = 0;
+ // we want ms, not s
sscanf(p, "%*[^:]:%u/%u/%u", &start, ¤t, &stop);
- current = (current - start) / 44100;
- if (stop) stop = (stop - start) / 44100;
+ current = ((current - start) / 44100) * 1000;
+ if (stop) stop = ((stop - start) / 44100) * 1000;
else stop = -1;
LOG_INFO("[%p]: SET PARAMETER progress %u/%u %s", ctx, current, stop, p);
success = ctx->cmd_cb(RAOP_PROGRESS, current, stop);
diff --git a/components/raop/rtp.c b/components/raop/rtp.c
index fbb9e2de..beccdda9 100644
--- a/components/raop/rtp.c
+++ b/components/raop/rtp.c
@@ -564,7 +564,7 @@ static void *rtp_thread_func(void *arg) {
for (i = 0; i < 3; i++) {
if (ctx->rtp_sockets[i].sock > sock) sock = ctx->rtp_sockets[i].sock;
- // send synchro requets 3 times
+ // send synchro request 3 times
ntp_sent = rtp_request_timing(ctx);
}
@@ -638,7 +638,9 @@ static void *rtp_thread_func(void *arg) {
u16_t flags = ntohs(*(u16_t*)(pktp+2));
u32_t remote_gap = NTP2MS(remote - ctx->timing.remote);
+ // something is wrong and if we are supposed to be NTP synced, better ask for re-sync
if (remote_gap > 10000) {
+ if (ctx->synchro.status & NTP_SYNC) rtp_request_timing(ctx);
LOG_WARN("discarding remote timing information %u", remote_gap);
break;
}
@@ -683,8 +685,9 @@ static void *rtp_thread_func(void *arg) {
u64_t remote =(((u64_t) ntohl(*(u32_t*)(pktp+16))) << 32) + ntohl(*(u32_t*)(pktp+20));
u32_t roundtrip = gettime_ms() - reference;
- // better discard sync packets when roundtrip is suspicious
+ // better discard sync packets when roundtrip is suspicious and ask for another one
if (roundtrip > 100) {
+ rtp_request_timing(ctx);
LOG_WARN("[%p]: discarding NTP roundtrip of %u ms", ctx, roundtrip);
break;
}
diff --git a/components/services/accessors.c b/components/services/accessors.c
index e2e4607b..cd12279e 100644
--- a/components/services/accessors.c
+++ b/components/services/accessors.c
@@ -58,3 +58,22 @@ const i2c_config_t * config_i2c_get(int * i2c_port) {
if(i2c_port) *i2c_port=i2c_system_port;
return &i2c;
}
+
+/****************************************************************************************
+ *
+ */
+void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
+ char *nvs_item, *p, type[4];
+ int gpio;
+
+ if ((nvs_item = config_alloc_get(NVS_TYPE_STR, "set_GPIO")) == NULL) return;
+
+ p = nvs_item;
+
+ do {
+ if (sscanf(p, "%d=%3[^,]", &gpio, type) > 0) cb(gpio, type);
+ p = strchr(p, ',');
+ } while (p++);
+
+ free(nvs_item);
+}
\ No newline at end of file
diff --git a/components/services/accessors.h b/components/services/accessors.h
index 615a8c52..d5daada7 100644
--- a/components/services/accessors.h
+++ b/components/services/accessors.h
@@ -13,3 +13,4 @@
esp_err_t config_i2c_set(const i2c_config_t * config, int port);
const i2c_config_t * config_i2c_get(int * i2c_port);
+void parse_set_GPIO(void (*cb)(int gpio, char *value));
diff --git a/components/services/battery.c b/components/services/battery.c
index 0eb78f59..d9a3e681 100644
--- a/components/services/battery.c
+++ b/components/services/battery.c
@@ -17,6 +17,13 @@
#include "driver/adc.h"
#include "battery.h"
+/*
+ There is a bug in esp32 which causes a spurious interrupt on gpio 36/39 when
+ using ADC, AMP and HALL sensor. Rather than making battery aware, we just ignore
+ if as the interrupt lasts 80ns and should be debounced (and the ADC read does not
+ happen very often)
+*/
+
#define BATTERY_TIMER (10*1000)
static const char *TAG = "battery";
@@ -27,6 +34,13 @@ static struct {
TimerHandle_t timer;
} battery;
+/****************************************************************************************
+ *
+ */
+ int battery_value_svc(void) {
+ return battery.avg;
+ }
+
/****************************************************************************************
*
*/
diff --git a/components/services/buttons.c b/components/services/buttons.c
index 4b260b98..396ea868 100644
--- a/components/services/buttons.c
+++ b/components/services/buttons.c
@@ -31,6 +31,9 @@
#include "esp_task.h"
#include "driver/gpio.h"
#include "buttons.h"
+#include "globdefs.h"
+
+bool gpio36_39_used;
static const char * TAG = "buttons";
@@ -208,7 +211,10 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu
ESP_LOGW(TAG, "cannot set pull up/down for gpio %u", gpio);
}
}
-
+
+ // nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
+ if (gpio == 36 || gpio == 39) gpio36_39_used = true;
+
gpio_isr_handler_add(gpio, gpio_isr_handler, (void*) &buttons[n_buttons]);
gpio_intr_enable(gpio);
diff --git a/components/services/display.c b/components/services/display.c
index 6b6ab350..7dd7050f 100644
--- a/components/services/display.c
+++ b/components/services/display.c
@@ -29,7 +29,7 @@
// here we should include all possible drivers
extern struct display_s SSD1306_display;
-struct display_s *display;
+struct display_s *display = NULL;
static const char *TAG = "display";
@@ -72,6 +72,7 @@ void display_init(char *welcome) {
init = true;
ESP_LOGI(TAG, "Display initialization successful");
} else {
+ display = NULL;
ESP_LOGE(TAG, "Display initialization failed");
}
} else {
@@ -103,7 +104,7 @@ void display_init(char *welcome) {
}
/****************************************************************************************
- * This is not really thread-safe as displayer_task might be in the middle of line drawing
+ * This is not thread-safe as displayer_task might be in the middle of line drawing
* but it won't crash (I think) and making it thread-safe would be complicated for a
* feature which is secondary (the LMS version of scrolling is thread-safe)
*/
@@ -128,11 +129,19 @@ static void displayer_task(void *args) {
if (scroll_sleep <= 10) {
// something to scroll (or we'll wake-up every pause ms ... no big deal)
if (*displayer.string && displayer.state == DISPLAYER_ACTIVE) {
- display->line(2, -displayer.offset, DISPLAY_CLEAR | DISPLAY_UPDATE, displayer.string);
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
+
+ // need to work with local copies as we don't want to suspend caller
+ int offset = -displayer.offset;
+ char *string = strdup(displayer.string);
scroll_sleep = displayer.offset ? displayer.speed : displayer.pause;
displayer.offset = displayer.offset >= displayer.boundary ? 0 : (displayer.offset + min(displayer.by, displayer.boundary - displayer.offset));
- xSemaphoreGive(displayer.mutex);
+
+ xSemaphoreGive(displayer.mutex);
+
+ // now display using safe copies, can be lengthy
+ display->line(2, offset, DISPLAY_CLEAR | DISPLAY_UPDATE, string);
+ free(string);
} else {
scroll_sleep = DEFAULT_SLEEP;
}
@@ -149,8 +158,8 @@ static void displayer_task(void *args) {
displayer.tick = tick;
displayer.elapsed += elapsed / 1000;
xSemaphoreGive(displayer.mutex);
- if (displayer.elapsed < 3600) sprintf(counter, "%2u:%02u", displayer.elapsed / 60, displayer.elapsed % 60);
- else sprintf(counter, "%2u:%2u:%02u", displayer.elapsed / 3600, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
+ if (displayer.elapsed < 3600) sprintf(counter, "%5u:%02u", displayer.elapsed / 60, displayer.elapsed % 60);
+ else sprintf(counter, "%2u:%02u:%02u", displayer.elapsed / 3600, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
display->line(1, DISPLAY_RIGHT, (DISPLAY_CLEAR | DISPLAY_ONLY_EOL) | DISPLAY_UPDATE, counter);
timer_sleep = 1000;
} else timer_sleep = max(1000 - elapsed, 0);
@@ -171,6 +180,10 @@ void displayer_metadata(char *artist, char *album, char *title) {
char *string = displayer.string, *p;
int len = SCROLLABLE_SIZE;
+ // need a display!
+ if (!display) return;
+
+ // just do title if there is no config set
if (!displayer.metadata_config) {
strncpy(displayer.string, title ? title : "", SCROLLABLE_SIZE);
return;
@@ -218,7 +231,7 @@ void displayer_metadata(char *artist, char *album, char *title) {
p = strchr(q + 1, '%');
}
} else {
- string = strdup(title ? title : "");
+ strncpy(string, title ? title : "", SCROLLABLE_SIZE);
}
// get optional scroll speed
@@ -232,11 +245,13 @@ void displayer_metadata(char *artist, char *album, char *title) {
xSemaphoreGive(displayer.mutex);
}
-
/****************************************************************************************
*
*/
void displayer_scroll(char *string, int speed) {
+ // need a display!
+ if (!display) return;
+
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
if (speed) displayer.speed = speed;
@@ -252,10 +267,13 @@ void displayer_scroll(char *string, int speed) {
*
*/
void displayer_timer(enum displayer_time_e mode, int elapsed, int duration) {
+ // need a display!
+ if (!display) return;
+
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
- if (elapsed >= 0) displayer.elapsed = elapsed;
- if (duration >= 0) displayer.duration = duration;
+ if (elapsed >= 0) displayer.elapsed = elapsed / 1000;
+ if (duration >= 0) displayer.duration = duration / 1000;
if (displayer.timer) displayer.tick = xTaskGetTickCount();
xSemaphoreGive(displayer.mutex);
@@ -267,6 +285,8 @@ void displayer_timer(enum displayer_time_e mode, int elapsed, int duration) {
void displayer_control(enum displayer_cmd_e cmd, ...) {
va_list args;
+ if (!display) return;
+
va_start(args, cmd);
xSemaphoreTake(displayer.mutex, portMAX_DELAY);
diff --git a/components/services/driver_SSD1306.c b/components/services/driver_SSD1306.c
index 6e2319e5..963fc66b 100644
--- a/components/services/driver_SSD1306.c
+++ b/components/services/driver_SSD1306.c
@@ -164,7 +164,7 @@ static bool set_font(int num, enum display_font_e font, int space) {
lines[0].y = lines[0].space;
for (int i = 1; i <= num; i++) lines[i].y = lines[i-1].y + lines[i-1].font->Height + lines[i].space;
- ESP_LOGI(TAG, "adding line %u at %u (height:%u)", num + 1, lines[num].y, lines[num].font->Height);
+ ESP_LOGI(TAG, "Adding line %u at %d (height:%u)", num + 1, lines[num].y, lines[num].font->Height);
if (lines[num].y + lines[num].font->Height > Display.Height) {
ESP_LOGW(TAG, "line does not fit display");
diff --git a/components/services/globdefs.h b/components/services/globdefs.h
index 3d2b1f50..1ec0834f 100644
--- a/components/services/globdefs.h
+++ b/components/services/globdefs.h
@@ -22,6 +22,7 @@
#define I2C_SYSTEM_PORT 1
extern int i2c_system_port;
+extern bool gpio36_39_used;
#ifdef CONFIG_SQUEEZEAMP
#define JACK_GPIO 34
@@ -31,4 +32,5 @@ extern int i2c_system_port;
#else
#define LED_GREEN_GPIO CONFIG_LED_GREEN_GPIO
#define LED_RED_GPIO CONFIG_LED_RED_GPIO
+#define JACK_GPIO CONFIG_JACK_GPIO
#endif
diff --git a/components/services/monitor.c b/components/services/monitor.c
index 763d9cd8..09a4b008 100644
--- a/components/services/monitor.c
+++ b/components/services/monitor.c
@@ -19,6 +19,7 @@
#include "buttons.h"
#include "led.h"
#include "globdefs.h"
+#include "config.h"
#define MONITOR_TIMER (10*1000)
@@ -83,19 +84,31 @@ bool spkfault_svc (void) {
#endif
}
-#include "driver/rtc_io.h"
+/****************************************************************************************
+ *
+ */
+void set_jack_gpio(int gpio, char *value) {
+ if (!strcasecmp(value, "jack")) {
+ ESP_LOGI(TAG,"Adding jack detection GPIO %d", 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);
+ }
+ }
+
/****************************************************************************************
*
*/
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);
+
+#if !defined(JACK_GPIO) || JACK_GPIO == -1
+ parse_set_GPIO(set_jack_gpio);
+#else
+ set_jack_gpio(JACK_GPIO, "jack");
#endif
#ifdef SPKFAULT_GPIO
@@ -107,6 +120,12 @@ void monitor_svc_init(void) {
button_create(NULL, SPKFAULT_GPIO, BUTTON_LOW, true, 0, spkfault_handler_default, 0, -1);
#endif
- monitor_timer = xTimerCreate("monitor", MONITOR_TIMER / portTICK_RATE_MS, pdTRUE, NULL, monitor_callback);
- xTimerStart(monitor_timer, portMAX_DELAY);
+ // do we want stats
+ char *p = config_alloc_get_default(NVS_TYPE_STR, "stats", "n", 0);
+ if (p && (*p == '1' || *p == 'Y' || *p == 'y')) {
+ monitor_timer = xTimerCreate("monitor", MONITOR_TIMER / portTICK_RATE_MS, pdTRUE, NULL, monitor_callback);
+ xTimerStart(monitor_timer, portMAX_DELAY);
+ }
+ free(p);
+
}
diff --git a/components/services/monitor.h b/components/services/monitor.h
index 65fad04f..c0bb8f68 100644
--- a/components/services/monitor.h
+++ b/components/services/monitor.h
@@ -26,3 +26,5 @@ extern bool jack_inserted_svc(void);
extern void (*spkfault_handler_svc)(bool inserted);
extern bool spkfault_svc(void);
+extern int battery_value_svc(void);
+
diff --git a/components/services/services.c b/components/services/services.c
index 671a4be1..f038b870 100644
--- a/components/services/services.c
+++ b/components/services/services.c
@@ -25,6 +25,25 @@ int i2c_system_port = I2C_SYSTEM_PORT;
static const char *TAG = "services";
+/****************************************************************************************
+ *
+ */
+void set_power_gpio(int gpio, char *value) {
+ bool parsed = true;
+
+ if (!strcasecmp(value, "vcc") ) {
+ gpio_pad_select_gpio(gpio);
+ gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
+ gpio_set_level(gpio, 1);
+ } else if (!strcasecmp(value, "gnd")) {
+ gpio_pad_select_gpio(gpio);
+ gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
+ gpio_set_level(gpio, 0);
+ } else parsed = false ;
+
+ if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value);
+ }
+
/****************************************************************************************
*
*/
@@ -40,20 +59,8 @@ void services_init(void) {
}
#endif
- // set fixed gpio if any
- if ((nvs_item = config_alloc_get(NVS_TYPE_STR, "Vcc_GPIO")) != NULL) {
- char *p = nvs_item;
- while (p && *p) {
- int gpio = atoi(p);
- gpio_pad_select_gpio(gpio);
- gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
- gpio_set_level(gpio, 1);
- p = strchr(p, ',');
- ESP_LOGI(TAG, "set GPIO %u to Vcc", gpio);
- if (p) p++;
- }
- free(nvs_item);
- }
+ // set potential power GPIO
+ parse_set_GPIO(set_power_gpio);
const i2c_config_t * i2c_config = config_i2c_get(&i2c_system_port);
diff --git a/components/services/tarablessd1306/ssd1306_font.c b/components/services/tarablessd1306/ssd1306_font.c
index afc1c19f..7a178fd1 100644
--- a/components/services/tarablessd1306/ssd1306_font.c
+++ b/components/services/tarablessd1306/ssd1306_font.c
@@ -47,7 +47,7 @@ void SSD1306_FontDrawChar( struct SSD1306_Device* DisplayHandle, char Character,
NullCheck( ( GlyphData = GetCharPtr( DisplayHandle->Font, Character ) ), return );
- if ( Character >= DisplayHandle->Font->StartChar || Character <= DisplayHandle->Font->EndChar ) {
+ if ( Character >= DisplayHandle->Font->StartChar && Character <= DisplayHandle->Font->EndChar ) {
/* The first byte in the glyph data is the width of the character in pixels, skip over */
GlyphData++;
GlyphColumnLen = RoundUpFontHeight( DisplayHandle->Font ) / 8;
diff --git a/components/squeezelite-ota/cmd_ota.c b/components/squeezelite-ota/cmd_ota.c
index 9b20c6b3..4bf283db 100644
--- a/components/squeezelite-ota/cmd_ota.c
+++ b/components/squeezelite-ota/cmd_ota.c
@@ -26,7 +26,7 @@
#include "esp32/rom/uart.h"
#include "sdkconfig.h"
-static const char * TAG = "platform_esp32";
+static const char * TAG = "ota";
extern esp_err_t start_ota(const char * bin_url);
static struct {
struct arg_str *url;
diff --git a/components/squeezelite/a1s/ac101.c b/components/squeezelite/a1s/ac101.c
new file mode 100644
index 00000000..414c2485
--- /dev/null
+++ b/components/squeezelite/a1s/ac101.c
@@ -0,0 +1,435 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2018
+ *
+ * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "adac.h"
+
+//#include "audio_hal.h"
+#include "ac101.h"
+
+const static char TAG[] = "AC101";
+
+#define AC_ASSERT(a, format, b, ...) \
+ if ((a) != 0) { \
+ ESP_LOGE(TAG, format, ##__VA_ARGS__); \
+ return b;\
+ }
+
+static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config);
+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);
+
+struct adac_s dac_a1s = { init, deinit, power, speaker, headset, volume };
+
+static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val);
+static uint16_t i2c_read_reg(uint8_t reg);
+static esp_err_t ac101_start(ac_module_t mode);
+static esp_err_t ac101_stop(void);
+static esp_err_t ac101_set_earph_volume(uint8_t volume);
+static esp_err_t ac101_set_spk_volume(uint8_t volume);
+
+//static void pa_power(bool enable);
+
+static int i2c_port;
+
+/****************************************************************************************
+ * init
+ */
+static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
+ esp_err_t res;
+
+ ESP_LOGI(TAG, "Initializing AC101");
+ i2c_port = i2c_port_num;
+
+ // configure i2c
+ i2c_config_t i2c_config = {
+ .mode = I2C_MODE_MASTER,
+ .sda_io_num = 33,
+ .sda_pullup_en = GPIO_PULLUP_ENABLE,
+ .scl_io_num = 32,
+ .scl_pullup_en = GPIO_PULLUP_ENABLE,
+ .master.clk_speed = 100000,
+ };
+
+ i2c_param_config(i2c_port, &i2c_config);
+ i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
+ ESP_LOGI(TAG, "DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
+
+ res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
+
+ //huh?
+ //vTaskDelay(1000 / portTICK_PERIOD_MS);
+ if (ESP_OK != res) {
+ ESP_LOGE(TAG, "reset failed!");
+ return false;
+ }
+
+ i2c_write_reg(SPKOUT_CTRL, 0xe880);
+
+ // Enable the PLL from 256*44.1KHz MCLK source
+ i2c_write_reg(PLL_CTRL1, 0x014f);
+ //res |= i2c_write_reg(PLL_CTRL2, 0x83c0);
+ i2c_write_reg(PLL_CTRL2, 0x8600);
+
+ //Clocking system
+ i2c_write_reg(SYSCLK_CTRL, 0x8b08);
+ i2c_write_reg(MOD_CLK_ENA, 0x800c);
+ i2c_write_reg(MOD_RST_CTRL, 0x800c);
+ i2c_write_reg(I2S_SR_CTRL, 0x7000); //sample rate
+
+ //AIF config
+ i2c_write_reg(I2S1LCK_CTRL, 0x8850); //BCLK/LRCK
+ i2c_write_reg(I2S1_SDOUT_CTRL, 0xc000); //
+ i2c_write_reg(I2S1_SDIN_CTRL, 0xc000);
+ i2c_write_reg(I2S1_MXR_SRC, 0x2200); //
+
+ i2c_write_reg(ADC_SRCBST_CTRL, 0xccc4);
+ i2c_write_reg(ADC_SRC, 0x2020);
+ i2c_write_reg(ADC_DIG_CTRL, 0x8000);
+ i2c_write_reg(ADC_APC_CTRL, 0xbbc3);
+
+ //Path Configuration
+ i2c_write_reg(DAC_MXR_SRC, 0xcc00);
+ i2c_write_reg(DAC_DIG_CTRL, 0x8000);
+ i2c_write_reg(OMIXER_SR, 0x0081);
+ i2c_write_reg(OMIXER_DACA_CTRL, 0xf080);//}
+
+ //* Enable Speaker output
+ i2c_write_reg(0x58, 0xeabd);
+
+ //ac101_pa_power(true);
+
+ uint16_t regval;
+
+ // configure I2S
+ regval = i2c_read_reg(I2S1LCK_CTRL);
+ regval &= 0xffc3;
+ regval |= (AC_MODE_SLAVE << 15);
+ regval |= (BIT_LENGTH_16_BITS << 4);
+ regval |= (AC_MODE_SLAVE << 2);
+ res |= i2c_write_reg(I2S1LCK_CTRL, regval);
+ res |= i2c_write_reg(I2S_SR_CTRL, SAMPLE_RATE_44100);
+
+ // configure I2S pins & install driver
+ i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = 27, .ws_io_num = 26,
+ .data_out_num = 25, .data_in_num = 35 //Not used
+ };
+ i2s_driver_install(i2s_num, i2s_config, 0, NULL);
+ i2s_set_pin(i2s_num, &i2s_pin_config);
+
+ ESP_LOGI(TAG, "DAC using I2S bck:%u, ws:%u, do:%u", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
+
+ return true;
+}
+
+/****************************************************************************************
+ * init
+ */
+static void deinit(void) {
+ i2c_driver_delete(i2c_port);
+}
+
+/****************************************************************************************
+ * change volume
+ */
+static void volume(unsigned left, unsigned right) {
+ // nothing at that point, volume is handled by backend
+}
+
+/****************************************************************************************
+ * power
+ */
+static void power(adac_power_e mode) {
+ esp_err_t ret = ESP_OK;
+
+ switch(mode) {
+ case ADAC_STANDBY:
+ case ADAC_OFF:
+ ret = ac101_stop();
+ break;
+ case ADAC_ON:
+ ret = ac101_start(AC_MODULE_DAC);
+ break;
+ default:
+ ESP_LOGW(TAG, "unknown power command");
+ break;
+ }
+
+ if (ret != ESP_OK) ESP_LOGW(TAG, "can't start AC101 %d", ret);
+}
+
+/****************************************************************************************
+ * speaker
+ */
+static void speaker(bool active) {
+ if (active) i2c_write_reg(SPKOUT_CTRL, 0xeabd);
+ else i2c_write_reg(SPKOUT_CTRL, 0xe880); //disable speaker
+}
+
+/****************************************************************************************
+ * headset
+ */
+static void headset(bool active) {
+ if (active) {
+ i2c_write_reg(OMIXER_DACA_CTRL, 0xff80);
+ i2c_write_reg(HPOUT_CTRL, 0xc3c1);
+ i2c_write_reg(HPOUT_CTRL, 0xcb00);
+ // huh?
+ vTaskDelay(100 / portTICK_PERIOD_MS);
+ i2c_write_reg(HPOUT_CTRL, 0xfbc0);
+ } else {
+ i2c_write_reg(HPOUT_CTRL, 0x01); //disable earphone
+ }
+}
+
+/****************************************************************************************
+ *
+ */
+static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val)
+{
+ i2c_cmd_handle_t cmd = i2c_cmd_link_create();
+ esp_err_t ret =0;
+ uint8_t send_buff[4];
+ send_buff[0] = (AC101_ADDR << 1);
+ send_buff[1] = reg;
+ send_buff[2] = (val>>8) & 0xff;
+ send_buff[3] = val & 0xff;
+ ret |= i2c_master_start(cmd);
+ ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN);
+ ret |= i2c_master_stop(cmd);
+ ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
+ i2c_cmd_link_delete(cmd);
+ return ret;
+}
+
+/****************************************************************************************
+ *
+ */
+static uint16_t i2c_read_reg(uint8_t reg) {
+ uint8_t data[2] = { 0 };
+
+ i2c_cmd_handle_t cmd = i2c_cmd_link_create();
+ i2c_master_start(cmd);
+ i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
+ i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
+ i2c_master_start(cmd);
+ i2c_master_write_byte(cmd, ( AC101_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN); //check or not
+ i2c_master_read(cmd, data, 2, ACK_VAL);
+ i2c_master_stop(cmd);
+ i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
+ i2c_cmd_link_delete(cmd);
+
+ return (data[0] << 8) + data[1];;
+}
+
+/****************************************************************************************
+ *
+ */
+void set_codec_clk(ac_adda_fs_i2s1_t rate) {
+ i2c_write_reg(I2S_SR_CTRL, rate);
+}
+
+/****************************************************************************************
+ *
+ */
+static int ac101_get_spk_volume(void) {
+ int res;
+ res = i2c_read_reg(SPKOUT_CTRL);
+ res &= 0x1f;
+ return res*2;
+}
+
+/****************************************************************************************
+ *
+ */
+static esp_err_t ac101_set_spk_volume(uint8_t volume) {
+ uint16_t res;
+ esp_err_t ret;
+ volume = volume/2;
+ res = i2c_read_reg(SPKOUT_CTRL);
+ res &= (~0x1f);
+ volume &= 0x1f;
+ res |= volume;
+ ret = i2c_write_reg(SPKOUT_CTRL,res);
+ return ret;
+}
+
+/****************************************************************************************
+ *
+ */
+static int ac101_get_earph_volume(void) {
+ int res;
+ res = i2c_read_reg(HPOUT_CTRL);
+ return (res>>4)&0x3f;
+}
+
+/****************************************************************************************
+ *
+ */
+static esp_err_t ac101_set_earph_volume(uint8_t volume) {
+ uint16_t res,tmp;
+ esp_err_t ret;
+ res = i2c_read_reg(HPOUT_CTRL);
+ tmp = ~(0x3f<<4);
+ res &= tmp;
+ volume &= 0x3f;
+ res |= (volume << 4);
+ ret = i2c_write_reg(HPOUT_CTRL,res);
+ return ret;
+}
+
+/****************************************************************************************
+ *
+ */
+static esp_err_t ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mixer_source_t source)
+{
+ uint16_t regval,temp,clrbit;
+ esp_err_t ret;
+ regval = i2c_read_reg(OMIXER_BST1_CTRL);
+ switch(source){
+ case SRC_MIC1:
+ temp = (gain&0x7) << 6;
+ clrbit = ~(0x7<<6);
+ break;
+ case SRC_MIC2:
+ temp = (gain&0x7) << 3;
+ clrbit = ~(0x7<<3);
+ break;
+ case SRC_LINEIN:
+ temp = (gain&0x7);
+ clrbit = ~0x7;
+ break;
+ default:
+ return -1;
+ }
+ regval &= clrbit;
+ regval |= temp;
+ ret = i2c_write_reg(OMIXER_BST1_CTRL,regval);
+ return ret;
+}
+
+/****************************************************************************************
+ *
+ */
+static esp_err_t ac101_start(ac_module_t mode) {
+ esp_err_t res = 0;
+
+ if (mode == AC_MODULE_LINE) {
+ res |= i2c_write_reg(0x51, 0x0408);
+ res |= i2c_write_reg(0x40, 0x8000);
+ res |= i2c_write_reg(0x50, 0x3bc0);
+ }
+ if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
+ //I2S1_SDOUT_CTRL
+ //res |= i2c_write_reg(PLL_CTRL2, 0x8120);
+ res |= i2c_write_reg(0x04, 0x800c);
+ res |= i2c_write_reg(0x05, 0x800c);
+ //res |= i2c_write_reg(0x06, 0x3000);
+ }
+ if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) {
+ //* Enable Headphone output 注意使用耳机时,最后开以下寄存器
+ res |= i2c_write_reg(OMIXER_DACA_CTRL, 0xff80);
+ res |= i2c_write_reg(HPOUT_CTRL, 0xc3c1);
+ res |= i2c_write_reg(HPOUT_CTRL, 0xcb00);
+ // huh?
+ vTaskDelay(100 / portTICK_PERIOD_MS);
+ res |= i2c_write_reg(HPOUT_CTRL, 0xfbc0);
+
+ //* Enable Speaker output
+ res |= i2c_write_reg(SPKOUT_CTRL, 0xeabd);
+ // huh?
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ ac101_set_earph_volume(255);
+ ac101_set_spk_volume(255);
+ }
+
+ return res;
+}
+
+/****************************************************************************************
+ *
+ */
+esp_err_t ac101_stop(void) {
+ esp_err_t res = 0;
+ res |= i2c_write_reg(HPOUT_CTRL, 0x01); //disable earphone
+ res |= i2c_write_reg(SPKOUT_CTRL, 0xe880); //disable speaker
+ return res;
+}
+
+/****************************************************************************************
+ *
+ */
+esp_err_t ac101_deinit(void) {
+ return i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
+}
+
+
+/****************************************************************************************
+ * Don't know when this one is supposed to be called
+ */
+esp_err_t AC101_i2s_config_clock(ac_i2s_clock_t *cfg) {
+ esp_err_t res = 0;
+ uint16_t regval=0;
+ regval = i2c_read_reg(I2S1LCK_CTRL);
+ regval &= 0xe03f;
+ regval |= (cfg->bclk_div << 9);
+ regval |= (cfg->lclk_div << 6);
+ res = i2c_write_reg(I2S1LCK_CTRL, regval);
+ return res;
+}
+
+/****************************************************************************************
+ *
+ */
+esp_err_t ac101_get_voice_volume(int* volume) {
+ *volume = ac101_get_earph_volume();
+ return 0;
+}
+
+/*
+void ac101_pa_power(bool enable) {
+ gpio_config_t io_conf;
+ memset(&io_conf, 0, sizeof(io_conf));
+ io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
+ io_conf.mode = GPIO_MODE_OUTPUT;
+ io_conf.pin_bit_mask = BIT(GPIO_PA_EN);
+ io_conf.pull_down_en = 0;
+ io_conf.pull_up_en = 0;
+ gpio_config(&io_conf);
+ if (enable) {
+ gpio_set_level(GPIO_PA_EN, 1);
+ } else {
+ gpio_set_level(GPIO_PA_EN, 0);
+ }
+}
+*/
\ No newline at end of file
diff --git a/components/squeezelite/a1s/ac101.h b/components/squeezelite/a1s/ac101.h
new file mode 100644
index 00000000..00cddb7a
--- /dev/null
+++ b/components/squeezelite/a1s/ac101.h
@@ -0,0 +1,176 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2018
+ *
+ * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
+ * it is free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AC101_H__
+#define __AC101_H__
+
+#include "esp_types.h"
+
+#define AC101_ADDR 0x1a /*!< Device address*/
+
+#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
+#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
+#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
+#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
+#define ACK_VAL 0x0 /*!< I2C ack value */
+#define NACK_VAL 0x1 /*!< I2C nack value */
+
+#define CHIP_AUDIO_RS 0x00
+#define PLL_CTRL1 0x01
+#define PLL_CTRL2 0x02
+#define SYSCLK_CTRL 0x03
+#define MOD_CLK_ENA 0x04
+#define MOD_RST_CTRL 0x05
+#define I2S_SR_CTRL 0x06
+#define I2S1LCK_CTRL 0x10
+#define I2S1_SDOUT_CTRL 0x11
+#define I2S1_SDIN_CTRL 0x12
+#define I2S1_MXR_SRC 0x13
+#define I2S1_VOL_CTRL1 0x14
+#define I2S1_VOL_CTRL2 0x15
+#define I2S1_VOL_CTRL3 0x16
+#define I2S1_VOL_CTRL4 0x17
+#define I2S1_MXR_GAIN 0x18
+#define ADC_DIG_CTRL 0x40
+#define ADC_VOL_CTRL 0x41
+#define HMIC_CTRL1 0x44
+#define HMIC_CTRL2 0x45
+#define HMIC_STATUS 0x46
+#define DAC_DIG_CTRL 0x48
+#define DAC_VOL_CTRL 0x49
+#define DAC_MXR_SRC 0x4c
+#define DAC_MXR_GAIN 0x4d
+#define ADC_APC_CTRL 0x50
+#define ADC_SRC 0x51
+#define ADC_SRCBST_CTRL 0x52
+#define OMIXER_DACA_CTRL 0x53
+#define OMIXER_SR 0x54
+#define OMIXER_BST1_CTRL 0x55
+#define HPOUT_CTRL 0x56
+#define SPKOUT_CTRL 0x58
+#define AC_DAC_DAPCTRL 0xa0
+#define AC_DAC_DAPHHPFC 0xa1
+#define AC_DAC_DAPLHPFC 0xa2
+#define AC_DAC_DAPLHAVC 0xa3
+#define AC_DAC_DAPLLAVC 0xa4
+#define AC_DAC_DAPRHAVC 0xa5
+#define AC_DAC_DAPRLAVC 0xa6
+#define AC_DAC_DAPHGDEC 0xa7
+#define AC_DAC_DAPLGDEC 0xa8
+#define AC_DAC_DAPHGATC 0xa9
+#define AC_DAC_DAPLGATC 0xaa
+#define AC_DAC_DAPHETHD 0xab
+#define AC_DAC_DAPLETHD 0xac
+#define AC_DAC_DAPHGKPA 0xad
+#define AC_DAC_DAPLGKPA 0xae
+#define AC_DAC_DAPHGOPA 0xaf
+#define AC_DAC_DAPLGOPA 0xb0
+#define AC_DAC_DAPOPT 0xb1
+#define DAC_DAP_ENA 0xb5
+
+typedef enum{
+ SAMPLE_RATE_8000 = 0x0000,
+ SAMPLE_RATE_11052 = 0x1000,
+ SAMPLE_RATE_12000 = 0x2000,
+ SAMPLE_RATE_16000 = 0x3000,
+ SAMPLE_RATE_22050 = 0x4000,
+ SAMPLE_RATE_24000 = 0x5000,
+ SAMPLE_RATE_32000 = 0x6000,
+ SAMPLE_RATE_44100 = 0x7000,
+ SAMPLE_RATE_48000 = 0x8000,
+ SAMPLE_RATE_96000 = 0x9000,
+ SAMPLE_RATE_192000 = 0xa000,
+} ac_adda_fs_i2s1_t;
+
+typedef enum{
+ BCLK_DIV_1 = 0x0,
+ BCLK_DIV_2 = 0x1,
+ BCLK_DIV_4 = 0x2,
+ BCLK_DIV_6 = 0x3,
+ BCLK_DIV_8 = 0x4,
+ BCLK_DIV_12 = 0x5,
+ BCLK_DIV_16 = 0x6,
+ BCLK_DIV_24 = 0x7,
+ BCLK_DIV_32 = 0x8,
+ BCLK_DIV_48 = 0x9,
+ BCLK_DIV_64 = 0xa,
+ BCLK_DIV_96 = 0xb,
+ BCLK_DIV_128 = 0xc,
+ BCLK_DIV_192 = 0xd,
+} ac_i2s1_bclk_div_t;
+
+typedef enum{
+ LRCK_DIV_16 =0x0,
+ LRCK_DIV_32 =0x1,
+ LRCK_DIV_64 =0x2,
+ LRCK_DIV_128 =0x3,
+ LRCK_DIV_256 =0x4,
+} ac_i2s1_lrck_div_t;
+
+typedef enum {
+ BIT_LENGTH_8_BITS = 0x00,
+ BIT_LENGTH_16_BITS = 0x01,
+ BIT_LENGTH_20_BITS = 0x02,
+ BIT_LENGTH_24_BITS = 0x03,
+} ac_bits_length_t;
+
+typedef enum {
+ AC_MODE_MIN = -1,
+ AC_MODE_SLAVE = 0x00,
+ AC_MODE_MASTER = 0x01,
+ AC_MODE_MAX,
+} ac_mode_sm_t;
+
+typedef enum {
+ AC_MODULE_MIN = -1,
+ AC_MODULE_ADC = 0x01,
+ AC_MODULE_DAC = 0x02,
+ AC_MODULE_ADC_DAC = 0x03,
+ AC_MODULE_LINE = 0x04,
+ AC_MODULE_MAX
+} ac_module_t;
+
+typedef enum{
+ SRC_MIC1 = 1,
+ SRC_MIC2 = 2,
+ SRC_LINEIN = 3,
+}ac_output_mixer_source_t;
+
+typedef enum {
+ GAIN_N45DB = 0,
+ GAIN_N30DB = 1,
+ GAIN_N15DB = 2,
+ GAIN_0DB = 3,
+ GAIN_15DB = 4,
+ GAIN_30DB = 5,
+ GAIN_45DB = 6,
+ GAIN_60DB = 7,
+} ac_output_mixer_gain_t;
+
+typedef struct {
+ ac_i2s1_bclk_div_t bclk_div; /*!< bits clock divide */
+ ac_i2s1_lrck_div_t lclk_div; /*!< WS clock divide */
+} ac_i2s_clock_t;
+
+#endif
\ No newline at end of file
diff --git a/components/squeezelite/adac.h b/components/squeezelite/adac.h
new file mode 100644
index 00000000..4a12a7d4
--- /dev/null
+++ b/components/squeezelite/adac.h
@@ -0,0 +1,38 @@
+/*
+ * Squeezelite for esp32
+ *
+ * (c) Sebastien 2019
+ * Philippe G. 2019, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "freertos/FreeRTOS.h"
+#include "driver/i2s.h"
+
+typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e;
+
+struct adac_s {
+ bool (*init)(int i2c_port_num, int i2s_num, i2s_config_t *config);
+ void (*deinit)(void);
+ void (*power)(adac_power_e mode);
+ void (*speaker)(bool active);
+ void (*headset)(bool active);
+ void (*volume)(unsigned left, unsigned right);
+};
+
+extern struct adac_s dac_tas57xx;
+extern struct adac_s dac_a1s;
+extern struct adac_s dac_null;
\ No newline at end of file
diff --git a/components/squeezelite/component.mk b/components/squeezelite/component.mk
index ef59f34e..9b670e61 100644
--- a/components/squeezelite/component.mk
+++ b/components/squeezelite/component.mk
@@ -19,5 +19,6 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON
# -I$(COMPONENT_PATH)/../codecs/inc/faad2
-
+COMPONENT_SRCDIRS := . tas57xx a1s null
+COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./a1s
diff --git a/components/squeezelite/decode_external.c b/components/squeezelite/decode_external.c
index a79d4d16..3cf0c698 100644
--- a/components/squeezelite/decode_external.c
+++ b/components/squeezelite/decode_external.c
@@ -207,7 +207,7 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
ms = ((u64_t) ((_buf_used(outputbuf) - raop_sync.len) / BYTES_PER_FRAME + output.device_frames + output.frames_in_process) * 1000) / RAOP_SAMPLE_RATE - (now - output.updated);
raop_sync.error[raop_sync.idx] = (raop_sync.playtime - now) - ms;
sync_nb = SYNC_NB;
- LOG_INFO("head local:%u, remote:%u (delta:%d)", ms, raop_sync.playtime - now, raop_sync.error[raop_sync.idx]);
+ LOG_DEBUG("head local:%u, remote:%u (delta:%d)", ms, raop_sync.playtime - now, raop_sync.error[raop_sync.idx]);
LOG_DEBUG("obuf:%u, sync_len:%u, devframes:%u, inproc:%u", _buf_used(outputbuf), raop_sync.len, output.device_frames, output.frames_in_process);
}
diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c
index 2b5663c1..252edd78 100644
--- a/components/squeezelite/display.c
+++ b/components/squeezelite/display.c
@@ -137,10 +137,16 @@ static void scroll_task(void* arg);
/****************************************************************************************
*
*/
-void sb_display_init(void) {
+bool sb_display_init(void) {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static EXT_RAM_ATTR StackType_t xStack[SCROLL_STACK_SIZE] __attribute__ ((aligned (4)));
+ // no display, just make sure we won't have requests
+ if (!display || display->height == 0 || display->width == 0) {
+ LOG_INFO("no display for LMS");
+ return false;
+ }
+
// need to force height to 32 maximum
display_width = display->width;
display_height = min(display->height, 32);
@@ -163,6 +169,8 @@ void sb_display_init(void) {
notify_chain = server_notify;
server_notify = server;
+
+ return true;
}
/****************************************************************************************
@@ -288,7 +296,7 @@ static void show_display_buffer(char *ddram) {
makeprintable((unsigned char *)line1);
makeprintable((unsigned char *)line2);
- LOG_INFO("\n\t%.40s\n\t%.40s", line1, line2);
+ LOG_DEBUG("\n\t%.40s\n\t%.40s", line1, line2);
display->line(1, DISPLAY_LEFT, DISPLAY_CLEAR, line1);
display->line(2, DISPLAY_LEFT, DISPLAY_CLEAR | DISPLAY_UPDATE, line2);
@@ -380,7 +388,7 @@ static void grfs_handler(u8_t *data, int len) {
int size = len - sizeof(struct grfs_packet);
int offset = htons(pkt->offset);
- LOG_INFO("gfrs s:%u d:%u p:%u sp:%u by:%hu m:%hu w:%hu o:%hu",
+ LOG_DEBUG("gfrs s:%u d:%u p:%u sp:%u by:%hu m:%hu w:%hu o:%hu",
(int) pkt->screen,
(int) pkt->direction, // 1=left, 2=right
htonl(pkt->pause), // in ms
@@ -425,7 +433,7 @@ static void grfs_handler(u8_t *data, int len) {
static void grfg_handler(u8_t *data, int len) {
struct grfg_packet *pkt = (struct grfg_packet*) data;
- LOG_INFO("gfrg s:%hu w:%hu (len:%u)", htons(pkt->screen), htons(pkt->width), len);
+ LOG_DEBUG("gfrg s:%hu w:%hu (len:%u)", htons(pkt->screen), htons(pkt->width), len);
memcpy(scroller.back_frame, data + sizeof(struct grfg_packet), len - sizeof(struct grfg_packet));
scroller.window_width = htons(pkt->width);
@@ -457,7 +465,7 @@ static void grfg_handler(u8_t *data, int len) {
}
else {
// if we just got a content update, let the scroller manage the screen
- LOG_INFO("resuming scrolling task");
+ LOG_DEBUG("resuming scrolling task");
vTaskResume(scroller.task);
}
diff --git a/components/squeezelite/embedded.c b/components/squeezelite/embedded.c
index 6dc3aed0..89a2aa83 100644
--- a/components/squeezelite/embedded.c
+++ b/components/squeezelite/embedded.c
@@ -50,9 +50,11 @@ uint32_t _gettime_ms_(void) {
}
extern void sb_controls_init(void);
-extern void sb_display_init(void);
+extern bool sb_display_init(void);
+
+u8_t custom_player_id = 12;
void embedded_init(void) {
sb_controls_init();
- sb_display_init();
+ if (sb_display_init()) custom_player_id = 100;
}
diff --git a/components/squeezelite/embedded.h b/components/squeezelite/embedded.h
index 5f75cd77..1d22876e 100644
--- a/components/squeezelite/embedded.h
+++ b/components/squeezelite/embedded.h
@@ -26,7 +26,10 @@
#define OUTPUT_THREAD_STACK_SIZE 6 * 1024
#define IR_THREAD_STACK_SIZE 6 * 1024
-#define PLAYER_ID 100
+// or can be as simple as #define PLAYER_ID 100
+#define PLAYER_ID custom_player_id;
+extern u8_t custom_player_id;
+
#define BASE_CAP "Model=squeezeesp32,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION
#define EXT_BSS __attribute__((section(".ext_ram.bss")))
diff --git a/components/squeezelite/main.c b/components/squeezelite/main.c
index 38be869d..295c9d63 100644
--- a/components/squeezelite/main.c
+++ b/components/squeezelite/main.c
@@ -52,8 +52,10 @@ static void usage(const char *argv0) {
printf(TITLE " See -t for license terms\n"
"Usage: %s [options]\n"
" -s [:]\tConnect to specified server, otherwise uses autodiscovery to find server\n"
+#if !EMBEDDED
" -o