mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-12 14:37:21 +03:00
Compare commits
6 Commits
v0.5.641-v
...
v0.5.647-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f08bde8d48 | ||
|
|
a6b57604d3 | ||
|
|
ca33ff4ba9 | ||
|
|
8b55fa3986 | ||
|
|
e04a631665 | ||
|
|
bcb087f9ee |
@@ -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
|
||||
|
||||
@@ -168,7 +168,7 @@ static void Update1( struct GDS_Device* Device ) {
|
||||
}
|
||||
|
||||
// in 1 bit mode, SSD1326 has a different memory map than SSD1306 and SH1106
|
||||
static void IRAM_ATTR DrawPixel1FastLocal( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||
static void IRAM_ATTR _DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||
uint32_t XBit = ( X & 0x07 );
|
||||
uint8_t* FBOffset = Device->Framebuffer + ( ( Y * Device->Width + X ) >> 3 );
|
||||
|
||||
@@ -188,12 +188,12 @@ static void ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int
|
||||
for (int r = y1; r <= y2; r++) {
|
||||
int c = x1;
|
||||
// for a row that is not on a boundary, not column opt can be done, so handle all columns on that line
|
||||
while (c & 0x07 && c <= x2) DrawPixel1FastLocal( Device, c++, r, Color );
|
||||
while (c & 0x07 && c <= x2) _DrawPixel1Fast( Device, c++, r, Color );
|
||||
// at this point we are aligned on column boundary
|
||||
int chunk = (x2 - c + 1) >> 3;
|
||||
memset(optr + Width * r + (c >> 3), _Color, chunk );
|
||||
c += chunk * 8;
|
||||
while (c <= x2) DrawPixel1FastLocal( Device, c++, r, Color );
|
||||
while (c <= x2) _DrawPixel1Fast( Device, c++, r, Color );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ static const struct GDS_Device SSD132x = {
|
||||
struct GDS_Device* SSD132x_Detect(char *Driver, struct GDS_Device* Device) {
|
||||
uint8_t Model;
|
||||
int Depth;
|
||||
|
||||
|
||||
if (strcasestr(Driver, "SSD1326")) Model = SSD1326;
|
||||
else if (strcasestr(Driver, "SSD1327")) Model = SSD1327;
|
||||
else return NULL;
|
||||
@@ -328,13 +328,14 @@ struct GDS_Device* SSD132x_Detect(char *Driver, struct GDS_Device* Device) {
|
||||
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||
|
||||
*Device = SSD132x;
|
||||
((struct PrivateSpace*) Device->Private)->Model = Model;
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
Private->Model = Model;
|
||||
|
||||
sscanf(Driver, "%*[^:]:%u", &Depth);
|
||||
|
||||
if (Model == SSD1326 && Depth == 1) {
|
||||
Device->Update = Update1;
|
||||
Device->DrawPixelFast = DrawPixel1FastLocal;
|
||||
Device->DrawPixelFast = _DrawPixel1Fast;
|
||||
Device->DrawBitmapCBR = DrawBitmapCBR;
|
||||
Device->ClearWindow = ClearWindow;
|
||||
Device->Depth = 1;
|
||||
|
||||
@@ -118,7 +118,7 @@ static void Update( struct GDS_Device* Device ) {
|
||||
}
|
||||
|
||||
// remember that for these ELD drivers W and H are "inverted"
|
||||
static inline void DrawPixelLocal( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||
static inline void _DrawPixel( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||
uint32_t YBit = ( Y & 0x07 );
|
||||
Y>>= 3;
|
||||
|
||||
@@ -129,7 +129,7 @@ static inline void DrawPixelLocal( struct GDS_Device* Device, int X, int Y, int
|
||||
static void ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) {
|
||||
for (int r = y1; r <= y2; r++) {
|
||||
for (int c = x1; c <= x2; c++) {
|
||||
DrawPixelLocal( Device, c, r, Color );
|
||||
_DrawPixel( Device, c, r, Color );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@ static bool Init( struct GDS_Device* Device ) {
|
||||
|
||||
static const struct GDS_Device SSD1675 = {
|
||||
.DrawBitmapCBR = DrawBitmapCBR, .ClearWindow = ClearWindow,
|
||||
.DrawPixelFast = DrawPixelLocal,
|
||||
.DrawPixelFast = _DrawPixel,
|
||||
.Update = Update, .Init = Init,
|
||||
.Mode = GDS_MONO, .Depth = 1,
|
||||
.Alloc = GDS_ALLOC_NONE,
|
||||
|
||||
@@ -282,8 +282,9 @@ struct GDS_Device* ST77xx_Detect(char *Driver, struct GDS_Device* Device) {
|
||||
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||
|
||||
*Device = ST77xx;
|
||||
((struct PrivateSpace*) Device->Private)->Model = Model;
|
||||
sscanf(Driver, "%*[^:]:%u", &Depth);
|
||||
struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
|
||||
Private->Model = Model;
|
||||
|
||||
if (Depth == 18) {
|
||||
Device->Mode = GDS_RGB666;
|
||||
|
||||
@@ -89,7 +89,13 @@ extern struct mdnsd* glmDNSServer;
|
||||
extern log_level raop_loglevel;
|
||||
static log_level *loglevel = &raop_loglevel;
|
||||
|
||||
#ifdef WIN32
|
||||
static void* rtsp_thread(void *arg);
|
||||
static void* search_remote(void *args);
|
||||
#else
|
||||
static void rtsp_thread(void *arg);
|
||||
static void search_remote(void *args);
|
||||
#endif
|
||||
static void cleanup_rtsp(raop_ctx_t *ctx, bool abort);
|
||||
static bool handle_rtsp(raop_ctx_t *ctx, int sock);
|
||||
|
||||
@@ -97,7 +103,7 @@ static char* rsa_apply(unsigned char *input, int inlen, int *outlen, int mode);
|
||||
static int base64_pad(char *src, char **padded);
|
||||
static int base64_encode(const void *data, int size, char **str);
|
||||
static int base64_decode(const char *str, void *data);
|
||||
static void* search_remote(void *args);
|
||||
|
||||
|
||||
extern char private_key[];
|
||||
|
||||
@@ -352,7 +358,11 @@ bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param) {
|
||||
}
|
||||
|
||||
free(command);
|
||||
closesocket(sock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
#ifdef WIN32
|
||||
static void *rtsp_thread(void *arg) {
|
||||
@@ -397,9 +407,9 @@ static void *rtsp_thread(void *arg) {
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sock != -1) closesocket(sock);
|
||||
|
||||
if (sock != -1) closesocket(sock);
|
||||
|
||||
#ifndef WIN32
|
||||
xTaskNotifyGive(ctx->joiner);
|
||||
vTaskSuspend(NULL);
|
||||
@@ -708,7 +718,7 @@ static void* search_remote(void *args) {
|
||||
|
||||
query_mDNS(ctx->active_remote.handle, "_dacp._tcp.local", 0, 0, &search_remote_cb, (void*) ctx);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -741,8 +751,6 @@ static void* search_remote(void *args) {
|
||||
}
|
||||
}
|
||||
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +158,12 @@ static void buffer_reset(abuf_t *audio_buffer);
|
||||
static void buffer_release(abuf_t *audio_buffer);
|
||||
static void buffer_reset(abuf_t *audio_buffer);
|
||||
static void buffer_push_packet(rtp_t *ctx);
|
||||
static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last);
|
||||
static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last);
|
||||
static bool rtp_request_timing(rtp_t *ctx);
|
||||
static int seq_order(seq_t a, seq_t b);
|
||||
#ifdef WIN32
|
||||
static void *rtp_thread_func(void *arg);
|
||||
#else
|
||||
static void rtp_thread_func(void *arg);
|
||||
#endif
|
||||
|
||||
@@ -565,7 +569,11 @@ static void buffer_push_packet(rtp_t *ctx) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef WIN32
|
||||
static void *rtp_thread_func(void *arg) {
|
||||
#else
|
||||
static void rtp_thread_func(void *arg) {
|
||||
#endif
|
||||
@@ -620,8 +628,9 @@ static void *rtp_thread_func(void *arg) {
|
||||
unsigned rtptime;
|
||||
|
||||
// re-sent packet
|
||||
case 0x56: {
|
||||
pktp += 4;
|
||||
case 0x56: {
|
||||
pktp += 4;
|
||||
plen -= 4;
|
||||
}
|
||||
// fall through
|
||||
|
||||
@@ -695,7 +704,6 @@ static void *rtp_thread_func(void *arg) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// NTP timing packet
|
||||
case 0x53: {
|
||||
@@ -712,8 +720,8 @@ static void *rtp_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
/*
|
||||
The expected elapsed remote time should be exactly the same as
|
||||
elapsed local time between the two request, corrected by the
|
||||
elapsed local time between the two request, corrected by the
|
||||
drifting
|
||||
u64_t expected = ctx->timing.remote + MS2NTP(reference - ctx->timing.local);
|
||||
*/
|
||||
@@ -740,9 +748,9 @@ static void *rtp_thread_func(void *arg) {
|
||||
free(packet);
|
||||
LOG_INFO("[%p]: terminating", ctx);
|
||||
|
||||
#ifndef WIN32
|
||||
xTaskNotifyGive(ctx->joiner);
|
||||
#ifndef WIN32
|
||||
xTaskNotifyGive(ctx->joiner);
|
||||
vTaskSuspend(NULL);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ static void ac101_start(ac_module_t mode);
|
||||
static void ac101_stop(void);
|
||||
static void ac101_set_earph_volume(uint8_t volume);
|
||||
static void ac101_set_spk_volume(uint8_t volume);
|
||||
static int ac101_get_spk_volume(void);
|
||||
|
||||
static int i2c_port;
|
||||
|
||||
@@ -268,13 +267,6 @@ void set_sample_rate(int rate) {
|
||||
i2c_write_reg(I2S_SR_CTRL, rate);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get normalized (0..100) speaker volume
|
||||
*/
|
||||
static int ac101_get_spk_volume(void) {
|
||||
return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Set normalized (0..100) volume
|
||||
*/
|
||||
@@ -285,13 +277,6 @@ static void ac101_set_spk_volume(uint8_t volume) {
|
||||
i2c_write_reg(SPKOUT_CTRL, value);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get normalized (0..100) earphone volume
|
||||
*/
|
||||
static int ac101_get_earph_volume(void) {
|
||||
return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Set normalized (0..100) earphone volume
|
||||
*/
|
||||
@@ -302,6 +287,21 @@ static void ac101_set_earph_volume(uint8_t volume) {
|
||||
i2c_write_reg(HPOUT_CTRL, value);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/****************************************************************************************
|
||||
* Get normalized (0..100) speaker volume
|
||||
*/
|
||||
static int ac101_get_spk_volume(void) {
|
||||
return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get normalized (0..100) earphone volume
|
||||
*/
|
||||
static int ac101_get_earph_volume(void) {
|
||||
return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
@@ -330,6 +330,27 @@ static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain,ac_output_mi
|
||||
i2c_write_reg(OMIXER_BST1_CTRL,regval);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void ac101_deinit(void) {
|
||||
i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Don't know when this one is supposed to be called
|
||||
*/
|
||||
static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
|
||||
uint16_t regval=0;
|
||||
regval = i2c_read_reg(I2S1LCK_CTRL);
|
||||
regval &= 0xe03f;
|
||||
regval |= (cfg->bclk_div << 9);
|
||||
regval |= (cfg->lclk_div << 6);
|
||||
i2c_write_reg(I2S1LCK_CTRL, regval);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
@@ -362,21 +383,3 @@ static void ac101_stop(void) {
|
||||
i2c_write_reg(PLL_CTRL2, value);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void ac101_deinit(void) {
|
||||
i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Don't know when this one is supposed to be called
|
||||
*/
|
||||
static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) {
|
||||
uint16_t regval=0;
|
||||
regval = i2c_read_reg(I2S1LCK_CTRL);
|
||||
regval &= 0xe03f;
|
||||
regval |= (cfg->bclk_div << 9);
|
||||
regval |= (cfg->lclk_div << 6);
|
||||
i2c_write_reg(I2S1LCK_CTRL, regval);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
// fifo bufffers
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "squeezelite.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -102,12 +104,42 @@ DECLARE_ALL_MIN_MAX;
|
||||
static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||
static void *output_thread_i2s(void *arg);
|
||||
static void *output_thread_i2s_stats(void *arg);
|
||||
static void output_thread_i2s_stats(void *arg);
|
||||
static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
|
||||
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);
|
||||
@@ -502,13 +538,13 @@ static void *output_thread_i2s(void *arg) {
|
||||
// this does not work well as set_sample_rates resets the fifos (and it's too early)
|
||||
if (i2s_config.sample_rate != output.current_sample_rate) {
|
||||
LOG_INFO("changing sampling rate %u to %u", i2s_config.sample_rate, output.current_sample_rate);
|
||||
/*
|
||||
if (synced)
|
||||
if (synced) {
|
||||
/*
|
||||
// can sleep for a buffer_queue - 1 and then eat a buffer (discard) if we are synced
|
||||
usleep(((DMA_BUF_COUNT - 1) * DMA_BUF_LEN * BYTES_PER_FRAME * 1000) / 44100 * 1000);
|
||||
discard = DMA_BUF_COUNT * DMA_BUF_LEN * BYTES_PER_FRAME;
|
||||
*/
|
||||
}
|
||||
*/
|
||||
i2s_config.sample_rate = output.current_sample_rate;
|
||||
i2s_set_sample_rates(CONFIG_I2S_NUM, spdif ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
|
||||
i2s_zero_dma_buffer(CONFIG_I2S_NUM);
|
||||
@@ -552,7 +588,7 @@ static void *output_thread_i2s(void *arg) {
|
||||
/****************************************************************************************
|
||||
* Stats output thread
|
||||
*/
|
||||
static void *output_thread_i2s_stats(void *arg) {
|
||||
static void output_thread_i2s_stats(void *arg) {
|
||||
while (1) {
|
||||
// no need to lock
|
||||
output_state state = output.state;
|
||||
@@ -579,7 +615,6 @@ static void *output_thread_i2s_stats(void *arg) {
|
||||
}
|
||||
vTaskDelay( pdMS_TO_TICKS( STATS_PERIOD_MS ) );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
// stream thread
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "squeezelite.h"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -37,7 +37,7 @@ extern bool bypass_wifi_manager;
|
||||
|
||||
extern EventGroupHandle_t wifi_event_group;
|
||||
extern const int CONNECTED_BIT;
|
||||
static const char * TAG = "cmd_wifi";
|
||||
//static const char * TAG = "cmd_wifi";
|
||||
/** Arguments used by 'join' function */
|
||||
static struct {
|
||||
struct arg_int *timeout;
|
||||
@@ -123,9 +123,8 @@ static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
return (bits & CONNECTED_BIT) != 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_auto_connect(int argc, char **argv)
|
||||
{
|
||||
//static int set_auto_connect(int argc, char **argv)
|
||||
//{
|
||||
// int nerrors = arg_parse(argc, argv, (void **) &join_args);
|
||||
// if (nerrors != 0) {
|
||||
// arg_print_errors(stderr, join_args.end, argv[0]);
|
||||
@@ -147,8 +146,9 @@ static int set_auto_connect(int argc, char **argv)
|
||||
// return 1;
|
||||
// }
|
||||
// ESP_LOGI(__func__, "Connected");
|
||||
return 0;
|
||||
}
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
static int connect(int argc, char **argv)
|
||||
{
|
||||
int nerrors = arg_parse(argc, argv, (void **) &join_args);
|
||||
|
||||
@@ -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