mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-06 19:47:02 +03:00
Improved audio ui, bug fixes
This commit is contained in:
@@ -121,7 +121,7 @@ void config_start_timer(){
|
||||
nvs_type_t config_get_item_type(cJSON * entry){
|
||||
if(entry==NULL){
|
||||
ESP_LOGE(TAG,"null pointer received!");
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
cJSON * item_type = cJSON_GetObjectItemCaseSensitive(entry, "type");
|
||||
if(item_type ==NULL ) {
|
||||
@@ -142,7 +142,7 @@ cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key, const void
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
||||
cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
||||
if(existing !=NULL && nvs_type == NVS_TYPE_STR && config_get_item_type(existing) != NVS_TYPE_STR ) {
|
||||
ESP_LOGW(TAG, "Storing numeric value from string");
|
||||
numvalue = atof((char *)value);
|
||||
|
||||
@@ -61,21 +61,19 @@ static void squeezelite_thread(void *arg){
|
||||
for(int i = 0;i<thread_parms.argc; i++){
|
||||
ESP_LOGV(TAG ," %s",thread_parms.argv[i]);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG ,"Calling squeezelite");
|
||||
int ret = squeezelite_main(thread_parms.argc, thread_parms.argv);
|
||||
|
||||
messaging_post_message(ret > 1 ? MESSAGING_ERROR : MESSAGING_WARNING,
|
||||
MESSAGING_CLASS_SYSTEM, "squeezelite exited with error code %d", ret);
|
||||
cmd_send_messaging("cfg-audio-tmpl",ret > 1 ? MESSAGING_ERROR : MESSAGING_WARNING,"squeezelite exited with error code %d\n", ret);
|
||||
|
||||
if (ret == 1) {
|
||||
int wait = 60;
|
||||
int wait = 60;
|
||||
wait_for_commit();
|
||||
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Rebooting in %d sec", wait);
|
||||
cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Rebooting in %d sec\n", wait);
|
||||
vTaskDelay( pdMS_TO_TICKS(wait * 1000));
|
||||
esp_restart();
|
||||
} else {
|
||||
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Correct command line and reboot");
|
||||
cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Correct command line and reboot\n");
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
|
||||
561
components/squeezelite/cs4265/cs4265.c
Normal file
561
components/squeezelite/cs4265/cs4265.c
Normal file
@@ -0,0 +1,561 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "adac.h"
|
||||
#include "stdio.h"
|
||||
#include "math.h"
|
||||
#define CS4265_PULL_UP (0x4F )
|
||||
#define CS4265_PULL_DOWN (0x4E )
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
static const char TAG[] = "CS4265";
|
||||
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
static void speaker(bool active);
|
||||
static void headset(bool active);
|
||||
static bool volume(unsigned left, unsigned right);
|
||||
static void power(adac_power_e mode);
|
||||
static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val );
|
||||
static esp_err_t set_clock();
|
||||
const struct adac_s dac_cs4265 = { "CS4265", init, adac_deinit, power, speaker, headset, volume };
|
||||
|
||||
struct cs4265_cmd_s {
|
||||
uint8_t reg;
|
||||
uint8_t value;
|
||||
};
|
||||
struct cs4265_private {
|
||||
uint8_t format;
|
||||
uint32_t sysclk;
|
||||
i2s_config_t *i2s_config;
|
||||
int i2c_port;
|
||||
};
|
||||
struct cs4265_private cs4265;
|
||||
|
||||
#define CS4265_CHIP_ID 0x1
|
||||
#define CS4265_CHIP_ID_VAL 0xD0
|
||||
#define CS4265_CHIP_ID_MASK 0xF0
|
||||
#define CS4265_REV_ID_MASK 0x0F
|
||||
|
||||
#define CS4265_PWRCTL 0x02
|
||||
#define CS4265_PWRCTL_PDN (1 << 0)
|
||||
#define CS4265_PWRCTL_PDN_DAC (1 << 1)
|
||||
#define CS4265_PWRCTL_PDN_ADC (1 << 2)
|
||||
#define CS4265_PWRCTL_PDN_MIC (1 << 3)
|
||||
#define CS4265_PWRCTL_FREEZE (1 << 7)
|
||||
#define CS4265_PWRCTL_PDN_ALL CS4265_PWRCTL_PDN | CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC
|
||||
|
||||
|
||||
|
||||
#define CS4265_DAC_CTL 0x3
|
||||
// De-Emphasis Control (Bit 1)
|
||||
// The standard 50/15 i2s digital de-emphasis filter response may be implemented for a sample
|
||||
// rate of 44.1 kHz when the DeEmph bit is set. NOTE: De-emphasis is available only in Single-Speed Mode.
|
||||
#define CS4265_DAC_CTL_DEEMPH (1 << 1)
|
||||
// MUTE DAC
|
||||
// The DAC outputs will mute and the MUTEC pin will become active when this bit is set. Though this bit is
|
||||
// active high, it should be noted that the MUTEC pin is active low. The common mode voltage on the outputs
|
||||
// will be retained when this bit is set. The muting function is effected, similar to attenuation changes, by the
|
||||
// DACSoft and DACZero bits in the DAC Control 2 register.
|
||||
#define CS4265_DAC_CTL_MUTE (1 << 2)
|
||||
// The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
|
||||
// DAC_DIF1 DAC_DIF0 Description Format Figure
|
||||
// 0 0 Left Justified, up to 24-bit data (default) 0 5
|
||||
// 0 1 I²S, up to 24-bit data 1 6
|
||||
// 1 0 Right-Justified, 16-bit Data 2 7
|
||||
// 1 1 Right-Justified, 24-bit Data 3 7
|
||||
#define CS4265_DAC_CTL_DIF0 (1 << 4)
|
||||
// The required relationship between LRCK, SCLK and SDIN for the DAC is defined by the DAC Digital Interface
|
||||
// DAC_DIF1 DAC_DIF0 Description Format Figure
|
||||
// 0 0 Left Justified, up to 24-bit data (default) 0 5
|
||||
// 0 1 I²S, up to 24-bit data 1 6
|
||||
// 1 0 Right-Justified, 16-bit Data 2 7
|
||||
// 1 1 Right-Justified, 24-bit Data 3 7
|
||||
#define CS4265_DAC_CTL_DIF1 (1 << 5)
|
||||
|
||||
|
||||
|
||||
#define CS4265_ADC_CTL 0x4
|
||||
#define CS4265_ADC_MASTER 1
|
||||
|
||||
#define CS4265_ADC_CTL_MUTE (1 << 2)
|
||||
#define CS4265_ADC_DIF (1 << 4)
|
||||
#define CS4265_ADC_FM (3 << 6)
|
||||
|
||||
//Master Clock Dividers (Bits 6:4)
|
||||
//Sets the frequency of the supplied MCLK signal.
|
||||
//
|
||||
//MCLK Divider MCLK Freq2 MCLK Freq1 MCLK Freq0
|
||||
// ÷ 1 0 0 0
|
||||
// ÷ 1.5 0 0 1
|
||||
// ÷ 2 0 1 0
|
||||
// ÷ 3 0 1 1
|
||||
// ÷ 4 1 0 0
|
||||
// NA 1 0 1
|
||||
// NA 1 1 x
|
||||
#define CS4265_MCLK_FREQ 0x5
|
||||
#define CS4265_MCLK_FREQ_1_0X (0b000<<4 )
|
||||
#define CS4265_MCLK_FREQ_1_5X (0b001<<4 )
|
||||
#define CS4265_MCLK_FREQ_2_0X (0b010<<4 )
|
||||
#define CS4265_MCLK_FREQ_3_0X (0b011<<4 )
|
||||
#define CS4265_MCLK_FREQ_4_0X (0b100<<4 )
|
||||
|
||||
|
||||
#define CS4265_MCLK_FREQ_MASK (7 << 4)
|
||||
|
||||
#define CS4265_SIG_SEL 0x6
|
||||
#define CS4265_SIG_SEL_LOOP (1 << 1)
|
||||
#define CS4265_SIG_SEL_SDIN2 (1 << 7)
|
||||
#define CS4265_SIG_SEL_SDIN1 (0 << 7)
|
||||
|
||||
// Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
|
||||
// +12 dB in 0.5 dB steps. The gain bits are in two’s complement with the Gain0 bit set for a 0.5 dB step.
|
||||
// Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
|
||||
#define CS4265_CHB_PGA_CTL 0x7
|
||||
// Sets the gain or attenuation for the ADC input PGA stage. The gain may be adjusted from -12 dB to
|
||||
// +12 dB in 0.5 dB steps. The gain bits are in two’s complement with the Gain0 bit set for a 0.5 dB step.
|
||||
// Register settings outside of the ±12 dB range are reserved and must not be used. See Table 13 for example settings
|
||||
#define CS4265_CHA_PGA_CTL 0x8
|
||||
// Gain[5:0] Setting
|
||||
// 101000 -12 dB
|
||||
// 000000 0 dB
|
||||
// 011000 +12 dB
|
||||
|
||||
|
||||
#define CS4265_ADC_CTL2 0x9
|
||||
|
||||
// The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
|
||||
// The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
|
||||
// activate attenuation equal to their decimal equivalent (in dB).
|
||||
//Binary Code Volume Setting
|
||||
//00000000 0 dB
|
||||
//00000001 -0.5 dB
|
||||
//00101000 -20 dB
|
||||
//00101001 -20.5 dB
|
||||
//11111110 -127 dB
|
||||
//11111111 -127.5 dB
|
||||
#define CS4265_DAC_CHA_VOL 0xA
|
||||
// The digital volume control allows the user to attenuate the signal in 0.5 dB increments from 0 to -127 dB.
|
||||
// The Vol0 bit activates a 0.5 dB attenuation when set, and no attenuation when cleared. The Vol[7:1] bits
|
||||
// activate attenuation equal to their decimal equivalent (in dB).
|
||||
//Binary Code Volume Setting
|
||||
//00000000 0 dB
|
||||
//00000001 -0.5 dB
|
||||
//00101000 -20 dB
|
||||
//00101001 -20.5 dB
|
||||
//11111110 -127 dB
|
||||
//11111111 -127.5 dB
|
||||
#define CS4265_DAC_CHB_VOL 0xB
|
||||
#define CS4265_DAC_VOL_ATT_000_0 0b00000000
|
||||
#define CS4265_DAC_VOL_ATT_000_5 0b00000001
|
||||
#define CS4265_DAC_VOL_ATT_020_0 0b00101000
|
||||
#define CS4265_DAC_VOL_ATT_020_5 0b00101001
|
||||
#define CS4265_DAC_VOL_ATT_127_0 0b11111110
|
||||
#define CS4265_DAC_VOL_ATT_127_5 0b11111111
|
||||
|
||||
// DAC Soft Ramp or Zero Cross Enable (Bits 7:6)
|
||||
//
|
||||
// Soft Ramp Enable
|
||||
// Soft Ramp allows level changes, both muting and attenuation, to be implemented by incrementally ramping, in 1/8 dB steps, from the current level to the new level at a rate of 1 dB per 8 left/right clock periods.
|
||||
// See Table 17.
|
||||
// Zero Cross Enable
|
||||
// Zero Cross Enable dictates that signal-level changes, either by attenuation changes or muting, will occur
|
||||
// on a signal zero crossing to minimize audible artifacts. The requested level change will occur after a timeout period between 512 and 1024 sample periods (10.7 ms to 21.3 ms at 48 kHz sample rate) if the signal
|
||||
// does not encounter a zero crossing. The zero cross function is independently monitored and implemented
|
||||
// for each channel. See Table 17.
|
||||
// Soft Ramp and Zero Cross Enable
|
||||
// Soft Ramp and Zero Cross Enable dictate that signal-level changes, either by attenuation changes or muting, will occur in 1/8 dB steps and be implemented on a signal zero crossing. The 1/8 dB level change will
|
||||
// occur after a time-out period between 512 and 1024 sample periods (10.7 ms to 21.3 ms at 48 kHz sample rate) if the signal does not encounter a zero crossing. The zero cross function is independently monitored and implemented for each channel
|
||||
// DACSoft DACZeroCross Mode
|
||||
// 0 0 Changes to affect immediately
|
||||
// 0 1 Zero Cross enabled
|
||||
// 1 0 Soft Ramp enabled
|
||||
// 1 1 Soft Ramp and Zero Cross enabled (default)
|
||||
#define CS4265_DAC_CTL2 0xC
|
||||
#define CS4265_DAC_CTL2_ZERO_CROSS_EN (uint8_t)(0b01 <<7)
|
||||
#define CS4265_DAC_CTL2_SOFT_RAMP_EN (uint8_t)(0b10 <<7)
|
||||
#define CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN (uint8_t)(0b11 <<7)
|
||||
|
||||
|
||||
#define CS4265_INT_STATUS 0xD
|
||||
#define CS4265_INT_STATUS_ADC_UNDF (1<<0)
|
||||
#define CS4265_INT_STATUS_ADC_OVF (1<<1)
|
||||
#define CS4265_INT_STATUS_CLKERR (1<<3)
|
||||
|
||||
|
||||
#define CS4265_INT_MASK 0xE
|
||||
#define CS4265_STATUS_MODE_MSB 0xF
|
||||
#define CS4265_STATUS_MODE_LSB 0x10
|
||||
|
||||
//Transmitter Control 1 - Address 11h
|
||||
#define CS4265_SPDIF_CTL1 0x11
|
||||
|
||||
|
||||
|
||||
#define CS4265_SPDIF_CTL2 0x12
|
||||
// Transmitter Digital Interface Format (Bits 7:6)
|
||||
// Function:
|
||||
// The required relationship between LRCK, SCLK and SDIN for the transmitter is defined
|
||||
// Tx_DIF1 Tx_DIF0 Description Format Figure
|
||||
// 0 0 Left Justified, up to 24-bit data (default) 0 5
|
||||
// 0 1 I²S, up to 24-bit data 1 6
|
||||
// 1 0 Right-Justified, 16-bit Data 2 7
|
||||
// 1 1 Right-Justified, 24-bit Data 3 7
|
||||
#define CS4265_SPDIF_CTL2_MMTLR (1<<0)
|
||||
#define CS4265_SPDIF_CTL2_MMTCS (1<<1)
|
||||
#define CS4265_SPDIF_CTL2_MMT (1<<2)
|
||||
#define CS4265_SPDIF_CTL2_V (1<<3)
|
||||
#define CS4265_SPDIF_CTL2_TXMUTE (1<<4)
|
||||
#define CS4265_SPDIF_CTL2_TXOFF (1<<5)
|
||||
#define CS4265_SPDIF_CTL2_MUTE (1 << 4)
|
||||
#define CS4265_SPDIF_CTL2_DIF (3 << 6)
|
||||
#define CS4265_SPDIF_CTL2_DIF0 (1 << 6)
|
||||
#define CS4265_SPDIF_CTL2_DIF1 (1 << 7)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define CS4265_C_DATA_BUFF 0x13
|
||||
#define CS4265_MAX_REGISTER 0x2A
|
||||
struct cs4265_clk_para {
|
||||
uint32_t mclk;
|
||||
uint32_t rate;
|
||||
uint8_t fm_mode; /* values 1, 2, or 4 */
|
||||
uint8_t mclkdiv;
|
||||
};
|
||||
static const struct cs4265_clk_para clk_map_table[] = {
|
||||
/*32k*/
|
||||
{8192000, 32000, 0, 0},
|
||||
{12288000, 32000, 0, 1},
|
||||
{16384000, 32000, 0, 2},
|
||||
{24576000, 32000, 0, 3},
|
||||
{32768000, 32000, 0, 4},
|
||||
|
||||
/*44.1k*/
|
||||
{11289600, 44100, 0, 0},
|
||||
{16934400, 44100, 0, 1},
|
||||
{22579200, 44100, 0, 2},
|
||||
{33868000, 44100, 0, 3},
|
||||
{45158400, 44100, 0, 4},
|
||||
|
||||
/*48k*/
|
||||
{12288000, 48000, 0, 0},
|
||||
{18432000, 48000, 0, 1},
|
||||
{24576000, 48000, 0, 2},
|
||||
{36864000, 48000, 0, 3},
|
||||
{49152000, 48000, 0, 4},
|
||||
|
||||
/*64k*/
|
||||
{8192000, 64000, 1, 0},
|
||||
{12288000, 64000, 1, 1},
|
||||
{16934400, 64000, 1, 2},
|
||||
{24576000, 64000, 1, 3},
|
||||
{32768000, 64000, 1, 4},
|
||||
|
||||
/* 88.2k */
|
||||
{11289600, 88200, 1, 0},
|
||||
{16934400, 88200, 1, 1},
|
||||
{22579200, 88200, 1, 2},
|
||||
{33868000, 88200, 1, 3},
|
||||
{45158400, 88200, 1, 4},
|
||||
|
||||
/* 96k */
|
||||
{12288000, 96000, 1, 0},
|
||||
{18432000, 96000, 1, 1},
|
||||
{24576000, 96000, 1, 2},
|
||||
{36864000, 96000, 1, 3},
|
||||
{49152000, 96000, 1, 4},
|
||||
|
||||
/* 128k */
|
||||
{8192000, 128000, 2, 0},
|
||||
{12288000, 128000, 2, 1},
|
||||
{16934400, 128000, 2, 2},
|
||||
{24576000, 128000, 2, 3},
|
||||
{32768000, 128000, 2, 4},
|
||||
|
||||
/* 176.4k */
|
||||
{11289600, 176400, 2, 0},
|
||||
{16934400, 176400, 2, 1},
|
||||
{22579200, 176400, 2, 2},
|
||||
{33868000, 176400, 2, 3},
|
||||
{49152000, 176400, 2, 4},
|
||||
|
||||
/* 192k */
|
||||
{12288000, 192000, 2, 0},
|
||||
{18432000, 192000, 2, 1},
|
||||
{24576000, 192000, 2, 2},
|
||||
{36864000, 192000, 2, 3},
|
||||
{49152000, 192000, 2, 4},
|
||||
};
|
||||
static const struct cs4265_cmd_s cs4265_init_sequence[] = {
|
||||
{CS4265_PWRCTL, CS4265_PWRCTL_PDN_ADC | CS4265_PWRCTL_FREEZE | CS4265_PWRCTL_PDN_DAC | CS4265_PWRCTL_PDN_MIC},
|
||||
{CS4265_DAC_CTL, CS4265_DAC_CTL_DIF0 | CS4265_DAC_CTL_MUTE},
|
||||
{CS4265_SIG_SEL, CS4265_SIG_SEL_SDIN1},/// SDIN1
|
||||
{CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF0 },//
|
||||
{CS4265_ADC_CTL, 0x00 },// // Set the serial audio port in slave mode
|
||||
{CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_1_0X },// // no divider
|
||||
{CS4265_CHB_PGA_CTL, 0x00 },// // sets the gain to 0db on channel B
|
||||
{CS4265_CHA_PGA_CTL, 0x00 },// // sets the gain to 0db on channel A
|
||||
{CS4265_ADC_CTL2, 0x19 },//
|
||||
{CS4265_DAC_CHA_VOL,CS4265_DAC_VOL_ATT_000_0 },// Full volume out
|
||||
{CS4265_DAC_CHB_VOL, CS4265_DAC_VOL_ATT_000_0 },// // Full volume out
|
||||
{CS4265_DAC_CTL2, CS4265_DAC_CTL2_SOFT_RAMP_ZERO_CROSS_EN },//
|
||||
{CS4265_SPDIF_CTL1, 0x00 },//
|
||||
{CS4265_INT_MASK, 0x00 },//
|
||||
{CS4265_STATUS_MODE_MSB, 0x00 },//
|
||||
{CS4265_STATUS_MODE_LSB, 0x00 },//
|
||||
{0xff,0xff}
|
||||
};
|
||||
|
||||
|
||||
// matching orders
|
||||
typedef enum { cs4265_ACTIVE = 0, cs4265_STANDBY, cs4265_DOWN, cs4265_ANALOGUE_OFF, cs4265_ANALOGUE_ON, cs4265_VOLUME } dac_cmd_e;
|
||||
|
||||
|
||||
|
||||
static int cs4265_addr;
|
||||
|
||||
static void dac_cmd(dac_cmd_e cmd, ...);
|
||||
static int cs4265_detect(void);
|
||||
static uint32_t calc_rnd_mclk_freq(){
|
||||
float m_scale = (cs4265.i2s_config->sample_rate > 96000 && cs4265.i2s_config->bits_per_sample > 16) ? 4 : 8;
|
||||
float num_channels = cs4265.i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
|
||||
return (uint32_t) round(cs4265.i2s_config->bits_per_sample*i2s_get_clk(cs4265.i2c_port)* m_scale*num_channels/100)*100;
|
||||
}
|
||||
static int cs4265_get_clk_index(int mclk, int rate)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
|
||||
if (clk_map_table[i].rate == rate &&
|
||||
clk_map_table[i].mclk == mclk)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static esp_err_t set_clock(){
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t mclk = calc_rnd_mclk_freq();
|
||||
int index = cs4265_get_clk_index(mclk,cs4265.i2s_config->sample_rate );
|
||||
if (index >= 0) {
|
||||
ESP_LOGD(TAG, "Setting clock for mclk %u, rate %u (fm mode:%u, clk div:%u))", mclk,cs4265.i2s_config->sample_rate,clk_map_table[index].fm_mode,clk_map_table[index].mclkdiv);
|
||||
err=cs4265_update_bit(CS4265_ADC_CTL,CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
|
||||
err|=cs4265_update_bit( CS4265_MCLK_FREQ,CS4265_MCLK_FREQ_MASK,clk_map_table[index].mclkdiv << 4);
|
||||
} else {
|
||||
ESP_LOGE(TAG,"can't get correct mclk for ");
|
||||
return -1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void get_status(){
|
||||
uint8_t sts1= adac_read_byte(cs4265_addr, CS4265_INT_STATUS);
|
||||
ESP_LOGD(TAG,"Status: %s",sts1&CS4265_INT_STATUS_CLKERR?"CLK Error":"CLK OK");
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* init
|
||||
*/
|
||||
static bool init(char *config, int i2c_port, i2s_config_t *i2s_config) {
|
||||
// find which TAS we are using (if any)
|
||||
cs4265_addr = adac_init(config, i2c_port);
|
||||
cs4265.i2s_config = i2s_config;
|
||||
cs4265.i2c_port=i2c_port;
|
||||
if (!cs4265_addr) cs4265_addr = cs4265_detect();
|
||||
if (!cs4265_addr) {
|
||||
ESP_LOGE(TAG, "No cs4265 detected");
|
||||
adac_deinit();
|
||||
return false;
|
||||
}
|
||||
#if BYTES_PER_FRAME == 8
|
||||
ESP_LOGE(TAG,"The CS4265 does not support 32 bits mode. ");
|
||||
adac_deinit();
|
||||
return false;
|
||||
#endif
|
||||
// configure MLK
|
||||
ESP_LOGD(TAG, "Configuring MCLK on GPIO0");
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
|
||||
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
|
||||
for (int i = 0; cs4265_init_sequence[i].reg != 0xff; i++) {
|
||||
i2c_master_start(i2c_cmd);
|
||||
i2c_master_write_byte(i2c_cmd, (cs4265_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].reg, I2C_MASTER_NACK);
|
||||
i2c_master_write_byte(i2c_cmd, cs4265_init_sequence[i].value, I2C_MASTER_NACK);
|
||||
ESP_LOGD(TAG, "i2c write %x at %u", cs4265_init_sequence[i].reg, cs4265_init_sequence[i].value);
|
||||
}
|
||||
|
||||
i2c_master_stop(i2c_cmd);
|
||||
esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(i2c_cmd);
|
||||
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not intialize cs4265 %d", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static esp_err_t cs4265_update_bit(uint8_t reg_no,uint8_t mask,uint8_t val ){
|
||||
esp_err_t ret=ESP_OK;
|
||||
uint8_t old= adac_read_byte(cs4265_addr, reg_no);
|
||||
uint8_t newval = (old & ~mask) | (val & mask);
|
||||
bool change = old != newval;
|
||||
if (change){
|
||||
ret = adac_write_byte(cs4265_addr, reg_no, newval);
|
||||
if(ret != ESP_OK){
|
||||
ESP_LOGE(TAG,"Unable to change dac register 0x%02x [0x%02x->0x%02x] from value 0x%02x, mask 0x%02x ",reg_no,old,newval,val,mask);
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(TAG,"Changed dac register 0x%02x [0x%02x->0x%02x] from value 0x%02x, mask 0x%02x ",reg_no,old,newval,val,mask);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change volume
|
||||
*/
|
||||
static bool volume(unsigned left, unsigned right) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* power
|
||||
*/
|
||||
static void power(adac_power_e mode) {
|
||||
switch(mode) {
|
||||
case ADAC_STANDBY:
|
||||
dac_cmd(cs4265_STANDBY);
|
||||
break;
|
||||
case ADAC_ON:
|
||||
dac_cmd(cs4265_ACTIVE);
|
||||
break;
|
||||
case ADAC_OFF:
|
||||
dac_cmd(cs4265_DOWN);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "unknown DAC command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* speaker
|
||||
*/
|
||||
static void speaker(bool active) {
|
||||
if (active) dac_cmd(cs4265_ANALOGUE_ON);
|
||||
else dac_cmd(cs4265_ANALOGUE_OFF);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* headset
|
||||
*/
|
||||
static void headset(bool active) { }
|
||||
|
||||
/****************************************************************************************
|
||||
* DAC specific commands
|
||||
*/
|
||||
void dac_cmd(dac_cmd_e cmd, ...) {
|
||||
va_list args;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
va_start(args, cmd);
|
||||
|
||||
switch(cmd) {
|
||||
case cs4265_VOLUME:
|
||||
ESP_LOGE(TAG, "DAC volume not handled yet");
|
||||
break;
|
||||
case cs4265_ACTIVE:
|
||||
ESP_LOGD(TAG, "Activating DAC");
|
||||
adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
|
||||
cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);
|
||||
break;
|
||||
case cs4265_STANDBY:
|
||||
ESP_LOGD(TAG, "DAC Stand-by");
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
|
||||
cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
|
||||
break;
|
||||
case cs4265_DOWN:
|
||||
ESP_LOGD(TAG, "DAC Power Down");
|
||||
adac_write_byte(cs4265_addr, CS4265_PWRCTL,CS4265_PWRCTL_PDN_ALL);
|
||||
break;
|
||||
case cs4265_ANALOGUE_OFF:
|
||||
ESP_LOGD(TAG, "DAC Analog off");
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,CS4265_SPDIF_CTL2_TXOFF);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,CS4265_SPDIF_CTL2_TXMUTE);
|
||||
cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,CS4265_DAC_CTL_MUTE);
|
||||
break;
|
||||
case cs4265_ANALOGUE_ON:
|
||||
ESP_LOGD(TAG, "DAC Analog on");
|
||||
adac_write_byte(cs4265_addr, CS4265_PWRCTL,0);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXOFF,0);
|
||||
cs4265_update_bit(CS4265_SPDIF_CTL2,CS4265_SPDIF_CTL2_TXMUTE,0);
|
||||
cs4265_update_bit(CS4265_DAC_CTL,CS4265_DAC_CTL_MUTE,0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not use cs4265 %d", ret);
|
||||
}
|
||||
get_status();
|
||||
// now set the clock
|
||||
ret=set_clock(cs4265.i2s_config,cs4265.i2c_port);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "could not set the cs4265's clock %d", ret);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* TAS57 detection
|
||||
*/
|
||||
static int cs4265_detect(void) {
|
||||
uint8_t addr[] = {CS4265_PULL_DOWN,CS4265_PULL_UP};
|
||||
|
||||
for (int i = 0; i < sizeof(addr); i++) {
|
||||
ESP_LOGI(TAG,"Looking for CS4265 @0x%x",addr[i]);
|
||||
uint8_t reg=adac_read_byte(addr[i], CS4265_CHIP_ID);
|
||||
if(reg==255){
|
||||
continue;
|
||||
}
|
||||
// found a device at that address
|
||||
uint8_t devid = reg & CS4265_CHIP_ID_MASK;
|
||||
if (devid != CS4265_CHIP_ID_VAL) {
|
||||
ESP_LOGE(TAG,"CS4265 Device ID (%X). Expected %X",devid, CS4265_CHIP_ID);
|
||||
return 0;
|
||||
}
|
||||
ESP_LOGI(TAG,"Found DAC @0x%x, Version %x",addr[i], reg & CS4265_REV_ID_MASK);
|
||||
return addr[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -266,6 +266,11 @@ cJSON* network_status_get_basic_info(cJSON** old) {
|
||||
*old = network_status_update_float(old, "avg_conn_time", nm->num_disconnect > 0 ? (nm->total_connected_time / nm->num_disconnect) : 0);
|
||||
*old = network_update_cjson_number(old, "bt_status", bt_app_source_get_a2d_state());
|
||||
*old = network_update_cjson_number(old, "bt_sub_status", bt_app_source_get_media_state());
|
||||
#if DEPTH == 16
|
||||
*old = network_update_cjson_number(old, "depth", 16);
|
||||
#elif DEPTH == 32
|
||||
*old = network_update_cjson_number(old, "depth", 32);
|
||||
#endif
|
||||
#if CONFIG_I2C_LOCKED
|
||||
*old = network_status_update_bool(old, "is_i2c_locked", true);
|
||||
#else
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
7
components/wifi-manager/webapp/dist/css/index.cd56ff129e3113d8cd3a.css
vendored
Normal file
7
components/wifi-manager/webapp/dist/css/index.cd56ff129e3113d8cd3a.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
components/wifi-manager/webapp/dist/css/index.cd56ff129e3113d8cd3a.css.gz
vendored
Normal file
BIN
components/wifi-manager/webapp/dist/css/index.cd56ff129e3113d8cd3a.css.gz
vendored
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
components/wifi-manager/webapp/dist/index.html.gz
vendored
BIN
components/wifi-manager/webapp/dist/index.html.gz
vendored
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
2
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js
vendored
Normal file
2
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js.gz
vendored
Normal file
BIN
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js.gz
vendored
Normal file
Binary file not shown.
1
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js.map
vendored
Normal file
1
components/wifi-manager/webapp/dist/js/index.ab1d13.bundle.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
39
components/wifi-manager/webapp/dist/report.html
vendored
Normal file
39
components/wifi-manager/webapp/dist/report.html
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -26,6 +26,20 @@ declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getStatus(): {};
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
@@ -54,6 +68,34 @@ declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function getRadioButton(entry: any): string;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
declare function pushStatus(): void;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
declare const PORT: 9100;
|
||||
import HtmlWebPackPlugin = require("html-webpack-plugin");
|
||||
export namespace entry {
|
||||
const test: string;
|
||||
@@ -17,7 +18,7 @@ export namespace devServer {
|
||||
}
|
||||
export const open: boolean;
|
||||
export const compress: boolean;
|
||||
export const port: number;
|
||||
export { PORT as port };
|
||||
export const host: string;
|
||||
export const allowedHosts: string;
|
||||
export const headers: {
|
||||
@@ -33,3 +34,4 @@ export namespace devServer {
|
||||
export function onBeforeSetupMiddleware(devServer: any): void;
|
||||
}
|
||||
export const plugins: HtmlWebPackPlugin[];
|
||||
export {};
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
"mock_plugin_has_proxy": "x",
|
||||
"mock_fail_fw_update":"",
|
||||
"mock_fail_recovery":"",
|
||||
"mock_old_recovery":""
|
||||
"mock_old_recovery":"",
|
||||
"depth": 16
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"scripts": {
|
||||
"prod": "webpack serve --open --mode=production",
|
||||
"build": "webpack --mode=production ",
|
||||
"stats": "webpack --env ANALYZE_SIZE=1 --mode=production ",
|
||||
"watch": "webpack --progress --watch --mode=development ",
|
||||
"dev": "webpack serve --open --mode=development"
|
||||
},
|
||||
@@ -51,6 +52,7 @@
|
||||
"lodash-webpack-plugin": "^0.11.6",
|
||||
"mini-css-extract-plugin": "^2.5.2",
|
||||
"node-sass": "^7.0.1",
|
||||
"open": "^9.1.0",
|
||||
"postcss": "^8.4.5",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"purgecss-webpack-plugin": "^4.1.3",
|
||||
@@ -65,7 +67,7 @@
|
||||
"ts-loader": "^9.2.6",
|
||||
"typescript": "^4.5.5",
|
||||
"webpack": "^5.67.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.3"
|
||||
},
|
||||
@@ -74,7 +76,9 @@
|
||||
"async-mutex": "^0.3.2",
|
||||
"bootstrap": "^5.1.3",
|
||||
"jquery": "^3.6.0",
|
||||
"popper.js": "^1.16.1"
|
||||
"popper.js": "^1.16.1",
|
||||
"webpack-visualizer-plugin": "^0.1.11",
|
||||
"webpack-visualizer-plugin2": "^1.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"webppack4",
|
||||
|
||||
@@ -44,19 +44,23 @@
|
||||
|
||||
</div>
|
||||
<div class="info navbar-right" style="display: inline-flex;">
|
||||
<span class="recovery_element material-icons " style="color:orange; display: none" aria-label="🛑" >system_update_alt</span>
|
||||
<span id="battery" class="material-icons" style="fill:white; display: none" aria-label="🔋" >battery_full</span>
|
||||
<span class="recovery_element material-icons " style="color:orange; display: none"
|
||||
aria-label="🛑">system_update_alt</span>
|
||||
<span id="battery" class="material-icons" style="fill:white; display: none"
|
||||
aria-label="🔋">battery_full</span>
|
||||
<span id="o_jack" class="material-icons" style="fill:white; display: none" aria-label="🎧">headphones</span>
|
||||
<span id="s_airplay" class="material-icons" style="fill:white; display: none" aria-label="🍎">airplay</span>
|
||||
<em id="s_cspot" class="fab fa-spotify" style="fill:white; display: inline"></em>
|
||||
<span data-bs-toggle="tooltip" id="o_type" data-bs-placement="top" title="">
|
||||
<span id="o_bt" class="material-icons" style="fill:white; display: none" aria-label="">bluetooth</span>
|
||||
<span id="o_spdif" class="material-icons" style="fill:white; display: none" aria-label="">graphic_eq</span>
|
||||
<span id="o_spdif" class="material-icons" style="fill:white; display: none"
|
||||
aria-label="">graphic_eq</span>
|
||||
<span id="o_i2s" class="material-icons" style="fill:white; display: none" aria-label="🔈">speaker</span>
|
||||
</span>
|
||||
<span id="ethernet" class="material-icons if_eth" style="fill:white; display: none" aria-label="ETH">cable</span>
|
||||
<span id="wifiStsIcon" class="material-icons if_wifi"
|
||||
style="fill:white; display: none" aria-label=""></span>
|
||||
<span id="ethernet" class="material-icons if_eth" style="fill:white; display: none"
|
||||
aria-label="ETH">cable</span>
|
||||
<span id="wifiStsIcon" class="material-icons if_wifi" style="fill:white; display: none"
|
||||
aria-label=""></span>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
@@ -215,33 +219,116 @@
|
||||
<div class="card text-white mb-3">
|
||||
<div class="card-header">Usage Templates</div>
|
||||
<div class="card-body">
|
||||
<fieldset>
|
||||
<fieldset class="form-group" id="output-tmpl">
|
||||
<legend>Output</legend>
|
||||
<div class="form-check">
|
||||
<label>Output</label><br>
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input type="radio" class="form-check-input" name="output-tmpl" id="i2s">
|
||||
I2S Dac
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input type="radio" class="form-check-input" name="output-tmpl" id="spdif">
|
||||
SPDIF
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input type="radio" class="form-check-input" name="output-tmpl" id="bt">
|
||||
Bluetooth
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-group"><label for="player">Player Name</label><input type="text"
|
||||
class="form-control " placeholder="Squeezelite" id="player"></div>
|
||||
<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP
|
||||
address)</label><input type="text" class="form-control" id="optional"></div>
|
||||
<fieldset>
|
||||
<div id="options">
|
||||
<div class="form-group"><label for="cmd_opt_n">Set the player name</label><input
|
||||
type="text" class="form-control sqcmd" placeholder="name" id="cmd_opt_n"></div>
|
||||
<div class="form-group"><label for="cmd_opt_s">Server</label><input type="text"
|
||||
class="form-control sqcmd" placeholder="server[:port]" id="cmd_opt_s"></div>
|
||||
<div class="form-group"><label for="cmd_opt_b">Stream and Output buffer sizes (in
|
||||
Kbytes)</label><input type="text" class="form-control sqcmd"
|
||||
placeholder="stream:output" id="cmd_opt_b"></div>
|
||||
<div class="form-group"><label for="cmd_opt_c">Restrict codecs </label><input
|
||||
type="text" class="form-control sqcmd" placeholder="codec1,codec2"
|
||||
id="cmd_opt_c"><small class="form-text text-muted">Supported: flac,pcm,mp3,ogg
|
||||
(mad,mpg for specific mp3 codec)</small></div>
|
||||
<div class="form-group"><label for="cmd_opt_C">Ouput device close timeout</label><input
|
||||
type="text" class="form-control sqcmd" placeholder="timeout"
|
||||
id="cmd_opt_C"><small class="form-text text-muted">Close output device after
|
||||
timeout seconds, default
|
||||
is to keep it open while player is 'on'</small></div>
|
||||
<div class="form-group"><label for="cmd_opt_d">Set logging level</label><input
|
||||
type="text" class="form-control sqcmd" placeholder="log=level"
|
||||
id="cmd_opt_d"><small class="form-text text-muted">Logs:
|
||||
all|slimproto|stream|decode|output, level:
|
||||
info|debug|sdebug</small></div>
|
||||
<div class="form-group"><label for="cmd_opt_e">Explicitly exclude native support of one
|
||||
or more codecs</label><input type="text" class="form-control sqcmd"
|
||||
placeholder="codec1,codec2" id="cmd_opt_e"><small
|
||||
class="form-text text-muted">Supported: flac,pcm,mp3,ogg (mad,mpg for specific
|
||||
mp3 codec)</small></div>
|
||||
<div class="form-group"><label for="cmd_opt_m">Set mac address</label><input type="text"
|
||||
class="form-control sqcmd" placeholder="mac addr" id="cmd_opt_m"><small
|
||||
class="form-text text-muted">Format: ab:cd:ef:12:34:56</small></div>
|
||||
<div class="form-group"><label for="cmd_opt_r">Sample rates supported, allows output to
|
||||
be off when squeezelite is started</label><input type="text"
|
||||
class="form-control sqcmd" placeholder="rates" id="cmd_opt_r"><small
|
||||
class="form-text text-muted"><maxrate>|<minrate><maxrate><rate1><rate2><rate3></small>
|
||||
</div>
|
||||
|
||||
<div class="form-group hide" id="cmd_opt_R">
|
||||
<label>Resample</label><br>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="resample" id="resample_none"
|
||||
suffix="" checked aint="false">
|
||||
<label class="form-check-label" for="resampleNone">No resampling</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="resample" id="resample"
|
||||
suffix=' -R' aint="false">
|
||||
<label class="form-check-label" for="resampleNone">Default</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="resample" id="resample_b"
|
||||
suffix=' -R -u b' aint="true">
|
||||
<label class="form-check-label" for="resampleBasic">Basic linear
|
||||
interpolation</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="resample" id="resample_l"
|
||||
suffix=' -R -u l' aint="true">
|
||||
<label class="form-check-label" for="resample13Taps">13 taps</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="resample" id="resample_m"
|
||||
suffix=' -R -u m' aint="true">
|
||||
<label class="form-check-label" for="resample21Taps">21 taps</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="interpolate"
|
||||
id="resample_i" suffix=":i">
|
||||
<label class="form-check-label" for="interpolate">Interpolate filter
|
||||
coefficients</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"><label for="cmd_opt_Z">Report rate to server in helo as the
|
||||
maximum sample rate we can support</label><input type="text"
|
||||
class="form-control" placeholder="rate" id="cmd_opt_Z"></div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="cmd_opt_W" value=""
|
||||
checked="">
|
||||
Read wave and aiff format from header, ignore server parameters
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="disable-squeezelite"
|
||||
|
||||
@@ -28,71 +28,95 @@ Object.assign(Date.prototype, {
|
||||
return this.toLocaleString(undefined, opt);
|
||||
},
|
||||
});
|
||||
function handleNVSVisible(){
|
||||
function get_control_option_value(obj) {
|
||||
let ctrl,id,val,opt;
|
||||
let radio = false;
|
||||
let checked = false;
|
||||
if (typeof (obj) === 'string') {
|
||||
id = obj;
|
||||
ctrl = $(`#${id}`);
|
||||
} else {
|
||||
id = $(obj).attr('id');
|
||||
ctrl = $(obj);
|
||||
}
|
||||
if(ctrl.attr('type') === 'checkbox'){
|
||||
opt = $(obj).checked?id.replace('cmd_opt_', ''):'';
|
||||
val = true;
|
||||
}
|
||||
else {
|
||||
opt = id.replace('cmd_opt_', '');
|
||||
val = $(obj).val();
|
||||
val = `${val.includes(" ") ? '"' : ''}${val}${val.includes(" ") ? '"' : ''}`;
|
||||
}
|
||||
|
||||
return { opt, val };
|
||||
}
|
||||
function handleNVSVisible() {
|
||||
let nvs_previous_checked = isEnabled(Cookies.get("show-nvs"));
|
||||
$('input#show-nvs')[0].checked = nvs_previous_checked ;
|
||||
$('input#show-nvs')[0].checked = nvs_previous_checked;
|
||||
if ($('input#show-nvs')[0].checked || recovery) {
|
||||
$('*[href*="-nvs"]').show();
|
||||
} else {
|
||||
$('*[href*="-nvs"]').hide();
|
||||
$('*[href*="-nvs"]').show();
|
||||
} else {
|
||||
$('*[href*="-nvs"]').hide();
|
||||
}
|
||||
}
|
||||
function concatenateOptions(options) {
|
||||
let commandLine = ' ';
|
||||
for (const [option, value] of Object.entries(options)) {
|
||||
if (option !== 'n' && option !== 'o') {
|
||||
commandLine += `-${option} `;
|
||||
if (value !== true) {
|
||||
commandLine += `${value} `;
|
||||
}
|
||||
}
|
||||
}
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
|
||||
function isEnabled(val) {
|
||||
return val!=undefined && typeof val === 'string' && val.match("[Yy1]");
|
||||
return val != undefined && typeof val === 'string' && val.match("[Yy1]");
|
||||
}
|
||||
|
||||
const nvsTypes = {
|
||||
NVS_TYPE_U8: 0x01,
|
||||
|
||||
/*! < Type uint8_t */
|
||||
NVS_TYPE_I8: 0x11,
|
||||
|
||||
/*! < Type int8_t */
|
||||
NVS_TYPE_U16: 0x02,
|
||||
|
||||
/*! < Type uint16_t */
|
||||
NVS_TYPE_I16: 0x12,
|
||||
|
||||
/*! < Type int16_t */
|
||||
NVS_TYPE_U32: 0x04,
|
||||
|
||||
/*! < Type uint32_t */
|
||||
NVS_TYPE_I32: 0x14,
|
||||
|
||||
/*! < Type int32_t */
|
||||
NVS_TYPE_U64: 0x08,
|
||||
|
||||
/*! < Type uint64_t */
|
||||
NVS_TYPE_I64: 0x18,
|
||||
|
||||
/*! < Type int64_t */
|
||||
NVS_TYPE_STR: 0x21,
|
||||
|
||||
/*! < Type string */
|
||||
NVS_TYPE_BLOB: 0x42,
|
||||
|
||||
/*! < Type blob */
|
||||
NVS_TYPE_ANY: 0xff /*! < Must be last */,
|
||||
};
|
||||
const btIcons = {
|
||||
bt_playing: {'label':'','icon': 'media_bluetooth_on'},
|
||||
bt_disconnected: {'label':'','icon': 'media_bluetooth_off'},
|
||||
bt_neutral: {'label':'','icon': 'bluetooth'},
|
||||
bt_connecting: {'label':'','icon': 'bluetooth_searching'},
|
||||
bt_connected: {'label':'','icon': 'bluetooth_connected'},
|
||||
bt_disabled: {'label':'','icon': 'bluetooth_disabled'},
|
||||
play_arrow: {'label':'','icon': 'play_circle_filled'},
|
||||
pause: {'label':'','icon': 'pause_circle'},
|
||||
stop: {'label':'','icon': 'stop_circle'},
|
||||
'': {'label':'','icon':''}
|
||||
bt_playing: { 'label': '', 'icon': 'media_bluetooth_on' },
|
||||
bt_disconnected: { 'label': '', 'icon': 'media_bluetooth_off' },
|
||||
bt_neutral: { 'label': '', 'icon': 'bluetooth' },
|
||||
bt_connecting: { 'label': '', 'icon': 'bluetooth_searching' },
|
||||
bt_connected: { 'label': '', 'icon': 'bluetooth_connected' },
|
||||
bt_disabled: { 'label': '', 'icon': 'bluetooth_disabled' },
|
||||
play_arrow: { 'label': '', 'icon': 'play_circle_filled' },
|
||||
pause: { 'label': '', 'icon': 'pause_circle' },
|
||||
stop: { 'label': '', 'icon': 'stop_circle' },
|
||||
'': { 'label': '', 'icon': '' }
|
||||
};
|
||||
const batIcons = [
|
||||
{ icon: "battery_0_bar", label:'▪', ranges: [{ f: 5.8, t: 6.8 }, { f: 8.8, t: 10.2 }] },
|
||||
{ icon: "battery_2_bar", label:'▪▪', ranges: [{ f: 6.8, t: 7.4 }, { f: 10.2, t: 11.1 }] },
|
||||
{ icon: "battery_3_bar", label:'▪▪▪', ranges: [{ f: 7.4, t: 7.5 }, { f: 11.1, t: 11.25 }] },
|
||||
{ icon: "battery_4_bar", label:'▪▪▪▪', ranges: [{ f: 7.5, t: 7.8 }, { f: 11.25, t: 11.7 }] }
|
||||
{ icon: "battery_0_bar", label: '▪', ranges: [{ f: 5.8, t: 6.8 }, { f: 8.8, t: 10.2 }] },
|
||||
{ icon: "battery_2_bar", label: '▪▪', ranges: [{ f: 6.8, t: 7.4 }, { f: 10.2, t: 11.1 }] },
|
||||
{ icon: "battery_3_bar", label: '▪▪▪', ranges: [{ f: 7.4, t: 7.5 }, { f: 11.1, t: 11.25 }] },
|
||||
{ icon: "battery_4_bar", label: '▪▪▪▪', ranges: [{ f: 7.5, t: 7.8 }, { f: 11.25, t: 11.7 }] }
|
||||
];
|
||||
const btStateIcons = [
|
||||
{ desc: 'Idle', sub: ['bt_neutral'] },
|
||||
@@ -162,7 +186,7 @@ let flashState = {
|
||||
$('.flact').prop('disabled', false);
|
||||
$('#flashfilename').value = null;
|
||||
$('#fw-url-input').value = null;
|
||||
if(!this.isStateError()){
|
||||
if (!this.isStateError()) {
|
||||
$('span#flash-status').html('');
|
||||
$('#fwProgressLabel').parent().removeClass('bg-danger');
|
||||
}
|
||||
@@ -357,8 +381,8 @@ let flashState = {
|
||||
const xhttp = new XMLHttpRequest();
|
||||
xhttp.context = this;
|
||||
var boundHandleUploadProgressEvent = this.HandleUploadProgressEvent.bind(this);
|
||||
var boundsetOTAError=this.setOTAError.bind(this);
|
||||
xhttp.upload.addEventListener("progress",boundHandleUploadProgressEvent, false);
|
||||
var boundsetOTAError = this.setOTAError.bind(this);
|
||||
xhttp.upload.addEventListener("progress", boundHandleUploadProgressEvent, false);
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (xhttp.readyState === 4) {
|
||||
if (xhttp.status === 0 || xhttp.status === 404) {
|
||||
@@ -464,11 +488,89 @@ window.handleReboot = function (link) {
|
||||
$('#reboot_nav').removeClass('active'); delayReboot(500, '', link);
|
||||
}
|
||||
}
|
||||
function isConnected(){
|
||||
return ConnectedTo.hasOwnProperty('ip') && ConnectedTo.ip!='0.0.0.0'&& ConnectedTo.ip!='';
|
||||
|
||||
function parseSqueezeliteCommandLine(commandLine) {
|
||||
const options = {};
|
||||
let output, name;
|
||||
let otherValues = '';
|
||||
|
||||
const argRegex = /("[^"]+"|'[^']+'|\S+)/g;
|
||||
const args = commandLine.match(argRegex);
|
||||
|
||||
let i = 0;
|
||||
|
||||
while (i < args.length) {
|
||||
const arg = args[i];
|
||||
|
||||
if (arg.startsWith('-')) {
|
||||
const option = arg.slice(1);
|
||||
|
||||
if (option === '') {
|
||||
otherValues += args.slice(i).join(' ');
|
||||
break;
|
||||
}
|
||||
|
||||
let value = true;
|
||||
|
||||
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
||||
value = args[i + 1].replace(/"/g, '').replace(/'/g, '');
|
||||
i++;
|
||||
}
|
||||
|
||||
options[option] = value;
|
||||
} else {
|
||||
otherValues += arg + ' ';
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
otherValues = otherValues.trim();
|
||||
output = getOutput(options);
|
||||
name = getName(options);
|
||||
let otherOptions={btname:null,n:null};
|
||||
// assign o and n options to otheroptions if present
|
||||
if (options.o && output.toUpperCase() === 'BT') {
|
||||
let temp = parseSqueezeliteCommandLine(options.o);
|
||||
if(temp.name) {
|
||||
otherOptions.btname = temp.name;
|
||||
}
|
||||
delete options.o;
|
||||
}
|
||||
if (options.n) {
|
||||
otherOptions['n'] = options.n;
|
||||
delete options.n;
|
||||
}
|
||||
return { name, output, options, otherValues,otherOptions };
|
||||
}
|
||||
function getIcon(icons){
|
||||
return isConnected()?icons.icon:icons.label;
|
||||
|
||||
function getOutput(options) {
|
||||
let output;
|
||||
if (options.o){
|
||||
output = options.o.replace(/"/g, '').replace(/'/g, '');
|
||||
/* set output as the first alphanumerical word in the command line */
|
||||
if (output.indexOf(' ') > 0) {
|
||||
output = output.substring(0, output.indexOf(' '));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function getName(options) {
|
||||
let name;
|
||||
/* if n option present, assign to name variable */
|
||||
if (options.n){
|
||||
name = options.n.replace(/"/g, '').replace(/'/g, '');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
function isConnected() {
|
||||
return ConnectedTo.hasOwnProperty('ip') && ConnectedTo.ip != '0.0.0.0' && ConnectedTo.ip != '';
|
||||
}
|
||||
function getIcon(icons) {
|
||||
return isConnected() ? icons.icon : icons.label;
|
||||
}
|
||||
function handlebtstate(data) {
|
||||
let icon = '';
|
||||
@@ -476,7 +578,7 @@ function handlebtstate(data) {
|
||||
if (data.bt_status !== undefined && data.bt_sub_status !== undefined) {
|
||||
const iconindex = btStateIcons[data.bt_status].sub[data.bt_sub_status];
|
||||
if (iconindex) {
|
||||
icon = btIcons[iconindex];
|
||||
icon = btIcons[iconindex];
|
||||
tt = btStateIcons[data.bt_status].desc;
|
||||
} else {
|
||||
icon = btIcons.bt_connected;
|
||||
@@ -485,19 +587,28 @@ function handlebtstate(data) {
|
||||
}
|
||||
|
||||
$('#o_type').attr('title', tt);
|
||||
$('#o_bt').html(isConnected()?icon.label:icon.text);
|
||||
$('#o_bt').html(isConnected() ? icon.label : icon.text);
|
||||
}
|
||||
function handleTemplateTypeRadio(outtype) {
|
||||
$('#o_type').children('span').css({ display: 'none' });
|
||||
let changed = false;
|
||||
if (outtype === 'bt') {
|
||||
changed = output !== 'bt' && output !== '';
|
||||
output = 'bt';
|
||||
} else if (outtype === 'spdif') {
|
||||
changed = output !== 'spdif' && output !== '';
|
||||
output = 'spdif';
|
||||
} else {
|
||||
changed = output !== 'i2s' && output !== '';
|
||||
output = 'i2s';
|
||||
}
|
||||
$('#' + output).prop('checked', true);
|
||||
$('#o_' + output).css({ display: 'inline' });
|
||||
if (changed) {
|
||||
Object.keys(commandDefaults[output]).forEach(function (key) {
|
||||
$(`#cmd_opt_${key}`).val(commandDefaults[output][key]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleExceptionResponse(xhr, _ajaxOptions, thrownError) {
|
||||
@@ -545,7 +656,17 @@ let releaseURL =
|
||||
|
||||
let recovery = false;
|
||||
let messagesHeld = false;
|
||||
const commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W';
|
||||
let commandBTSinkName = '';
|
||||
const commandHeader = 'squeezelite ';
|
||||
const commandDefaults = {
|
||||
i2s: { b: "500:2000", C: "30", W: "", Z: "96000", o: "I2S" },
|
||||
spdif: { b: "500:2000", C: "30", W: "", Z: "48000", o: "SPDIF" },
|
||||
bt: { b: "500:2000", C: "30", W: "", Z: "44100", o: "BT" },
|
||||
};
|
||||
let validOptions = {
|
||||
codecs: ['flac', 'pcm', 'mp3', 'ogg', 'aac', 'wma', 'alac', 'dsd', 'mad', 'mpg']
|
||||
};
|
||||
|
||||
//let blockFlashButton = false;
|
||||
let apList = null;
|
||||
//let selectedSSID = '';
|
||||
@@ -559,6 +680,7 @@ let hostName = '';
|
||||
let versionName = 'Squeezelite-ESP32';
|
||||
let prevmessage = '';
|
||||
let project_name = versionName;
|
||||
let depth = 16;
|
||||
let board_model = '';
|
||||
let platform_name = versionName;
|
||||
let preset_name = '';
|
||||
@@ -690,11 +812,6 @@ function handleHWPreset(allfields, reboot) {
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -773,23 +890,34 @@ function delayReboot(duration, cmdname, ota = 'reboot') {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
window.saveAutoexec1 = function (apply) {
|
||||
showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Saving.\n', false);
|
||||
let commandLine = commandHeader + ' -n "' + $('#player').val() + '"';
|
||||
let commandLine = `${commandHeader} -o ${output} `;
|
||||
$('.sqcmd').each(function () {
|
||||
let { opt, val } = get_control_option_value($(this));
|
||||
if ((opt && opt.length>0 ) && typeof(val) == 'boolean' || val.length > 0) {
|
||||
const optStr=opt===':'?opt:(` -${opt} `);
|
||||
val = typeof(val) == 'boolean'?'':val;
|
||||
commandLine += `${optStr} ${val}`;
|
||||
}
|
||||
});
|
||||
const resample=$('#cmd_opt_R input[name=resample]:checked');
|
||||
if (resample.length>0 && resample.attr('suffix')!=='') {
|
||||
commandLine += resample.attr('suffix');
|
||||
// now check resample_i option and if checked, add suffix to command line
|
||||
if ($('#resample_i').is(":checked") && resample.attr('aint') =='true') {
|
||||
commandLine += $('#resample_i').attr('suffix');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (output === 'bt') {
|
||||
commandLine += ' -o "BT" -R -Z 192000';
|
||||
showCmdMessage(
|
||||
'cfg-audio-tmpl',
|
||||
'MESSAGING_INFO',
|
||||
'Remember to configure the Bluetooth audio device name.\n',
|
||||
true
|
||||
);
|
||||
} else if (output === 'spdif') {
|
||||
commandLine += ' -o SPDIF -Z 192000';
|
||||
} else {
|
||||
commandLine += ' -o I2S';
|
||||
}
|
||||
if ($('#optional').val() !== '') {
|
||||
commandLine += ' ' + $('#optional').val();
|
||||
}
|
||||
commandLine += concatenateOptions(options);
|
||||
const data = {
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
@@ -880,9 +1008,33 @@ window.handleConnect = function () {
|
||||
// now we can re-set the intervals regardless of result
|
||||
|
||||
}
|
||||
function renderError(opt,error){
|
||||
const fieldname = `cmd_opt_${opt}`;
|
||||
let errorFieldName=`${fieldname}-error`;
|
||||
let errorField=$(`#${errorFieldName}`);
|
||||
let field=$(`#${fieldname}`);
|
||||
|
||||
if (!errorField || errorField.length ==0) {
|
||||
field.after(`<div id="${errorFieldName}" class="invalid-feedback"></div>`);
|
||||
errorField=$(`#${errorFieldName}`);
|
||||
}
|
||||
if(error.length ==0){
|
||||
errorField.hide();
|
||||
field.removeClass('is-invalid');
|
||||
field.addClass('is-valid');
|
||||
errorField.text('');
|
||||
}
|
||||
else {
|
||||
errorField.show();
|
||||
errorField.text(error);
|
||||
field.removeClass('is-valid');
|
||||
field.addClass('is-invalid');
|
||||
}
|
||||
return errorField;
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('.material-icons').each(function (_index, entry) {
|
||||
entry.attributes['icon']=entry.textContent;
|
||||
entry.attributes['icon'] = entry.textContent;
|
||||
});
|
||||
setIcons(true);
|
||||
handleNVSVisible();
|
||||
@@ -908,6 +1060,43 @@ $(document).ready(function () {
|
||||
|
||||
});
|
||||
setTimeout(refreshAP, 1500);
|
||||
/* add validation for cmd_opt_c, which accepts a comma separated list.
|
||||
getting known codecs from validOptions.codecs array
|
||||
use bootstrap classes to highlight the error with an overlay message */
|
||||
$('#options input').on('input', function () {
|
||||
const { opt, val } = get_control_option_value(this);
|
||||
if (opt === 'c' || opt === 'e') {
|
||||
const fieldname = `cmd_opt_${opt}_codec-error`;
|
||||
|
||||
const values = val.split(',').map(function (item) {
|
||||
return item.trim();
|
||||
});
|
||||
/* get a list of invalid codecs */
|
||||
const invalid = values.filter(function (item) {
|
||||
return !validOptions.codecs.includes(item);
|
||||
});
|
||||
renderError(opt,invalid.length > 0 ? `Invalid codec(s) ${invalid.join(', ')}` : '');
|
||||
}
|
||||
/* add validation for cmd_opt_m, which accepts a mac_address */
|
||||
if (opt === 'm') {
|
||||
const mac_regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
||||
renderError(opt,mac_regex.test(val) ? '' : 'Invalid MAC address');
|
||||
}
|
||||
if (opt === 'r') {
|
||||
const rateRegex = /^(\d+\.?\d*|\.\d+)-(\d+\.?\d*|\.\d+)$|^(\d+\.?\d*)$|^(\d+\.?\d*,)+\d+\.?\d*$/;
|
||||
renderError(opt,rateRegex.test(val)?'':`Invalid rate(s) ${val}. Acceptable format: <maxrate>|<minrate>-<maxrate>|<rate1>,<rate2>,<rate3>`);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$('#WifiConnectDialog')[0].addEventListener('shown.bs.modal', function (event) {
|
||||
$("*[class*='connecting']").hide();
|
||||
@@ -1029,7 +1218,7 @@ $(document).ready(function () {
|
||||
|
||||
$('input#show-nvs').on('click', function () {
|
||||
this.checked = this.checked ? 1 : 0;
|
||||
Cookies.set("show-nvs", this.checked?'Y':'N');
|
||||
Cookies.set("show-nvs", this.checked ? 'Y' : 'N');
|
||||
handleNVSVisible();
|
||||
});
|
||||
$('#btn_reboot_recovery').on('click', function () {
|
||||
@@ -1048,7 +1237,7 @@ $(document).ready(function () {
|
||||
saveAutoexec1(true);
|
||||
});
|
||||
$('#btn_disconnect').on('click', function () {
|
||||
ConnectedTo={};
|
||||
ConnectedTo = {};
|
||||
refreshAPHTML2();
|
||||
$.ajax({
|
||||
url: '/connect.json',
|
||||
@@ -1303,15 +1492,15 @@ window.setURL = function (button) {
|
||||
|
||||
function rssiToIcon(rssi) {
|
||||
if (rssi >= -55) {
|
||||
return {'label':'****','icon':`signal_wifi_statusbar_4_bar`};
|
||||
return { 'label': '****', 'icon': `signal_wifi_statusbar_4_bar` };
|
||||
} else if (rssi >= -60) {
|
||||
return {'label':'***','icon':`network_wifi_3_bar`};
|
||||
return { 'label': '***', 'icon': `network_wifi_3_bar` };
|
||||
} else if (rssi >= -65) {
|
||||
return {'label':'**','icon':`network_wifi_2_bar`};
|
||||
return { 'label': '**', 'icon': `network_wifi_2_bar` };
|
||||
} else if (rssi >= -70) {
|
||||
return {'label':'*','icon':`network_wifi_1_bar`};
|
||||
return { 'label': '*', 'icon': `network_wifi_1_bar` };
|
||||
} else {
|
||||
return {'label':'.','icon':`signal_wifi_statusbar_null`};
|
||||
return { 'label': '.', 'icon': `signal_wifi_statusbar_null` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1339,9 +1528,9 @@ function refreshAP() {
|
||||
});
|
||||
}
|
||||
function formatAP(ssid, rssi, auth) {
|
||||
const rssi_icon=rssiToIcon(rssi);
|
||||
const auth_icon={label:auth == 0 ? '🔓' : '🔒',icon:auth == 0 ? 'no_encryption' : 'lock'};
|
||||
|
||||
const rssi_icon = rssiToIcon(rssi);
|
||||
const auth_icon = { label: auth == 0 ? '🔓' : '🔒', icon: auth == 0 ? 'no_encryption' : 'lock' };
|
||||
|
||||
return `<tr data-bs-toggle="modal" data-bs-target="#WifiConnectDialog"><td></td><td>${ssid}</td><td>
|
||||
<span class="material-icons" style="fill:white; display: inline" aria-label="${rssi_icon.label}" icon="${rssi_icon.icon}" >${getIcon(rssi_icon)}</span>
|
||||
</td><td>
|
||||
@@ -1512,9 +1701,9 @@ function getMessages() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTimeout(getMessages,messageInterval);
|
||||
setTimeout(getMessages, messageInterval);
|
||||
}).fail(function (xhr, ajaxOptions, thrownError) {
|
||||
|
||||
|
||||
if (xhr.status == 404) {
|
||||
$('.orec').hide(); // system commands won't be available either
|
||||
messagesHeld = true;
|
||||
@@ -1522,15 +1711,15 @@ function getMessages() {
|
||||
else {
|
||||
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
||||
}
|
||||
if(xhr.status == 0 && xhr.readyState ==0){
|
||||
if (xhr.status == 0 && xhr.readyState == 0) {
|
||||
// probably a timeout. Target is rebooting?
|
||||
setTimeout(getMessages,messageInterval*2); // increase duration if a failure happens
|
||||
setTimeout(getMessages, messageInterval * 2); // increase duration if a failure happens
|
||||
}
|
||||
else if(!messagesHeld){
|
||||
else if (!messagesHeld) {
|
||||
// 404 here means we rebooted to an old recovery
|
||||
setTimeout(getMessages,messageInterval); // increase duration if a failure happens
|
||||
setTimeout(getMessages, messageInterval); // increase duration if a failure happens
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1552,18 +1741,18 @@ function handleRecoveryMode(data) {
|
||||
$('#boot-button').html('Reboot');
|
||||
$('#boot-form').attr('action', '/reboot_ota.json');
|
||||
} else {
|
||||
if(!recovery && messagesHeld){
|
||||
messagesHeld=false;
|
||||
setTimeout(getMessages,messageInterval); // increase duration if a failure happens
|
||||
if (!recovery && messagesHeld) {
|
||||
messagesHeld = false;
|
||||
setTimeout(getMessages, messageInterval); // increase duration if a failure happens
|
||||
}
|
||||
recovery = false;
|
||||
|
||||
|
||||
$('.recovery_element').hide();
|
||||
$('.ota_element').show();
|
||||
$('#boot-button').html('Recovery');
|
||||
$('#boot-form').attr('action', '/recovery.json');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function hasConnectionChanged(data) {
|
||||
@@ -1645,9 +1834,9 @@ function handleWifiDialog(data) {
|
||||
|
||||
}
|
||||
}
|
||||
function setIcons(offline){
|
||||
function setIcons(offline) {
|
||||
$('.material-icons').each(function (_index, entry) {
|
||||
entry.textContent = entry.attributes[offline?'aria-label':'icon'].value;
|
||||
entry.textContent = entry.attributes[offline ? 'aria-label' : 'icon'].value;
|
||||
});
|
||||
}
|
||||
function handleNetworkStatus(data) {
|
||||
@@ -1682,13 +1871,13 @@ function batteryToIcon(voltage) {
|
||||
for (const iconEntry of batIcons) {
|
||||
for (const entryRanges of iconEntry.ranges) {
|
||||
if (inRange(voltage, entryRanges.f, entryRanges.t)) {
|
||||
return { label: iconEntry.label, icon:iconEntry.icon};
|
||||
return { label: iconEntry.label, icon: iconEntry.icon };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {label:'▪▪▪▪',icon:"battery_full"};
|
||||
return { label: '▪▪▪▪', icon: "battery_full" };
|
||||
}
|
||||
function checkStatus() {
|
||||
$.ajaxSetup({
|
||||
@@ -1700,6 +1889,16 @@ function checkStatus() {
|
||||
handleNetworkStatus(data);
|
||||
handlebtstate(data);
|
||||
flashState.EventTargetStatus(data);
|
||||
if(data.depth) {
|
||||
depth = data.depth;
|
||||
if(depth==16){
|
||||
$('#cmd_opt_R').show();
|
||||
}
|
||||
else{
|
||||
$('#cmd_opt_R').hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (data.project_name && data.project_name !== '') {
|
||||
project_name = data.project_name;
|
||||
@@ -1717,10 +1916,10 @@ function checkStatus() {
|
||||
$('span#flash-status').html('');
|
||||
}
|
||||
if (data.Voltage) {
|
||||
const bat_icon=batteryToIcon(data.Voltage);
|
||||
const bat_icon = batteryToIcon(data.Voltage);
|
||||
$('#battery').html(`${getIcon(bat_icon)}`);
|
||||
$('#battery').attr("aria-label",bat_icon.label);
|
||||
$('#battery').attr("icon",bat_icon.icon);
|
||||
$('#battery').attr("aria-label", bat_icon.label);
|
||||
$('#battery').attr("icon", bat_icon.icon);
|
||||
$('#battery').show();
|
||||
} else {
|
||||
$('#battery').hide();
|
||||
@@ -1757,15 +1956,15 @@ function checkStatus() {
|
||||
});
|
||||
}
|
||||
$('#o_jack').css({ display: Number(data.Jack) ? 'inline' : 'none' });
|
||||
setTimeout(checkStatus,statusInterval);
|
||||
setTimeout(checkStatus, statusInterval);
|
||||
}).fail(function (xhr, ajaxOptions, thrownError) {
|
||||
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
||||
if(xhr.status == 0 && xhr.readyState ==0){
|
||||
if (xhr.status == 0 && xhr.readyState == 0) {
|
||||
// probably a timeout. Target is rebooting?
|
||||
setTimeout(checkStatus,messageInterval*2); // increase duration if a failure happens
|
||||
setTimeout(checkStatus, messageInterval * 2); // increase duration if a failure happens
|
||||
}
|
||||
else {
|
||||
setTimeout(checkStatus,messageInterval); // increase duration if a failure happens
|
||||
setTimeout(checkStatus, messageInterval); // increase duration if a failure happens
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1995,6 +2194,7 @@ function getConfig() {
|
||||
$('#nvsTable tr').remove();
|
||||
const data = (entries.config ? entries.config : entries);
|
||||
SystemConfig = data;
|
||||
commandBTSinkName = '';
|
||||
Object.keys(data)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
@@ -2006,20 +2206,15 @@ function getConfig() {
|
||||
$('#disable-squeezelite')[0].checked = false;
|
||||
}
|
||||
} else if (key === 'autoexec1') {
|
||||
const re = /-o\s?(["][^"]*["]|[^-]+)/g;
|
||||
const m = re.exec(val);
|
||||
if (m[1].toUpperCase().startsWith('I2S')) {
|
||||
handleTemplateTypeRadio('i2s');
|
||||
} else if (m[1].toUpperCase().startsWith('SPDIF')) {
|
||||
handleTemplateTypeRadio('spdif');
|
||||
} else if (m[1].toUpperCase().startsWith('"BT')) {
|
||||
handleTemplateTypeRadio('bt');
|
||||
}
|
||||
/* call new function to parse the squeezelite options */
|
||||
processSqueezeliteCommandLine(val);
|
||||
} else if (key === 'host_name') {
|
||||
val = val.replaceAll('"', '');
|
||||
$('input#dhcp-name1').val(val);
|
||||
$('input#dhcp-name2').val(val);
|
||||
$('#player').val(val);
|
||||
if ($('#cmd_opt_n').length == 0) {
|
||||
$('#cmd_opt_n').val(val);
|
||||
}
|
||||
document.title = val;
|
||||
hostName = val;
|
||||
} else if (key === 'rel_api') {
|
||||
@@ -2054,6 +2249,10 @@ function getConfig() {
|
||||
);
|
||||
$('input#' + key).val(data[key].value);
|
||||
});
|
||||
if(commandBTSinkName.length > 0) {
|
||||
// persist the sink name found in the autoexec1 command line
|
||||
$('#cfg-audio-bt_source-sink_name').val(commandBTSinkName);
|
||||
}
|
||||
$('tbody#nvsTable').append(
|
||||
"<tr><td><input type='text' class='form-control' id='nvs-new-key' placeholder='new key'></td><td><input type='text' class='form-control' id='nvs-new-value' placeholder='new value' nvs_type=33 ></td></tr>"
|
||||
);
|
||||
@@ -2083,6 +2282,40 @@ function getConfig() {
|
||||
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
||||
});
|
||||
}
|
||||
|
||||
function processSqueezeliteCommandLine(val) {
|
||||
const parsed = parseSqueezeliteCommandLine(val);
|
||||
if (parsed.output.toUpperCase().startsWith('I2S')) {
|
||||
handleTemplateTypeRadio('i2s');
|
||||
} else if (parsed.output.toUpperCase().startsWith('SPDIF')) {
|
||||
handleTemplateTypeRadio('spdif');
|
||||
} else if (parsed.output.toUpperCase().startsWith('BT')) {
|
||||
if(parsed.otherOptions.btname){
|
||||
commandBTSinkName= parsed.otherOptions.btname;
|
||||
}
|
||||
handleTemplateTypeRadio('bt');
|
||||
}
|
||||
Object.keys(parsed.options).forEach(function (key) {
|
||||
const option = parsed.options[key];
|
||||
if (!$(`#cmd_opt_${key}`).hasOwnProperty('checked')) {
|
||||
$(`#cmd_opt_${key}`).val(option);
|
||||
} else {
|
||||
$(`#cmd_opt_${key}`)[0].checked = option;
|
||||
}
|
||||
});
|
||||
if (parsed.options.hasOwnProperty('u')) {
|
||||
// parse -u v[:i] and check the appropriate radio button with id #resample_v
|
||||
const [resampleValue, resampleInterpolation] = parsed.options.u.split(':');
|
||||
$(`#resample_${resampleValue}`).prop('checked', true);
|
||||
// if resampleinterpolation is set, check resample_i checkbox
|
||||
if (resampleInterpolation) {
|
||||
$('#resample_i').prop('checked', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function showLocalMessage(message, severity) {
|
||||
const msg = {
|
||||
message: message,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/css/index.60aa97be4459083adfab.css.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/css/index.cd56ff129e3113d8cd3a.css.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/favicon-32x32.png BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/index.html.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.392dfa.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.392dfa.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.ab1d13.bundle.js.gz BINARY)
|
||||
target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.ab1d13.bundle.js.gz BINARY)
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
// Automatically generated. Do not edit manually!.
|
||||
#include <inttypes.h>
|
||||
extern const uint8_t _index_60aa97be4459083adfab_css_gz_start[] asm("_binary_index_60aa97be4459083adfab_css_gz_start");
|
||||
extern const uint8_t _index_60aa97be4459083adfab_css_gz_end[] asm("_binary_index_60aa97be4459083adfab_css_gz_end");
|
||||
extern const uint8_t _index_cd56ff129e3113d8cd3a_css_gz_start[] asm("_binary_index_cd56ff129e3113d8cd3a_css_gz_start");
|
||||
extern const uint8_t _index_cd56ff129e3113d8cd3a_css_gz_end[] asm("_binary_index_cd56ff129e3113d8cd3a_css_gz_end");
|
||||
extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_start");
|
||||
extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
|
||||
extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
|
||||
extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
|
||||
extern const uint8_t _index_392dfa_bundle_js_gz_start[] asm("_binary_index_392dfa_bundle_js_gz_start");
|
||||
extern const uint8_t _index_392dfa_bundle_js_gz_end[] asm("_binary_index_392dfa_bundle_js_gz_end");
|
||||
extern const uint8_t _node_vendors_392dfa_bundle_js_gz_start[] asm("_binary_node_vendors_392dfa_bundle_js_gz_start");
|
||||
extern const uint8_t _node_vendors_392dfa_bundle_js_gz_end[] asm("_binary_node_vendors_392dfa_bundle_js_gz_end");
|
||||
extern const uint8_t _index_ab1d13_bundle_js_gz_start[] asm("_binary_index_ab1d13_bundle_js_gz_start");
|
||||
extern const uint8_t _index_ab1d13_bundle_js_gz_end[] asm("_binary_index_ab1d13_bundle_js_gz_end");
|
||||
extern const uint8_t _node_vendors_ab1d13_bundle_js_gz_start[] asm("_binary_node_vendors_ab1d13_bundle_js_gz_start");
|
||||
extern const uint8_t _node_vendors_ab1d13_bundle_js_gz_end[] asm("_binary_node_vendors_ab1d13_bundle_js_gz_end");
|
||||
const char * resource_lookups[] = {
|
||||
"/css/index.60aa97be4459083adfab.css.gz",
|
||||
"/css/index.cd56ff129e3113d8cd3a.css.gz",
|
||||
"/favicon-32x32.png",
|
||||
"/index.html.gz",
|
||||
"/js/index.392dfa.bundle.js.gz",
|
||||
"/js/node_vendors.392dfa.bundle.js.gz",
|
||||
"/js/index.ab1d13.bundle.js.gz",
|
||||
"/js/node_vendors.ab1d13.bundle.js.gz",
|
||||
""
|
||||
};
|
||||
const uint8_t * resource_map_start[] = {
|
||||
_index_60aa97be4459083adfab_css_gz_start,
|
||||
_index_cd56ff129e3113d8cd3a_css_gz_start,
|
||||
_favicon_32x32_png_start,
|
||||
_index_html_gz_start,
|
||||
_index_392dfa_bundle_js_gz_start,
|
||||
_node_vendors_392dfa_bundle_js_gz_start
|
||||
_index_ab1d13_bundle_js_gz_start,
|
||||
_node_vendors_ab1d13_bundle_js_gz_start
|
||||
};
|
||||
const uint8_t * resource_map_end[] = {
|
||||
_index_60aa97be4459083adfab_css_gz_end,
|
||||
_index_cd56ff129e3113d8cd3a_css_gz_end,
|
||||
_favicon_32x32_png_end,
|
||||
_index_html_gz_end,
|
||||
_index_392dfa_bundle_js_gz_end,
|
||||
_node_vendors_392dfa_bundle_js_gz_end
|
||||
_index_ab1d13_bundle_js_gz_end,
|
||||
_node_vendors_ab1d13_bundle_js_gz_end
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
|
||||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const globSync = require("glob").sync;
|
||||
const glob = require('glob');
|
||||
const { merge } = require('webpack-merge');
|
||||
@@ -39,7 +40,15 @@ class BuildEventsHook {
|
||||
module.exports = (env, options) => (
|
||||
merge(
|
||||
env.WEBPACK_SERVE ? devserver : {},
|
||||
env.ANALYZE_SIZE?{ plugins: [ new BundleAnalyzerPlugin() ]}:{},
|
||||
env.ANALYZE_SIZE?{ plugins: [ new BundleAnalyzerPlugin(
|
||||
{
|
||||
analyzerMode: 'static',
|
||||
generateStatsFile: true,
|
||||
statsFilename: 'stats.json',
|
||||
}
|
||||
) ]}:{},
|
||||
|
||||
|
||||
{
|
||||
entry:
|
||||
{
|
||||
@@ -170,7 +179,6 @@ module.exports = (env, options) => (
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'SqueezeESP32',
|
||||
template: './src/index.ejs',
|
||||
@@ -328,6 +336,7 @@ extern const uint8_t * resource_map_end[];`;
|
||||
optimization: {
|
||||
minimize: true,
|
||||
providedExports: true,
|
||||
usedExports: true,
|
||||
minimizer: [
|
||||
|
||||
new TerserPlugin({
|
||||
@@ -340,7 +349,14 @@ extern const uint8_t * resource_map_end[];`;
|
||||
// enable parallel running
|
||||
parallel: true,
|
||||
}),
|
||||
new HtmlMinimizerPlugin(),
|
||||
new HtmlMinimizerPlugin({
|
||||
minimizerOptions: {
|
||||
removeComments: true,
|
||||
removeOptionalTags: true,
|
||||
|
||||
}
|
||||
}
|
||||
),
|
||||
new CssMinimizerPlugin(),
|
||||
new ImageMinimizerPlugin({
|
||||
minimizer: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/***********************************
|
||||
webpack_headers
|
||||
dist/css/index.60aa97be4459083adfab.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.392dfa.bundle.js.gz,dist/js/node_vendors.392dfa.bundle.js.gz
|
||||
dist/css/index.cd56ff129e3113d8cd3a.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.ab1d13.bundle.js.gz,dist/js/node_vendors.ab1d13.bundle.js.gz
|
||||
***********************************/
|
||||
#pragma once
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -6,6 +6,7 @@ const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||
const { Command } = require('commander');
|
||||
let cmdLines= { };
|
||||
var { parseArgsStringToArgv } = require('string-argv');
|
||||
const PORT = 9100;
|
||||
|
||||
const data = {
|
||||
messages: require("../mock/messages.json"),
|
||||
@@ -133,11 +134,10 @@ const connectReturnCode = {
|
||||
}
|
||||
module.exports ={
|
||||
entry: {
|
||||
test: './src/test.ts',
|
||||
test: './src/test.ts'
|
||||
|
||||
},
|
||||
devServer: {
|
||||
|
||||
|
||||
static: {
|
||||
directory: path.resolve(__dirname, './dist'),
|
||||
staticOptions: {},
|
||||
@@ -158,11 +158,10 @@ module.exports ={
|
||||
},
|
||||
open: true,
|
||||
compress: true,
|
||||
port: 9100,
|
||||
port: PORT,
|
||||
host: '127.0.0.1',//your ip address
|
||||
allowedHosts: "all",
|
||||
headers: {'Access-Control-Allow-Origin': '*',
|
||||
'Accept-Encoding': 'identity'},
|
||||
headers: {'Access-Control-Allow-Origin': '*', 'Accept-Encoding': 'identity'},
|
||||
client: {
|
||||
logging: "verbose",
|
||||
// Can be used only for `errors`/`warnings`
|
||||
@@ -179,8 +178,18 @@ module.exports ={
|
||||
throw new Error('webpack-dev-server is not defined');
|
||||
}
|
||||
|
||||
const port = devServer.server.address().port;
|
||||
console.log('Listening on port:', port);
|
||||
const PORT = devServer.server.address().port;
|
||||
|
||||
// get the path to the test page
|
||||
const compiler = devServer.compiler;
|
||||
const entry = compiler.options.entry;
|
||||
const testEntry = entry['test'].import[0];
|
||||
const testPath = testEntry.replace('./src/', '').replace('.ts', '.html');
|
||||
|
||||
// open the test page
|
||||
import('open').then((open) => open.default(`http://localhost:${PORT}/${testPath}`));
|
||||
|
||||
|
||||
},
|
||||
|
||||
onBeforeSetupMiddleware: function (devServer) {
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
|
||||
# Check if the required dependencies are installed
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
if(Python3_Interpreter_FOUND)
|
||||
execute_process(COMMAND pip3 install protobuf grpcio-tools)
|
||||
else()
|
||||
message(FATAL_ERROR "Python3 interpreter not found. Please install Python3 before building the project.")
|
||||
endif()
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
function(___register_flash partition_name sub_type)
|
||||
|
||||
Reference in New Issue
Block a user