mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-12 22:47:15 +03:00
Compare commits
5 Commits
v0.5.642-v
...
v0.5.647-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f08bde8d48 | ||
|
|
a6b57604d3 | ||
|
|
ca33ff4ba9 | ||
|
|
8b55fa3986 | ||
|
|
e04a631665 |
@@ -86,6 +86,7 @@ The parameter "dac_controlset" allows definition of simple commands to be sent o
|
||||
```
|
||||
This is standard JSON notation, so if you are not familiar with it, Google is your best friend. Be aware that the '...' means you can have as many entries as you want, it's not part of the syntax. Every section is optional, but it does not make sense to set i2c in the 'dac_config' parameter and not setting anything here. The parameter 'mode' allows to *or* the register with the value or to *and* it. Don't set 'mode' if you simply want to write. **Note that all values must be decimal**
|
||||
|
||||
NB: For well-known configuration, this is ignored
|
||||
### SPDIF
|
||||
The NVS parameter "spdif_config" sets the i2s's gpio needed for SPDIF.
|
||||
|
||||
@@ -97,6 +98,7 @@ Leave it blank to disable SPDIF usage, you can also define them at compile time
|
||||
```
|
||||
bck=<gpio>,ws=<gpio>,do=<gpio>
|
||||
```
|
||||
NB: For well-known configuration, this is ignored
|
||||
### Display
|
||||
The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
|
||||
```
|
||||
@@ -156,12 +158,13 @@ Syntax is:
|
||||
```
|
||||
<gpio>=Vcc|GND|amp[:1|0]|ir|jack[:0|1]|green[:0|1]|red[:0|1]|spkfault[:0|1][,<repeated sequence for next GPIO>]
|
||||
```
|
||||
You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for SqueezeAMP where these are forced at runtime.
|
||||
You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for well-known configurations where these are forced at runtime.
|
||||
### LED
|
||||
See §**set_GPIO** for how to set the green and red LEDs. In addition, their brightness can be controlled using the "led_brigthness" parameter. The syntax is
|
||||
```
|
||||
[green=0..100][,red=0..100]
|
||||
```
|
||||
NB: For well-known configuration, this is ignored
|
||||
### Rotary Encoder
|
||||
One rotary encoder is supported, quadrature shift with press. Such encoders usually have 2 pins for encoders (A and B), and common C that must be set to ground and an optional SW pin for press. A, B and SW must be pulled up, so automatic pull-up is provided by ESP32, but you can add your own resistors. A bit of filtering on A and B (~470nF) helps for debouncing which is not made by software.
|
||||
|
||||
@@ -278,9 +281,9 @@ There is no good or bad option, it's your choice. Use the NVS parameter "lms_ctr
|
||||
### Battery / ADC
|
||||
The NVS parameter "bat_config" sets the ADC1 channel used to measure battery/DC voltage. Scale is a float ratio applied to every sample of the 12 bits ADC. A measure is taken every 10s and an average is made every 5 minutes (not a sliding window). Syntax is
|
||||
```
|
||||
channel=0..7,scale=<scale>
|
||||
channel=0..7,scale=<scale>,cells=<2|3>
|
||||
```
|
||||
NB: Set parameter to empty to disable battery reading
|
||||
NB: Set parameter to empty to disable battery reading. For well-known configuration, this is ignored (except for SqueezeAMP where number of cells is required)
|
||||
## Setting up ESP-IDF
|
||||
### Docker
|
||||
You can use docker to build squeezelite-esp32
|
||||
|
||||
@@ -26,7 +26,7 @@ CONFIG_SPKFAULT_GPIO=-1
|
||||
CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=-1
|
||||
CONFIG_BAT_SCALE="0"
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=27
|
||||
CONFIG_SPDIF_WS_IO=26
|
||||
CONFIG_SPDIF_DO_IO=-1
|
||||
@@ -116,10 +116,6 @@ CONFIG_INCLUDE_VORBIS=y
|
||||
CONFIG_INCLUDE_ALAC=y
|
||||
|
||||
CONFIG_A1S=y
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=-1
|
||||
CONFIG_SPDIF_WS_IO=-1
|
||||
CONFIG_SPDIF_DO_IO=-1
|
||||
|
||||
CONFIG_A2DP_SINK_NAME="SMSL BT4.2"
|
||||
CONFIG_A2DP_DEV_NAME="Squeezelite"
|
||||
|
||||
@@ -25,13 +25,13 @@ CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=-1
|
||||
CONFIG_BAT_SCALE="0"
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_I2S_BCK_IO=33
|
||||
CONFIG_I2S_WS_IO=25
|
||||
CONFIG_I2S_DO_IO=32
|
||||
CONFIG_I2S_BCK_IO=-1
|
||||
CONFIG_I2S_WS_IO=-1
|
||||
CONFIG_I2S_DO_IO=-1
|
||||
CONFIG_I2S_DI_IO=-1
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=33
|
||||
CONFIG_SPDIF_WS_IO=25
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=-1
|
||||
CONFIG_SPDIF_WS_IO=-1
|
||||
CONFIG_SPDIF_DO_IO=-1
|
||||
CONFIG_MUTE_GPIO=-1
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
@@ -121,11 +121,6 @@ CONFIG_INCLUDE_ALAC=y
|
||||
|
||||
CONFIG_BASIC_I2C_BT=y
|
||||
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_BCK_IO=-1
|
||||
CONFIG_SPDIF_WS_IO=-1
|
||||
CONFIG_SPDIF_DO_IO=-1
|
||||
|
||||
CONFIG_A2DP_SINK_NAME="SMSL BT4.2"
|
||||
CONFIG_A2DP_DEV_NAME="Squeezelite"
|
||||
CONFIG_A2DP_CONTROL_DELAY_MS=500
|
||||
|
||||
@@ -29,7 +29,7 @@ CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=7
|
||||
CONFIG_BAT_SCALE="20.24"
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
|
||||
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0"
|
||||
CONFIG_IDF_TARGET_ESP32=y
|
||||
|
||||
@@ -29,7 +29,7 @@ CONFIG_SPKFAULT_GPIO_LEVEL=0
|
||||
CONFIG_BAT_CHANNEL=7
|
||||
CONFIG_BAT_SCALE="20.24"
|
||||
CONFIG_I2S_NUM=0
|
||||
CONFIG_SDIF_NUM=0
|
||||
CONFIG_SPDIF_NUM=0
|
||||
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
|
||||
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14"
|
||||
CONFIG_MUTE_GPIO_LEVEL=-1
|
||||
|
||||
@@ -33,15 +33,27 @@ static struct {
|
||||
int channel;
|
||||
float sum, avg, scale;
|
||||
int count;
|
||||
int cells;
|
||||
TimerHandle_t timer;
|
||||
} battery;
|
||||
} battery = {
|
||||
.channel = CONFIG_BAT_CHANNEL,
|
||||
.cells = 2,
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
int battery_value_svc(void) {
|
||||
return battery.avg;
|
||||
return battery.avg;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
uint8_t battery_level_svc(void) {
|
||||
// TODO: this is totally incorrect
|
||||
return battery.avg ? (battery.avg - (3.0 * battery.cells)) / ((4.2 - 3.0) * battery.cells) * 100 : 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
@@ -59,29 +71,30 @@ static void battery_callback(TimerHandle_t xTimer) {
|
||||
*
|
||||
*/
|
||||
void battery_svc_init(void) {
|
||||
battery.channel = CONFIG_BAT_CHANNEL;
|
||||
#ifdef CONFIG_BAT_SCALE
|
||||
battery.scale = atof(CONFIG_BAT_SCALE);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BAT_LOCKED
|
||||
char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "n", 0);
|
||||
if (nvs_item) {
|
||||
char *p;
|
||||
char *p;
|
||||
#ifndef CONFIG_BAT_LOCKED
|
||||
if ((p = strcasestr(nvs_item, "channel")) != NULL) battery.channel = atoi(strchr(p, '=') + 1);
|
||||
if ((p = strcasestr(nvs_item, "scale")) != NULL) battery.scale = atof(strchr(p, '=') + 1);
|
||||
#endif
|
||||
if ((p = strcasestr(nvs_item, "cells")) != NULL) battery.cells = atof(strchr(p, '=') + 1);
|
||||
free(nvs_item);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (battery.channel != -1) {
|
||||
ESP_LOGI(TAG, "Battery measure channel: %u, scale %f", battery.channel, battery.scale);
|
||||
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
adc1_config_channel_atten(battery.channel, ADC_ATTEN_DB_0);
|
||||
|
||||
|
||||
battery.avg = adc1_get_raw(battery.channel) * battery.scale / 4095.0;
|
||||
battery.timer = xTimerCreate("battery", BATTERY_TIMER / portTICK_RATE_MS, pdTRUE, NULL, battery_callback);
|
||||
xTimerStart(battery.timer, portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, cells %u, avg %.2fV", battery.channel, battery.scale, battery.cells, battery.avg);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No battery");
|
||||
}
|
||||
|
||||
@@ -17,4 +17,5 @@ extern void (*spkfault_handler_svc)(bool inserted);
|
||||
extern bool spkfault_svc(void);
|
||||
|
||||
extern int battery_value_svc(void);
|
||||
extern uint8_t battery_level_svc(void);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "monitor.h"
|
||||
|
||||
mutex_type slimp_mutex;
|
||||
|
||||
@@ -60,3 +61,11 @@ u16_t get_RSSI(void) {
|
||||
if (wifidata.primary != 0) return 100 + wifidata.rssi + 30;
|
||||
else return 0xffff;
|
||||
}
|
||||
|
||||
u16_t get_plugged(void) {
|
||||
return jack_inserted_svc() ? PLUG_HEADPHONE : 0;
|
||||
}
|
||||
|
||||
u8_t get_battery(void) {
|
||||
return (battery_level_svc() * 16) / 100;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,13 @@ extern mutex_type slimp_mutex;
|
||||
#define LOCK_P mutex_lock(slimp_mutex)
|
||||
#define UNLOCK_P mutex_unlock(slimp_mutex)
|
||||
|
||||
// must provide or define as 0xffff
|
||||
u16_t get_RSSI(void);
|
||||
// bitmap of plugs status
|
||||
#define PLUG_LINE_IN 0x01
|
||||
#define PLUG_LINE_OUT 0x02
|
||||
#define PLUG_HEADPHONE 0x04
|
||||
u16_t get_RSSI(void); // must provide or define as 0xffff
|
||||
u16_t get_plugged(void); // must provide or define as 0x0
|
||||
u8_t get_battery(void); // must provide 0..15 or define as 0x0
|
||||
|
||||
// to be defined to nothing if you don't want to support these
|
||||
extern struct visu_export_s {
|
||||
|
||||
@@ -31,6 +31,7 @@ sure that using rate_delay would fix that
|
||||
*/
|
||||
|
||||
#include "squeezelite.h"
|
||||
#include "slimproto.h"
|
||||
#include "esp_pthread.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2c.h"
|
||||
@@ -82,6 +83,7 @@ const struct adac_s *adac = &dac_external;
|
||||
|
||||
static log_level loglevel;
|
||||
|
||||
static bool (*slimp_handler_chain)(u8_t *data, int len);
|
||||
static bool jack_mutes_amp;
|
||||
static bool running, isI2SStarted;
|
||||
static i2s_config_t i2s_config;
|
||||
@@ -108,6 +110,36 @@ static void (*jack_handler_chain)(bool inserted);
|
||||
|
||||
#define I2C_PORT 0
|
||||
|
||||
/****************************************************************************************
|
||||
* AUDO packet handler
|
||||
*/
|
||||
static bool handler(u8_t *data, int len){
|
||||
bool res = true;
|
||||
|
||||
if (!strncmp((char*) data, "audo", 4)) {
|
||||
struct audo_packet *pkt = (struct audo_packet*) data;
|
||||
// 0 = headphone (internal speakers off), 1 = sub out,
|
||||
// 2 = always on (internal speakers on), 3 = always off
|
||||
|
||||
if (jack_mutes_amp != (pkt->config == 0)) {
|
||||
jack_mutes_amp = pkt->config == 0;
|
||||
config_set_value(NVS_TYPE_STR, "jack_mutes_amp", jack_mutes_amp ? "y" : "n");
|
||||
|
||||
if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false);
|
||||
else adac->speaker(true);
|
||||
}
|
||||
|
||||
LOG_INFO("got AUDO %02x", pkt->config);
|
||||
} else {
|
||||
res = false;
|
||||
}
|
||||
|
||||
// chain protocol handlers (bitwise or is fine)
|
||||
if (*slimp_handler_chain) res |= (*slimp_handler_chain)(data, len);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* jack insertion handler
|
||||
*/
|
||||
@@ -164,6 +196,10 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
int silent_do = -1;
|
||||
char *p;
|
||||
esp_err_t res;
|
||||
|
||||
// chain SLIMP handlers
|
||||
slimp_handler_chain = slimp_handler;
|
||||
slimp_handler = handler;
|
||||
|
||||
p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0);
|
||||
jack_mutes_amp = (strcmp(p,"1") == 0 ||strcasecmp(p,"y") == 0);
|
||||
|
||||
@@ -190,6 +190,7 @@ static void sendSTAT(const char *event, u32_t server_timestamp) {
|
||||
packN(&pkt.bytes_received_L, (u64_t)status.stream_bytes & 0xffffffff);
|
||||
#if EMBEDDED
|
||||
packn(&pkt.signal_strength, get_RSSI());
|
||||
packn(&pkt.voltage, (get_battery() << 4) | get_plugged());
|
||||
#else
|
||||
pkt.signal_strength = 0xffff;
|
||||
#endif
|
||||
@@ -197,7 +198,6 @@ static void sendSTAT(const char *event, u32_t server_timestamp) {
|
||||
packN(&pkt.output_buffer_size, status.output_size);
|
||||
packN(&pkt.output_buffer_fullness, status.output_full);
|
||||
packN(&pkt.elapsed_seconds, ms_played / 1000);
|
||||
// voltage;
|
||||
packN(&pkt.elapsed_milliseconds, ms_played);
|
||||
pkt.server_timestamp = server_timestamp; // keep this is server format - don't unpack/pack
|
||||
// error_code;
|
||||
|
||||
@@ -178,6 +178,12 @@ struct codc_packet {
|
||||
u8_t pcm_endianness;
|
||||
};
|
||||
|
||||
// initially Boom
|
||||
struct audo_packet {
|
||||
char opcode[4];
|
||||
u8_t config;
|
||||
};
|
||||
|
||||
#ifndef SUN
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
|
||||
@@ -97,17 +97,17 @@ menu "Squeezelite-ESP32"
|
||||
I2S dma channel to use.
|
||||
config I2S_BCK_IO
|
||||
int "I2S Bit clock GPIO number. "
|
||||
default 33
|
||||
default -1
|
||||
help
|
||||
I2S Bit Clock gpio pin to use.
|
||||
config I2S_WS_IO
|
||||
int "I2S Word Select GPIO number. "
|
||||
default 25
|
||||
default -1
|
||||
help
|
||||
I2S Word Select gpio pin to use.
|
||||
config I2S_DO_IO
|
||||
int "I2S Data Output GPIO number. "
|
||||
default 32
|
||||
default -1
|
||||
help
|
||||
I2S data output gpio pin to use.
|
||||
config I2S_DI_IO
|
||||
|
||||
@@ -333,6 +333,9 @@ void register_default_nvs(){
|
||||
ESP_LOGD(TAG,"Registering default value for key %s", "dac_controlset");
|
||||
config_set_default(NVS_TYPE_STR, "dac_controlset", "", 0);
|
||||
|
||||
ESP_LOGD(TAG,"Registering default value for key %s", "jack_mutes_amp");
|
||||
config_set_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0);
|
||||
|
||||
ESP_LOGD(TAG,"Registering default value for key %s", "bat_config");
|
||||
config_set_default(NVS_TYPE_STR, "bat_config", "", 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user