Compare commits

...

23 Commits

Author SHA1 Message Date
Sebastien
5ff673ae7d Fix build issue - release 2020-09-08 17:11:52 -04:00
Sebastien
2eb995d621 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32.git into master-cmake 2020-09-08 16:47:08 -04:00
Sebastien
573ddb6fda Bug fix - some values weren't passed back in the command call - release 2020-09-08 16:46:50 -04:00
Philippe G
708a3f9c4a small tweaks 2020-09-06 17:06:52 -07:00
Philippe G
a73c659a1e solving mistery of component made of external static libs only
(and I hate CMake)
2020-09-06 16:54:09 -07:00
Philippe G
b22143a3b6 typos 2020-09-06 00:49:04 -07:00
Sebastien
6195750b41 Minor fix to the UI and command line help text - release 2020-09-04 16:24:12 -04:00
Sebastien
889b1097cc Reorganize configuration UI - release
The System tab is now hidden by default and can be enabled via a toggle
under the Credits tab, similar to how NVS tab works.  A new tab was
created to hold configurations, and display configuration was added.
2020-09-04 16:02:53 -04:00
Sebastien
41cdb8bcdd Allow saving/loading nvs from the nvs editor - release 2020-09-02 13:09:46 -04:00
Philippe G
8c33acfd35 tweak dac_controlset timing - release 2020-09-01 16:24:36 -07:00
Sebastien
0222a34286 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32.git into master-cmake 2020-09-01 16:45:11 -04:00
Sebastien
a90c9802ab Fix commands not working in telnet #43 - release 2020-09-01 16:43:48 -04:00
Philippe G
94da8ca950 i2c timeout change + remove some wifi test code used for led fix - release 2020-09-01 13:40:25 -07:00
Philippe G
9a9a4fef65 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2020-09-01 12:24:11 -07:00
Philippe G
3a7b1f48c7 change a bit log 2020-09-01 12:24:09 -07:00
Sebastien
a46bbb409f Fixes #50 - Green led flash state reset on wifi connect - release 2020-09-01 15:11:45 -04:00
Sebastien
08d16c2ca2 Led configuration wasn't correctly reported in logs 2020-09-01 12:03:31 -04:00
Philippe G
b501352ddc Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2020-08-31 15:36:21 -07:00
Philippe G
1c51598366 shift i2c address by 1 for consistency - release 2020-08-31 15:36:17 -07:00
Sebastien
db839a9ccd Add new status field: is_i2c_locked to help with the new config page 2020-08-31 16:56:54 -04:00
Philippe G
5aba426b98 no mutex needed for polling - release 2020-08-30 12:30:30 -07:00
Philippe G
6c184efa92 faster & simpler solution for stream poll() - release 2020-08-30 11:22:03 -07:00
Philippe G
028a090864 update plugin files 2020-08-29 22:20:26 -07:00
23 changed files with 535 additions and 250 deletions

View File

@@ -1,6 +1,5 @@
idf_component_register(SRC_DIRS .
idf_component_register(
INCLUDE_DIRS . ./inc inc/alac inc/FLAC inc/helix-aac inc/mad inc/ogg inc/opus inc/opusfile inc/resample16 inc/soxr inc/vorbis
PRIV_REQUIRES newlib
)
add_prebuilt_library(libmad lib/libmad.a)
@@ -9,16 +8,16 @@ add_prebuilt_library(libhelix-aac lib/libhelix-aac.a )
add_prebuilt_library(libvorbisidec lib/libvorbisidec.a )
add_prebuilt_library(libogg lib/libogg.a )
add_prebuilt_library(libalac lib/libalac.a )
add_prebuilt_library(libremple16 lib/libresample16.a )
add_prebuilt_library(libresample16 lib/libresample16.a )
add_prebuilt_library(libopusfile lib/libopusfile.a )
add_prebuilt_library(libopus lib/libopus.a )
target_link_libraries(${COMPONENT_LIB} PRIVATE libmad)
target_link_libraries(${COMPONENT_LIB} PRIVATE libFLAC)
target_link_libraries(${COMPONENT_LIB} PRIVATE libhelix-aac)
target_link_libraries(${COMPONENT_LIB} PRIVATE libvorbisidec)
target_link_libraries(${COMPONENT_LIB} PRIVATE libogg)
target_link_libraries(${COMPONENT_LIB} PRIVATE libalac)
target_link_libraries(${COMPONENT_LIB} PRIVATE libremple16)
target_link_libraries(${COMPONENT_LIB} PRIVATE libopusfile)
target_link_libraries(${COMPONENT_LIB} PRIVATE libopus)
target_link_libraries(${COMPONENT_LIB} INTERFACE libmad)
target_link_libraries(${COMPONENT_LIB} INTERFACE libFLAC)
target_link_libraries(${COMPONENT_LIB} INTERFACE libhelix-aac)
target_link_libraries(${COMPONENT_LIB} INTERFACE libvorbisidec)
target_link_libraries(${COMPONENT_LIB} INTERFACE libogg)
target_link_libraries(${COMPONENT_LIB} INTERFACE libalac)
target_link_libraries(${COMPONENT_LIB} INTERFACE libresample16)
target_link_libraries(${COMPONENT_LIB} INTERFACE libopusfile)
target_link_libraries(${COMPONENT_LIB} INTERFACE libopus)

View File

@@ -1,3 +0,0 @@
void dummy_obj() {
return;
}

View File

@@ -35,7 +35,7 @@ static bool I2CDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data,
bool GDS_I2CInit( int PortNumber, int SDA, int SCL, int Speed ) {
I2CPortNumber = PortNumber;
I2CWait = pdMS_TO_TICKS( Speed ? Speed / 4000 : 100 );
I2CWait = pdMS_TO_TICKS( Speed ? (250 * 250000) / Speed : 250 );
if (SDA != -1 && SCL != -1) {
i2c_config_t Config = { 0 };

View File

@@ -396,3 +396,27 @@ const char *display_conf_get_driver_name(char * driver){
}
return NULL;
}
/****************************************************************************************
*
*/
char * display_get_supported_drivers(void){
int total_size = 1;
char * supported_drivers=NULL;
const char * separator = "|";
int separator_len = strlen(separator);
for(uint8_t i=0;known_drivers[i]!=NULL && strlen(known_drivers[i])>0;i++ ){
total_size += strlen(known_drivers[i])+separator_len;
}
total_size+=2;
supported_drivers = malloc(total_size);
memset(supported_drivers,0x00,total_size);
strcat(supported_drivers,"<");
for(uint8_t i=0;known_drivers[i]!=NULL && strlen(known_drivers[i])>0;i++ ){
supported_drivers = strcat(supported_drivers,known_drivers[i]);
supported_drivers = strcat(supported_drivers,separator);
}
strcat(supported_drivers,">");
return supported_drivers;
}

View File

@@ -10,6 +10,7 @@
#include "gds.h"
/*
The displayer is not thread-safe and the caller must ensure use its own
mutexes if it wants something better. Especially, text() line() and draw()
@@ -38,3 +39,4 @@ void displayer_scroll(char *string, int speed, int pause);
void displayer_control(enum displayer_cmd_e cmd, ...);
void displayer_metadata(char *artist, char *album, char *title);
void displayer_timer(enum displayer_time_e mode, int elapsed, int duration);
char * display_get_supported_drivers(void);

View File

@@ -30,7 +30,8 @@
#define NACK_VAL 0x1 /*!< I2C nack value */
static const char *TAG = "cmd_i2ctools";
#define NOT_OUTPUT "has input capabilities only"
#define NOT_GPIO "is not a GPIO"
static gpio_num_t i2c_gpio_sda = 19;
static gpio_num_t i2c_gpio_scl = 18;
static uint32_t i2c_frequency = 100000;
@@ -62,11 +63,12 @@ static struct {
} i2cdump_args;
static struct {
struct arg_lit *load;
struct arg_int *port;
struct arg_int *freq;
struct arg_int *sda;
struct arg_int *scl;
struct arg_lit *load;
struct arg_lit *clear;
struct arg_end *end;
} i2cconfig_args;
@@ -82,15 +84,17 @@ static struct {
} i2ccheck_args;
static struct {
struct arg_lit *clear;
struct arg_lit *hflip;
struct arg_lit *vflip;
struct arg_lit *rotate;
struct arg_int *address;
struct arg_int *width;
struct arg_int *height;
struct arg_str *name;
struct arg_str *driver;
struct arg_int *width;
struct arg_int *height;
struct arg_int *address;
struct arg_lit *rotate;
struct arg_lit *hflip;
struct arg_lit *vflip;
struct arg_int *speed;
struct arg_int *back;
struct arg_lit *clear;
struct arg_end *end;
} i2cdisp_args;
@@ -368,8 +372,7 @@ static int do_i2c_show_display(int argc, char **argv){
static int do_i2c_set_display(int argc, char **argv)
{
int width=0, height=0, address=60;
int result = 0;
int width=0, height=0, address=60, back=-1, speed=8000000 ;
char * name = NULL;
char * driver= NULL;
char config_string[200]={};
@@ -426,6 +429,7 @@ static int do_i2c_set_display(int argc, char **argv)
fprintf(f,"Missing parameter: --height\n");
nerrors ++;
}
/* Check "--name" option */
if (i2cdisp_args.name->count) {
name=strdup(i2cdisp_args.name->sval[0]);
@@ -436,7 +440,33 @@ static int do_i2c_set_display(int argc, char **argv)
driver=strdup(i2cdisp_args.driver->sval[0]);
}
/* Check "--back" option */
if (i2cdisp_args.back->count) {
back=i2cdisp_args.back->ival[0];
if(!GPIO_IS_VALID_OUTPUT_GPIO(back)){
fprintf(f,"Invalid GPIO for back light: %d %s\n", back, GPIO_IS_VALID_GPIO(back)?NOT_OUTPUT:NOT_GPIO );
back=-1;
nerrors ++;
}
}
if(!name) name = strdup("I2C");
/* Check "--speed" option */
if (i2cdisp_args.speed->count) {
speed=i2cdisp_args.speed->ival[0];
}
else {
if(strcasestr(name,"I2C")){
speed = 250000;
}
else {
speed = 8000000;
}
}
if(!driver) driver = strdup("SSD1306");
@@ -456,33 +486,44 @@ static int do_i2c_set_display(int argc, char **argv)
bool rotate = i2cdisp_args.rotate->count>0;
if(nerrors==0){
snprintf(config_string, sizeof(config_string),"%s:width=%i,height=%i,address=%i,driver=%s%s%s",
name,width,height,address,driver,rotate || i2cdisp_args.hflip->count?",HFlip":"",rotate || i2cdisp_args.vflip->count?",VFlip":"" );
snprintf(config_string, sizeof(config_string),"%s:back=%i,speed=%i,width=%i,height=%i,address=%i,driver=%s%s%s",
name,back,speed,width,height,address,driver,rotate || i2cdisp_args.hflip->count?",HFlip":"",rotate || i2cdisp_args.vflip->count?",VFlip":"" );
fprintf(f,"Updating display configuration string configuration to :\n"
"display_config = \"%s\"",config_string );
result = config_set_value(NVS_TYPE_STR, "display_config", config_string)!=ESP_OK;
}
else {
result = 1;
nerrors = config_set_value(NVS_TYPE_STR, "display_config", config_string)!=ESP_OK;
}
FREE_AND_NULL(name);
FREE_AND_NULL(driver);
fflush (f);
log_send_messaging(nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
fclose(f);
FREE_AND_NULL(buf);
return result;
return nerrors==0;
}
static int do_i2cconfig_cmd(int argc, char **argv)
{
esp_err_t err=ESP_OK;
int res=0;
char * err_message=malloc(1);
int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&i2cconfig_args);
if (nerrors != 0) {
return 0;
}
/* Check "--clear" option */
if (i2cconfig_args.clear->count) {
log_send_messaging(MESSAGING_WARNING,"i2c config cleared");
config_set_value(NVS_TYPE_STR, "i2c_config", "");
return 0;
}
char *buf = NULL;
size_t buf_size = 0;
FILE *f = open_memstream(&buf, &buf_size);
if (f == NULL) {
log_send_messaging(MESSAGING_ERROR,"Unable to open memory stream.");
return 0;
}
/* Check "--load" option */
if (i2cconfig_args.load->count) {
log_send_messaging(MESSAGING_WARNING,"Loading i2c config");
@@ -493,8 +534,8 @@ static int do_i2cconfig_cmd(int argc, char **argv)
/* Check "--port" option */
if (i2cconfig_args.port->count) {
if (i2c_get_port(i2cconfig_args.port->ival[0], &i2c_port) != ESP_OK) {
log_send_messaging(MESSAGING_ERROR, "Invalid port %u ",i2cconfig_args.port->ival[0]);
return 1;
fprintf(f,"Invalid port %u \n",i2cconfig_args.port->ival[0]);
nerrors ++;
}
}
/* Check "--freq" option */
@@ -504,60 +545,67 @@ static int do_i2cconfig_cmd(int argc, char **argv)
if (i2cconfig_args.sda->count){
/* Check "--sda" option */
i2c_gpio_sda = i2cconfig_args.sda->ival[0];
if(!GPIO_IS_VALID_OUTPUT_GPIO(i2c_gpio_sda )){
fprintf(f,"Invalid SDA gpio: %d %s\n", i2c_gpio_sda , GPIO_IS_VALID_GPIO(i2c_gpio_sda )?NOT_OUTPUT:NOT_GPIO );
nerrors ++;
}
}
else {
REALLOC_CAT(err_message,"Missing --sda option.");
res=1;
fprintf(f,"Missing SDA GPIO\n");
nerrors ++;
}
if (i2cconfig_args.scl->count){
/* Check "--sda" option */
/* Check "--scl" option */
i2c_gpio_scl = i2cconfig_args.scl->ival[0];
if(!GPIO_IS_VALID_OUTPUT_GPIO(i2c_gpio_scl )){
fprintf(f,"Invalid SCL gpio: %d %s\n", i2c_gpio_scl , GPIO_IS_VALID_GPIO(i2c_gpio_scl )?NOT_OUTPUT:NOT_GPIO );
nerrors ++;
}
}
else {
REALLOC_CAT(err_message,"Missing --scl option.");
res=1;
fprintf(f,"Missing SCL GPIO\n");
nerrors ++;
}
}
#ifdef CONFIG_SQUEEZEAMP
if (i2c_port == I2C_NUM_0) {
i2c_port = I2C_NUM_1;
log_send_messaging(MESSAGING_ERROR, "can't use i2c port 0 on SqueezeAMP. Changing to port 1.");
fprintf(f,"can't use i2c port 0 on SqueezeAMP. Changing to port 1.\n");
}
#endif
if(!res){
log_send_messaging(MESSAGING_INFO,"Uninstall i2c driver from port %u if needed",i2c_port);
if(!nerrors){
fprintf(f,"Uninstalling i2c driver from port %u if needed\n",i2c_port);
if(is_i2c_started(i2c_port)){
if((err=i2c_driver_delete(i2c_port))!=ESP_OK){
log_send_messaging(MESSAGING_ERROR, "i2c driver delete failed. %s", esp_err_to_name(err));
res = 1;
fprintf(f,"i2c driver delete failed. %s\n", esp_err_to_name(err));
nerrors++;
}
}
}
if(!res){
log_send_messaging(MESSAGING_INFO, "Initializing driver with config scl=%u sda=%u speed=%u port=%u",i2c_gpio_scl,i2c_gpio_sda,i2c_frequency,i2c_port);
if(!nerrors){
fprintf(f,"Initializing driver with config scl=%u sda=%u speed=%u port=%u\n",i2c_gpio_scl,i2c_gpio_sda,i2c_frequency,i2c_port);
if((err=i2c_master_driver_initialize())==ESP_OK){
log_send_messaging(MESSAGING_INFO, "Initalize success.");
fprintf(f,"Initalize success.\n");
// now start the i2c driver
log_send_messaging(MESSAGING_INFO,"Starting the i2c driver.");
fprintf(f,"Starting the i2c driver.");
if((err=i2c_master_driver_install())!=ESP_OK){
log_send_messaging(MESSAGING_ERROR,"I2C master driver install failed. %s", esp_err_to_name(err));
res=1;
fprintf(f,"I2C master driver install failed. %s\n", esp_err_to_name(err));
nerrors++;
}
else
{
log_send_messaging(MESSAGING_INFO,"i2c driver successfully started.");
fprintf(f,"i2c driver successfully started.\n");
}
}
else {
log_send_messaging(MESSAGING_ERROR,"I2C initialization failed. %s", esp_err_to_name(err));
res=1;
fprintf(f,"I2C initialization failed. %s\n", esp_err_to_name(err));
nerrors++;
}
}
if(!res && !i2cconfig_args.load->count){
log_send_messaging(MESSAGING_INFO,"Storing i2c parameters.");
if(!nerrors && !i2cconfig_args.load->count){
fprintf(f,"Storing i2c parameters.\n");
i2c_config_t config={
.mode = I2C_MODE_MASTER,
.sda_io_num = i2c_gpio_sda,
@@ -568,11 +616,12 @@ static int do_i2cconfig_cmd(int argc, char **argv)
};
config_i2c_set(&config, i2c_port);
}
if(res){
log_send_messaging(MESSAGING_ERROR,"%s", err_message);
}
free(err_message);
return res;
fflush (f);
log_send_messaging(nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
fclose(f);
FREE_AND_NULL(buf);
return nerrors==0;
}
#define RUN_SHOW_ERROR(c)
@@ -897,15 +946,19 @@ cJSON * i2c_set_display_cb(){
}
static void register_i2c_set_display(){
char * supported_drivers = display_get_supported_drivers();
i2cdisp_args.address = arg_int0("a", "address", "<n>", "Set the device address, default 60");
i2cdisp_args.width = arg_int0("w", "width", "<n>", "Set the display width");
i2cdisp_args.height = arg_int0("h", "height", "<n>", "Set the display height");
i2cdisp_args.name = arg_str0("t", "type", "<I2C|SPI>", "Display type, I2C or SPI. Default I2C");
i2cdisp_args.driver = arg_str0("d", "driver", "<string>", "Set the display driver name. Default SSD1306");
i2cdisp_args.driver = arg_str0("d", "driver", supported_drivers?supported_drivers:"<string>", "Set the display driver name. Default SSD1306");
i2cdisp_args.clear = arg_lit0(NULL, "clear", "clear configuration and return");
i2cdisp_args.hflip = arg_lit0(NULL, "hf", "Flip picture horizontally");
i2cdisp_args.vflip = arg_lit0(NULL, "vf", "Flip picture vertically");
i2cdisp_args.rotate = arg_lit0("r", "rotate", "Rotate the picture 180 deg");
i2cdisp_args.back = arg_int0("b", "back", "<n>","Backlight GPIO (if applicable)");
i2cdisp_args.speed = arg_int0("s", "speed", "<n>","Default speed is 8000000 (8MHz) for SPI and 250000 for I2C. The SPI interface can work up to 26MHz~40MHz");
i2cdisp_args.end = arg_end(8);
const esp_console_cmd_t i2c_set_display= {
.command = "setdisplay",
@@ -1038,6 +1091,7 @@ cJSON * i2config_cb(){
}
static void register_i2cconfig(void)
{
i2cconfig_args.clear = arg_lit0(NULL, "clear", "clear configuration and return");
i2cconfig_args.port = arg_int0("p", "port", "0|1", "Set the I2C bus port number");
i2cconfig_args.freq = arg_int0("f", "freq", "int", "Set the frequency(Hz) of I2C bus. e.g. 100000");
i2cconfig_args.sda = arg_int0("d", "sda", "int", "Set the gpio for I2C SDA. e.g. 19");

View File

@@ -85,7 +85,7 @@ static void vCallbackFunction( TimerHandle_t xTimer ) {
bool led_blink_core(int idx, int ontime, int offtime, bool pushed) {
if (!leds[idx].gpio || leds[idx].gpio < 0 ) return false;
ESP_LOGD(TAG,"led_blink_core");
ESP_LOGD(TAG,"led_blink_core %d on:%d off:%d, pushed:%u", idx, ontime, offtime, pushed);
if (leds[idx].timer) {
// normal requests waits if a pop is pending
if (!pushed && leds[idx].pushed) {
@@ -231,7 +231,6 @@ 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, green.gpio, green.active, green.pwm );
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"), *p;
if (nvs_item) {
@@ -242,4 +241,6 @@ void led_svc_init(void) {
led_config(LED_GREEN, green.gpio, green.active, green.pwm);
led_config(LED_RED, 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, red.gpio, red.active, red.pwm );
}

View File

@@ -128,12 +128,12 @@ static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val) {
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, (i2c_addr << 1) | 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);
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
@@ -153,15 +153,15 @@ static uint8_t i2c_read_reg(uint8_t reg) {
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, (i2c_addr << 1) | 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_write_byte(cmd, (i2c_addr << 1) | 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);
ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {

View File

@@ -46,27 +46,17 @@ struct buffer *streambuf = &buf;
#define UNLOCK mutex_unlock(streambuf->mutex)
/*
After a lot of hesitation, I've added that "poll mutex" to prevent
socket from being allocated while we are still in poll(). The issue
happens is we have a close quickly followed by an open, we might still
be in the poll() and simple OS fail as they re-allocate the same socket
on which a thread is still waiting.
Ideally, you want to set the lock in the disconnect() but that would mean
very often we'd have to always wait for the end of the poll(), i.e. up to
100ms for nothing most of the time where if it is in the open(), it is
less elegant as closing a socket on which there is a poll() is not good
but it's more efficient as it is very rare that you'd have an open() less
then 100ms after a close()
When LMS sends a close/open sequence very quickly, the stream thread might
still be waiting in the poll() on the closed socket. It is never recommended
to have a thread closing a socket used by another thread but it works, as
opposed to an infinite select().
In stream_sock() a new socket is created and full OS will allocate a different
one but on RTOS and simple IP stack, the same might be re-used and that causes
an exception as a thread is already waiting on a newly allocated socket
A simple variable that forces stream_sock() to wait until we are out of poll()
is enough and much faster than a mutex
*/
#if EMBEDDED
static mutex_type poll_mutex;
#define LOCK_L mutex_lock(poll_mutex)
#define UNLOCK_L mutex_unlock(poll_mutex)
#else
#define LOCK_L
#define UNLOCK_L
#endif
static bool polling;
static sockfd fd;
struct streamstate stream;
@@ -209,7 +199,6 @@ static void *stream_thread() {
} else {
LOCK_L;
pollinfo.fd = fd;
pollinfo.events = POLLIN;
if (stream.state == SEND_HEADERS) {
@@ -218,10 +207,12 @@ static void *stream_thread() {
}
UNLOCK;
// no mutex needed - we just want to know if we are inside poll()
polling = true;
if (_poll(ssl, &pollinfo, 100)) {
UNLOCK_L;
polling = false;
LOCK;
// check socket has not been closed while in poll
@@ -374,7 +365,7 @@ static void *stream_thread() {
UNLOCK;
} else {
UNLOCK_L;
polling = false;
LOG_SDEBUG("poll timeout");
}
}
@@ -427,9 +418,6 @@ void stream_init(log_level level, unsigned stream_buf_size) {
*stream.header = '\0';
fd = -1;
#if EMBEDDED
mutex_create_p(poll_mutex);
#endif
#if LINUX || FREEBSD
touch_memory(streambuf->buf, streambuf->size);
@@ -459,9 +447,6 @@ void stream_close(void) {
#endif
free(stream.header);
buf_destroy(streambuf);
#if EMBEDDED
mutex_destroy(poll_mutex);
#endif
}
void stream_file(const char *header, size_t header_len, unsigned threshold) {
@@ -503,9 +488,12 @@ void stream_file(const char *header, size_t header_len, unsigned threshold) {
void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, unsigned threshold, bool cont_wait) {
struct sockaddr_in addr;
LOCK_L;
#if EMBEDDED
// wait till we are not polling anymore
while (polling && running) { usleep(10000); }
#endif
int sock = socket(AF_INET, SOCK_STREAM, 0);
UNLOCK_L;
if (sock < 0) {
LOG_ERROR("failed to create socket");

View File

@@ -253,6 +253,10 @@ void process_received_data(const char * buffer, size_t size){
if(bMirrorToUART){
write(uart_fd, command, size);
}
for(int i=strlen(command);i>=0;i--){
// strip any cr/lf
if(command[i]== '\n' || command[i]== '\r') command[i]= '\0';
}
run_command((char *)command);
}
free(command);

View File

@@ -63,8 +63,19 @@ var checkStatusInterval = null;
var StatusIntervalActive = false;
var RefreshAPIIntervalActive = false;
var LastRecoveryState=null;
var LastCommandsState=null;
var output = '';
function delay_msg(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, v), t)
});
}
Promise.prototype.delay = function(t) {
return this.then(function(v) {
return delay_msg(t, v);
});
}
function stopCheckStatusInterval(){
if(checkStatusInterval != null){
clearTimeout(checkStatusInterval);
@@ -100,8 +111,98 @@ function RepeatRefreshAPInterval(){
if(RefreshAPIIntervalActive)
startRefreshAPInterval();
}
function getConfigJson(slimMode){
var config = {};
$("input.nvs").each(function() {
var key = $(this)[0].id;
var val = $(this).val();
if(!slimMode){
var nvs_type = parseInt($(this)[0].attributes.nvs_type.nodeValue,10);
if (key != '') {
config[key] = {};
if(nvs_type == nvs_type_t.NVS_TYPE_U8
|| nvs_type == nvs_type_t.NVS_TYPE_I8
|| nvs_type == nvs_type_t.NVS_TYPE_U16
|| nvs_type == nvs_type_t.NVS_TYPE_I16
|| nvs_type == nvs_type_t.NVS_TYPE_U32
|| nvs_type == nvs_type_t.NVS_TYPE_I32
|| nvs_type == nvs_type_t.NVS_TYPE_U64
|| nvs_type == nvs_type_t.NVS_TYPE_I64) {
config[key].value = parseInt(val);
}
else {
config[key].value = val;
}
config[key].type = nvs_type;
}
}
else {
config[key] = val;
}
});
var key = $("#nvs-new-key").val();
var val = $("#nvs-new-value").val();
if (key != '') {
if(!slimMode){
config[key] = {};
config[key].value = val;
config[key].type = 33;
}
else {
config[key] = val;
}
}
return config;
}
function onFileLoad(elementId, event) {
var data={};
try{
data = JSON.parse(elementId.srcElement.result);
}
catch (e){
alert('Parsing failed!\r\n '+ e);
}
$("input.nvs").each(function() {
var key = $(this)[0].id;
var val = $(this).val();
if(data[key]){
if(data[key] != val){
console.log("Changed "& key & " " & val & "==>" & data[key]);
$(this).val(data[key]);
}
}
else {
console.log("Value " & key & " missing from file");
}
});
}
function onChooseFile(event, onLoadFileHandler) {
if (typeof window.FileReader !== 'function')
throw ("The file API isn't supported on this browser.");
let input = event.target;
if (!input)
throw ("The browser does not properly implement the event object");
if (!input.files)
throw ("This browser does not support the `files` property of the file input.");
if (!input.files[0])
return undefined;
let file = input.files[0];
let fr = new FileReader();
fr.onload = onLoadFileHandler;
fr.readAsText(file);
input.value="";
}
$(document).ready(function(){
$("input#show-commands")[0].checked=LastCommandsState==1?true:false;
$('a[href^="#tab-commands"]').hide();
$("#load-nvs").click(function () {
$("#nvsfilename").trigger('click');
});
$("#wifi-status").on("click", ".ape", function() {
$( "#wifi" ).slideUp( "fast", function() {});
$( "#connect-details" ).slideDown( "fast", function() {});
@@ -210,6 +311,17 @@ $(document).ready(function(){
$( "#wifi" ).slideDown( "fast", function() {})
});
$("input#show-commands").on("click", function() {
this.checked=this.checked?1:0;
if(this.checked){
$('a[href^="#tab-commands"]').show();
LastCommandsState = 1;
} else {
LastCommandsState = 0;
$('a[href^="#tab-commands"]').hide();
}
});
$("input#show-nvs").on("click", function() {
this.checked=this.checked?1:0;
if(this.checked){
@@ -334,42 +446,27 @@ $(document).ready(function(){
console.log('sent config JSON with data:', JSON.stringify(data));
});
$("#save-as-nvs").on("click", function() {
var data = { 'timestamp': Date.now() };
var config = getConfigJson(true);
const a = document.createElement("a");
a.href = URL.createObjectURL(
new Blob([JSON.stringify(config, null, 2)], {
type: "text/plain"
}));
a.setAttribute("download", "nvs_config" + Date.now() +"json");
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
console.log('sent config JSON with headers:', JSON.stringify(headers));
console.log('sent config JSON with data:', JSON.stringify(data));
});
$("#save-nvs").on("click", function() {
var headers = {};
var data = { 'timestamp': Date.now() };
var config = {};
$("input.nvs").each(function() {
var key = $(this)[0].id;
var val = $(this).val();
var nvs_type = parseInt($(this)[0].attributes.nvs_type.nodeValue,10);
if (key != '') {
config[key] = {};
if(nvs_type == nvs_type_t.NVS_TYPE_U8
|| nvs_type == nvs_type_t.NVS_TYPE_I8
|| nvs_type == nvs_type_t.NVS_TYPE_U16
|| nvs_type == nvs_type_t.NVS_TYPE_I16
|| nvs_type == nvs_type_t.NVS_TYPE_U32
|| nvs_type == nvs_type_t.NVS_TYPE_I32
|| nvs_type == nvs_type_t.NVS_TYPE_U64
|| nvs_type == nvs_type_t.NVS_TYPE_I64) {
config[key].value = parseInt(val);
}
else {
config[key].value = val;
}
config[key].type = nvs_type;
}
});
var key = $("#nvs-new-key").val();
var val = $("#nvs-new-value").val();
if (key != '') {
// headers["X-Custom-" +key] = val;
config[key] = {};
config[key].value = val;
config[key].type = 33;
}
var config = getConfigJson(false);
data['config'] = config;
$.ajax({
url: '/config.json',
@@ -421,7 +518,6 @@ $(document).ready(function(){
fwurl : {
value : url,
type : 33
}
};
@@ -935,19 +1031,22 @@ function checkStatus(){
blockAjax = false;
});
}
function runCommand(button) {
function runCommand(button,reboot) {
pardiv = button.parentNode.parentNode;
fields=document.getElementById("flds-"+button.value);
cmdstring=button.value+' ';
cmdstring = button.attributes.cmdname.value;
fields=document.getElementById("flds-"+cmdstring);
cmdstring+=' ';
if(fields){
hint = pardiv.hint;
allfields=fields.getElementsByTagName("input");
allfields=fields.querySelectorAll("select,input");
for (i = 0; i < allfields.length; i++) {
attr=allfields[i].attributes;
qts='';
opt='';
optspacer=' ';
isSelect=allfields[i].attributes?.class?.value=="custom-select";
if(( isSelect && allfields[i].selectedIndex != 0 )|| !isSelect ){
if (attr.longopts.value!== "undefined"){
opt+= '--' + attr.longopts.value;
optspacer='=';
@@ -968,6 +1067,7 @@ function runCommand(button) {
}
}
}
}
console.log(cmdstring);
var data = { 'timestamp': Date.now() };
@@ -984,6 +1084,35 @@ function runCommand(button) {
console.log(xhr.status);
console.log(thrownError);
if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR');
},
complete: function(response) {
//var returnedResponse = JSON.parse(response.responseText);
console.log(response.responseText);
if(reboot){
showMessage('Applying. Please wait for the ESP32 to reboot', 'MESSAGING_WARNING');
console.log('now triggering reboot');
$.ajax({
url: '/reboot.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ 'timestamp': Date.now()}),
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR');
},
complete: function(response) {
console.log('reboot call completed');
Promise.resolve().delay(5000).then(function(v) {
console.log('Getting updated commands');
getCommands();
});
}
});
}
}
});
enableStatusTimer = true;
@@ -993,43 +1122,54 @@ function runCommand(button) {
function getCommands() {
$.getJSON("/commands.json", function(data) {
console.log(data);
innerhtml='';
var advancedtabhtml='';
data.commands.forEach(function(command) {
innerhtml+='<tr><td>';
innerhtml+=escapeHTML(command.help).replace(/\n/g, '<br />')+'<br>';
if($("#flds-"+command.name).length == 0){
isConfig=($('#'+command.name+'-list').length>0);
innerhtml='';
innerhtml+='<tr><td>'+(isConfig?'<h1>':'');
innerhtml+=escapeHTML(command.help).replace(/\n/g, '<br />')+(isConfig?'</h1>':'<br>');
innerhtml+='<div >';
if(command.hasOwnProperty("argtable")){
innerhtml+='<table class="table table-hover" id="flds-'+command.name+'"><tbody>';
command.argtable.forEach(function (arg){
innerhtml+="<tr>";
placeholder=arg?.datatype || '';
ctrlname=command.name+'-'+arg.longopts;
innerhtml+='<td><label for="'+ctrlname+'">'+ arg.glossary+'</label></td>';
curvalue=data.values?.[command.name]?.[arg.longopts] || '';
innerhtml+="<tr>";
var attributes ='datatype="'+arg.datatype+'" ';
attributes+='hasvalue='+arg.hasvalue+' ';
attributes+='longopts="'+arg.longopts+'" ';
attributes+='shortopts="'+arg.shortopts+'" ';
attributes+='checkbox='+arg.checkbox+' ';
attributes+='cmdname="'+command.name+'" ';
attributes+= 'id="'+ctrlname+'" name="'+ctrlname+'" placeholder="'+placeholder+'" hasvalue="'+arg.hasvalue+'" ';
if(placeholder.includes('|')){
placeholder = placeholder.replace('<','').replace('>','');
innerhtml+='<td><select ';
innerhtml+=attributes;
innerhtml+=' class="custom-select">';
innerhtml+='<option '+(curvalue.length>0?'value':'selected')+'>'+arg.glossary+'</option>'
placeholder.split('|').forEach(function(choice){
innerhtml+='<option '+(curvalue.length>0&&curvalue==choice?'selected':'value')+'="'+choice+'">'+choice+'</option>';
});
innerhtml+='</select></td>';
}
else {
ctrltype="text";
if(arg.checkbox){
ctrltype="checkbox";
}
curvalue=data.values?.[command.name]?.[arg.longopts] || '';
placeholder=arg?.datatype || '';
innerhtml+='<td><input type="'+ctrltype+'" id="'+ctrlname+'" name="'+ctrlname+'" placeholder="'+placeholder+'" hasvalue="'+arg.hasvalue+'" ';
innerhtml+='datatype="'+arg.datatype+'" ';
innerhtml+='hasvalue='+arg.hasvalue+' ';
innerhtml+='longopts="'+arg.longopts+'" ';
innerhtml+='shortopts="'+arg.shortopts+'" ';
innerhtml+='checkbox='+arg.checkbox+' ';
innerhtml+='<td><label for="'+ctrlname+'">'+ arg.glossary+'</label></td>';
innerhtml+='<td><input type="'+ctrltype+'"';
innerhtml+=attributes;
if(arg.checkbox){
if(curvalue=data.values?.[command.name]?.[arg.longopts] ){
innerhtml+='checked=true ';
if(data.values?.[command.name]?.[arg.longopts] ){
innerhtml+='checked ';
}
else{
innerhtml+='checked=false ';
}
innerhtml+='></input></td>';
}
@@ -1037,16 +1177,40 @@ function getCommands() {
innerhtml+='value="'+curvalue+'" ';
innerhtml+='></input></td>'+ curvalue.length>0?'<td>last: '+curvalue+'</td>':'';
}
}
innerhtml+="</tr>";
});
innerhtml+='</tbody></table><br>';
innerhtml+='</tbody></table>';
}
innerhtml+='<div class="buttons"><input id="btn-'+ command.name + '" type="button" class="btn btn-danger btn-sm" value="'+command.name+'" onclick="runCommand(this);"></div></div><td></tr>';
if(isConfig){
innerhtml+='<div class="buttons"><input id="btn-'+ command.name + '" type="button" class="btn btn-success" cmdname="'+command.name+'" value="Save" onclick="runCommand(this,false);">';
innerhtml+='<input id="btn-'+ command.name + '-apply" type="button" class="btn btn-success" cmdname="'+command.name+'" value="Apply" onclick="runCommand(this,true);"></div></div><td></tr>';
$('#'+command.name+'-list').append(innerhtml);
}
else {
advancedtabhtml+='<br>'+innerhtml;
advancedtabhtml+='<div class="buttons"><input id="btn-'+ command.name + '" type="button" class="btn btn-danger btn-sm" cmdname="'+command.name+'" value="'+command.name+'" onclick="runCommand(this, false);"></div></div><td></tr>';
}
}
});
$("#commands-list").append(advancedtabhtml);
data.commands.forEach(function(command) {
if(command.hasOwnProperty("argtable")){
command.argtable.forEach(function (arg){
ctrlselector='#'+command.name+'-'+arg.longopts;
if(arg.checkbox){
$(ctrlselector)[0].checked=data.values?.[command.name]?.[arg.longopts];
}
else {
$(ctrlselector)[0].value=data.values?.[command.name]?.[arg.longopts] || '';
}
});
$("#commands-list").append(innerhtml);
}
});
})
.fail(function(xhr, ajaxOptions, thrownError) {
@@ -1114,7 +1278,6 @@ function getConfig() {
});
}
function showMessage(message, severity, age=0) {
if (severity == 'MESSAGING_INFO') {
$('#message').css('background', '#6af');

View File

@@ -721,6 +721,7 @@ esp_err_t config_post_handler(httpd_req_t *req){
if(err==ESP_OK){
httpd_resp_sendstr(req, "{ \"result\" : \"OK\" }");
messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Save Success");
}
cJSON_Delete(root);
if(bOTA) {

View File

@@ -67,11 +67,14 @@
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-firmware">Firmware</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-setdisplay">Configuration</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-syslog">Syslog</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-commands">System</a>
<a class="nav-link" data-toggle="tab" href="#tab-commands">Advanced</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-nvs">NVS editor</a>
@@ -81,7 +84,6 @@
</li>
</ul>
<div id="message"></div>
<div id="content">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active show" id="tab-wifi">
@@ -195,6 +197,11 @@
</div>
</div>
</div> <!-- wifi -->
<div class="tab-pane fade" id="tab-setdisplay">
<table class="table table-hover" id="setdisplay-table"><tbody id="setdisplay-list"></tbody></table>
<table class="table table-hover" id="i2cconfig-table"><tbody id="i2cconfig-list"></tbody></table>
<table class="table table-hover" id="spiset-table"><tbody id="spiset-list"></tbody></table>
</div> <!-- display -->
<div class="tab-pane fade" id="tab-audio">
<div id="audioout">
@@ -304,7 +311,6 @@
</tbody>
</table>
</div> <!-- system -->
<div class="tab-pane fade" id="tab-syslog">
<table class="table table-hover">
<thead>
@@ -338,7 +344,10 @@
<button id="reboot-button" type="submit" class="btn btn-primary">Reboot</button>
</form>
</div>
<input id="save-nvs" type="button" class="btn btn-success" value="Save" />
<input id="save-nvs" type="button" class="btn btn-success" value="Commit">
<input id="save-as-nvs" type="button" class="btn btn-success" value="Download config">
<input id="load-nvs" type="button" class="btn btn-success" value="Load File">
<input aria-describedby="fileHelp" onchange="onChooseFile(event, onFileLoad.bind(this))" id="nvsfilename" type="file" style="display:none">
</div>
</div> <!-- nvs -->
@@ -363,6 +372,11 @@
<input type="checkbox" class="custom-control-input" id="show-nvs" checked="checked">
<label class="custom-control-label" for="show-nvs"></label>
</div>
<h2>Show Advanced Commands</h2>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="show-commands" checked="checked">
<label class="custom-control-label" for="show-commands"></label>
</div>
</div> <!-- credits -->
</div>
<footer class="footer"><span id="foot-fw"></span><span id="foot-wifi"></span></footer>

View File

@@ -462,7 +462,11 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
cJSON_AddNumberToObject(root,"Voltage", battery_value_svc());
cJSON_AddNumberToObject(root,"disconnect_count", num_disconnect );
cJSON_AddNumberToObject(root,"avg_conn_time", num_disconnect>0?(total_connected_time/num_disconnect):0 );
#if CONFIG_I2C_LOCKED
cJSON_AddTrueToObject(root, "is_i2c_locked");
#else
cJSON_AddFalseToObject(root, "is_i2c_locked");
#endif
ESP_LOGV(TAG, "wifi_manager_get_basic_info done");
return root;
}

View File

@@ -44,7 +44,7 @@ menu "Squeezelite-ESP32"
string
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 "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020
default ""
config SPDIF_CONFIG
string

View File

@@ -447,7 +447,7 @@ void app_main()
/* start the wifi manager */
ESP_LOGD(TAG,"Blinking led");
led_blink(LED_GREEN, 250, 250);
led_blink_pushed(LED_GREEN, 250, 250);
if(bypass_wifi_manager){
ESP_LOGW(TAG,"*******************************************************************************************");

Binary file not shown.

View File

@@ -78,7 +78,7 @@ sub displayWidth {
if ($display->widthOverride) {
my $artwork = $prefs->client($client)->get('artwork');
if ($artwork->{'enable'} && $artwork->{'y'} < 32 && ($client->isPlaying || $client->isPaused)) {
return $artwork->{x} + ($display->modes->[$mode || 0]{_width} || 0);
return ($artwork->{x} || $display->widthOverride) + ($display->modes->[$mode || 0]{_width} || 0);
} else {
return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
}
@@ -113,9 +113,9 @@ sub build_modes {
my $artwork = $cprefs->get('artwork');
my $disp_width = $cprefs->get('width') || 128;
# if artwork is in main display, reduce width
my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32) ? $artwork->{'x'} : $disp_width;
my $width_low = ($artwork->{'enable'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width;
# if artwork is in main display, reduce width but when artwork is (0,0) fake it
my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32 && $artwork->{'x'}) ? $artwork->{'x'} : $disp_width;
my $width_low = ($artwork->{'enable'} && $artwork->{'x'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width;
my $small_VU = $cprefs->get('small_VU');
my $spectrum = $cprefs->get('spectrum');

View File

@@ -13,6 +13,19 @@ my $sprefs = preferences('server');
my $prefs = preferences('plugin.squeezeesp32');
my $log = logger('plugin.squeezeesp32');
{
__PACKAGE__->mk_accessor('rw', 'tone_update');
}
sub new {
my $class = shift;
my $client = $class->SUPER::new(@_);
$client->init_accessor(
tone_update => 0,
);
return $client;
}
our $defaultPrefs = {
'analogOutMode' => 0,
'bass' => 0,
@@ -44,7 +57,6 @@ sub hasIR { 1 }
# TODO: add in settings when ready
sub hasLineIn { 0 }
sub hasHeadSubOut { 1 }
# TODO: LMS sliders are hard-coded in html file from -23 to +23
sub maxTreble { 20 }
sub minTreble { -13 }
sub maxBass { 20 }
@@ -117,25 +129,41 @@ sub playerSettingsFrame {
}
sub bass {
return tone(2, @_);
my ($client, $new) = @_;
my $value = $client->SUPER::bass($new);
$client->update_equalizer($value, [2, 1, 3]) if defined $new;
return $value;
}
sub treble {
return tone(8, @_);
my ($client, $new) = @_;
my $value = $client->SUPER::treble($new);
$client->update_equalizer($value, [8, 9, 7]) if defined $new;
return $value;
}
sub tone {
my ($center, $client, $value) = @_;
my $equalizer = $prefs->client($client)->get('equalizer');
sub update_equalizer {
my ($client, $value, $index) = @_;
return if $client->tone_update;
if (defined($value)) {
$equalizer->[$center-1] = int($value * 0.2 + 0.5);
$equalizer->[$center] = int($value * 0.7 + 0.5);
$equalizer->[$center+1] = int($value * 0.1 + 0.5);
my $equalizer = $prefs->client($client)->get('equalizer');
$equalizer->[$index->[0]] = $value;
$equalizer->[$index->[1]] = int($value / 2 + 0.5);
$equalizer->[$index->[2]] = int($value / 4 + 0.5);
$prefs->client($client)->set('equalizer', $equalizer);
}
return int($equalizer->[$center-1] * 0.2 + $equalizer->[$center] * 0.7 + $equalizer->[$center+1] * 0.1);
sub update_tones {
my ($client, $equalizer) = @_;
$client->tone_update(1);
$sprefs->client($client)->set('bass', int(($equalizer->[1] * 2 + $equalizer->[2] + $equalizer->[3] * 4) / 7 + 0.5));
$sprefs->client($client)->set('treble', int(($equalizer->[7] * 4 + $equalizer->[8] + $equalizer->[9] * 2) / 7 + 0.5));
$client->tone_update(0);
}
sub update_artwork {
@@ -193,6 +221,11 @@ sub clear_artwork {
if ($artwork && $artwork->{'enable'}) {
main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . $request->getRequestString());
$client->pluginData('artwork_md5', '');
# refresh screen and disable artwork when artwork was full screen (hack)
if (!$artwork->{'x'} && !$artwork->{'y'}) {
$client->sendFrame(grfa => \("\x00"x4)) unless $artwork->{'x'} || $artwork->{'y'};
$client->display->update;
}
}
}

View File

@@ -31,7 +31,7 @@ sub page {
sub prefs {
my ($class, $client) = @_;
my @prefs;
push @prefs, qw(width small_VU) if $client->displayWidth;
push @prefs, qw(width small_VU) if defined $client->displayWidth;
return ($prefs->client($client), @prefs);
}
@@ -41,7 +41,7 @@ sub handler {
my ($cprefs, @prefs) = $class->prefs($client);
if ($paramRef->{'saveSettings'}) {
if ($client->displayWidth) {
if (defined $client->displayWidth) {
$cprefs->set('small_VU', $paramRef->{'pref_small_VU'} || 15);
my $spectrum = {
scale => $paramRef->{'pref_spectrum_scale'} || 25,
@@ -73,9 +73,10 @@ sub handler {
$equalizer->[$i] = $paramRef->{"pref_equalizer.$i"} || 0;
}
$cprefs->set('equalizer', $equalizer);
$client->update_tones($equalizer);
}
if ($client->displayWidth) {
if (defined $client->displayWidth) {
# the Settings super class can't handle anything but scalar values
# we need to populate the $paramRef for the other prefs manually
$paramRef->{'pref_spectrum'} = $cprefs->get('spectrum');

View File

@@ -10,6 +10,6 @@
<name>PLUGIN_SQUEEZEESP32</name>
<description>PLUGIN_SQUEEZEESP32_DESC</description>
<module>Plugins::SqueezeESP32::Plugin</module>
<version>0.100</version>
<version>0.104</version>
<creator>Philippe</creator>
</extensions>

View File

@@ -1,10 +1,10 @@
<?xml version='1.0' standalone='yes'?>
<extensions>
<plugins>
<plugin version="0.100" name="SqueezeESP32" minTarget="7.9" maxTarget="*">
<plugin version="0.104" name="SqueezeESP32" minTarget="7.9" maxTarget="*">
<link>https://github.com/sle118/squeezelite-esp32</link>
<creator>Philippe</creator>
<sha>572fa8afeaa3bc3cfb245b8d42ba05739aec584b</sha>
<sha>79e505a30d7b6dbf43893acab176d57438e2a4a1</sha>
<email>philippe_44@outlook.com</email>
<desc lang="EN">SqueezeESP32 additional player id (100)</desc>
<url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>