backend for Muse

This commit is contained in:
Philippe G
2022-01-19 00:51:35 -08:00
parent de025602ac
commit 533ee5e408
10 changed files with 265 additions and 29 deletions

View File

@@ -281,6 +281,19 @@ CONFIG_LED_GREEN_GPIO=-1
CONFIG_LED_RED_GPIO=-1 CONFIG_LED_RED_GPIO=-1
# end of LED configuration # end of LED configuration
#
# Audio controls
#
CONFIG_AUDIO_CONTROLS=""
# end of Audio Contorls configuration
#
# AMP configuration
#
CONFIG_AMP_GPIO=-1
# end of AMP configuration
# #
# Audio JACK # Audio JACK
# #

View File

@@ -274,6 +274,18 @@ CONFIG_BAT_SCALE="20.24"
CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W"
# end of Squeezelite-ESP32 # end of Squeezelite-ESP32
#
# Audio controls
#
CONFIG_AUDIO_CONTROLS=""
# end of Audio Contorls configuration
#
# AMP configuration
#
CONFIG_AMP_GPIO=-1
# end of AMP configuration
# #
# Compiler options # Compiler options
# #

View File

@@ -41,6 +41,8 @@ static struct {
.attenuation = ADC_ATTEN_DB_0, .attenuation = ADC_ATTEN_DB_0,
}; };
void (*battery_handler_svc)(float value);
/**************************************************************************************** /****************************************************************************************
* *
*/ */
@@ -65,6 +67,7 @@ static void battery_callback(TimerHandle_t xTimer) {
if (++battery.count == 30) { if (++battery.count == 30) {
battery.avg = battery.sum / battery.count; battery.avg = battery.sum / battery.count;
battery.sum = battery.count = 0; battery.sum = battery.count = 0;
if (battery_handler_svc) (battery_handler_svc)(battery.avg);
ESP_LOGI(TAG, "Voltage %.2fV", battery.avg); ESP_LOGI(TAG, "Voltage %.2fV", battery.avg);
} }
} }

View File

@@ -20,6 +20,7 @@ extern bool jack_inserted_svc(void);
extern void (*spkfault_handler_svc)(bool inserted); extern void (*spkfault_handler_svc)(bool inserted);
extern bool spkfault_svc(void); extern bool spkfault_svc(void);
extern void (*battery_handler_svc)(float value);
extern float battery_value_svc(void); extern float battery_value_svc(void);
extern uint16_t battery_level_svc(void); extern uint16_t battery_level_svc(void);

View File

@@ -75,6 +75,10 @@ sure that using rate_delay would fix that
#define STATS_PERIOD_MS 5000 #define STATS_PERIOD_MS 5000
#define STAT_STACK_SIZE (3*1024) #define STAT_STACK_SIZE (3*1024)
#ifndef CONFIG_AMP_GPIO_LEVEL
#define CONFIG_AMP_GPIO_LEVEL 1
#endif
extern struct outputstate output; extern struct outputstate output;
extern struct buffer *streambuf; extern struct buffer *streambuf;
extern struct buffer *outputbuf; extern struct buffer *outputbuf;
@@ -101,7 +105,7 @@ static TaskHandle_t stats_task, output_i2s_task;
static bool stats; static bool stats;
static struct { static struct {
int gpio, active; int gpio, active;
} amp_control = { -1, 1 }, } amp_control = { CONFIG_AMP_GPIO, CONFIG_AMP_GPIO_LEVEL },
mute_control = { CONFIG_MUTE_GPIO, CONFIG_MUTE_GPIO_LEVEL }; mute_control = { CONFIG_MUTE_GPIO, CONFIG_MUTE_GPIO_LEVEL };
DECLARE_ALL_MIN_MAX; DECLARE_ALL_MIN_MAX;
@@ -171,20 +175,16 @@ static void jack_handler(bool inserted) {
/**************************************************************************************** /****************************************************************************************
* amp GPIO * amp GPIO
*/ */
#ifndef AMP_GPIO_LOCKED
static void set_amp_gpio(int gpio, char *value) { static void set_amp_gpio(int gpio, char *value) {
char *p; char *p;
if (strcasestr(value, "amp")) { if (strcasestr(value, "amp")) {
amp_control.gpio = gpio; amp_control.gpio = gpio;
if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1); if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1);
gpio_pad_select_gpio_x(amp_control.gpio);
gpio_set_direction_x(amp_control.gpio, GPIO_MODE_OUTPUT);
gpio_set_level_x(amp_control.gpio, !amp_control.active);
LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active);
} }
} }
#endif
/**************************************************************************************** /****************************************************************************************
* Set pin from config string * Set pin from config string
@@ -347,14 +347,22 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
jack_handler_chain = jack_handler_svc; jack_handler_chain = jack_handler_svc;
jack_handler_svc = jack_handler; jack_handler_svc = jack_handler;
#ifndef AMP_GPIO_LOCKED
parse_set_GPIO(set_amp_gpio); parse_set_GPIO(set_amp_gpio);
#endif
if (amp_control.gpio != -1) {
gpio_pad_select_gpio_x(amp_control.gpio);
gpio_set_direction_x(amp_control.gpio, GPIO_MODE_OUTPUT);
gpio_set_level_x(amp_control.gpio, !amp_control.active);
LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active);
}
if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false); if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false);
else adac->speaker(true); else adac->speaker(true);
adac->headset(jack_inserted_svc()); adac->headset(jack_inserted_svc());
// create task as a FreeRTOS task but uses stack in internal RAM // create task as a FreeRTOS task but uses stack in internal RAM
{ {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));

View File

@@ -0,0 +1,13 @@
# This should be made a pure CMake component but as CMake is even
# more shitty under Windows, backslash in path screws it all
if(CONFIG_MUSE)
message("Compiling for MUSE")
set(src_dirs "muse")
else()
set(src_dirs ".")
endif()
idf_component_register( SRC_DIRS ${src_dirs}
PRIV_REQUIRES services
)

View File

@@ -0,0 +1,3 @@
// weak should do the job but it does not...
__attribute__((weak)) void target_init(void) {
}

View File

@@ -0,0 +1,137 @@
/*
YOUR LICENSE
*/
#include <string.h>
#include <esp_log.h>
#include <esp_types.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/adc.h>
#include "driver/rmt.h"
#include "monitor.h"
/////////////////////////////////////////////////////////////////
//*********************** NeoPixels ***************************
////////////////////////////////////////////////////////////////
#define NUM_LEDS 1
#define LED_RMT_TX_CHANNEL 0
#define LED_RMT_TX_GPIO 22
#define BITS_PER_LED_CMD 24
#define LED_BUFFER_ITEMS ((NUM_LEDS * BITS_PER_LED_CMD))
// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet.
#define T0H 14 // 0 bit high time
#define T1H 52 // 1 bit high time
#define TL 52 // low time for either bit
#define GREEN 0xFF0000
#define RED 0x00FF00
#define BLUE 0x0000FF
#define WHITE 0xFFFFFF
#define YELLOW 0xE0F060
struct led_state {
uint32_t leds[NUM_LEDS];
};
void ws2812_control_init(void);
void ws2812_write_leds(struct led_state new_state);
///////////////////////////////////////////////////////////////////
static const char TAG[] = "muse";
static void (*battery_handler_chain)(float value);
static void battery(void *data);
static void battery_svc(float value);
void target_init(void) {
battery_handler_chain = battery_handler_svc;
battery_handler_svc = battery_svc;
ESP_LOGI(TAG, "Initializing for Muse");
}
static void battery_svc(float value) {
ESP_LOGI(TAG, "Called for battery service with %f", value);
if (battery_handler_chain) battery_handler_chain(value);
}
// Battery monitoring
static void battery(void *data)
{
#define VGREEN 2300
#define VRED 2000
#define NM 10
static int val;
static int V[NM];
static int I=0;
int S;
for(int i=0;i<NM;i++)V[i]=VGREEN;
vTaskDelay(1000 / portTICK_PERIOD_MS);
struct led_state new_state;
ws2812_control_init();
// init ADC interface for battery survey
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_GPIO33_CHANNEL, ADC_ATTEN_DB_11);
while(true)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
V[I++] = adc1_get_raw(ADC1_GPIO33_CHANNEL);
if(I >= NM)I = 0;
S = 0;
for(int i=0;i<NM;i++)S = S + V[i];
val = S / NM;
new_state.leds[0] = YELLOW;
if(val > VGREEN) new_state.leds[0] = GREEN;
if(val < VRED) new_state.leds[0] = RED;
printf("====> %d %6x\n", val, new_state.leds[0]);
ws2812_write_leds(new_state);
}
}
// This is the buffer which the hw peripheral will access while pulsing the output pin
rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS];
void setup_rmt_data_buffer(struct led_state new_state);
void ws2812_control_init(void)
{
rmt_config_t config;
config.rmt_mode = RMT_MODE_TX;
config.channel = LED_RMT_TX_CHANNEL;
config.gpio_num = LED_RMT_TX_GPIO;
config.mem_block_num = 3;
config.tx_config.loop_en = false;
config.tx_config.carrier_en = false;
config.tx_config.idle_output_en = true;
config.tx_config.idle_level = 0;
config.clk_div = 2;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
}
void ws2812_write_leds(struct led_state new_state) {
setup_rmt_data_buffer(new_state);
ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false));
ESP_ERROR_CHECK(rmt_wait_tx_done(LED_RMT_TX_CHANNEL, portMAX_DELAY));
}
void setup_rmt_data_buffer(struct led_state new_state)
{
for (uint32_t led = 0; led < NUM_LEDS; led++) {
uint32_t bits_to_send = new_state.leds[led];
uint32_t mask = 1 << (BITS_PER_LED_CMD - 1);
for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) {
uint32_t bit_is_set = bits_to_send & mask;
led_data_buffer[led * BITS_PER_LED_CMD + bit] = bit_is_set ?
(rmt_item32_t){{{T1H, 1, TL, 0}}} :
(rmt_item32_t){{{T0H, 1, TL, 0}}};
mask >>= 1;
}
}
}

View File

@@ -26,6 +26,8 @@ menu "Squeezelite-ESP32"
help help
Set logging level info|debug|sdebug Set logging level info|debug|sdebug
endmenu endmenu
config AMP_LOCKED
bool
config JACK_LOCKED config JACK_LOCKED
bool bool
config BAT_LOCKED config BAT_LOCKED
@@ -59,6 +61,12 @@ menu "Squeezelite-ESP32"
config TWATCH2020 config TWATCH2020
bool "T-WATCH2020 by LilyGo" bool "T-WATCH2020 by LilyGo"
select I2C_LOCKED select I2C_LOCKED
config MUSE
bool "Muse"
select JACK_LOCKED
select BAT_LOCKED
select I2C_LOCKED
select AMP_LOCKED
endchoice endchoice
config RELEASE_API config RELEASE_API
string "Software update URL" string "Software update URL"
@@ -76,11 +84,13 @@ menu "Squeezelite-ESP32"
string string
default "SqueezeAMP" if SQUEEZEAMP default "SqueezeAMP" if SQUEEZEAMP
default "Squeezelite-TWATCH" if TWATCH2020 default "Squeezelite-TWATCH" if TWATCH2020
default "Muse" if MUSE
default "Squeezelite-ESP32" default "Squeezelite-ESP32"
config FW_PLATFORM_NAME config FW_PLATFORM_NAME
string string
default "SqueezeAmp" if SQUEEZEAMP default "SqueezeAmp" if SQUEEZEAMP
default "TWATCH" if TWATCH2020 default "TWATCH" if TWATCH2020
default "Muse" if MUSE
default "ESP32" default "ESP32"
# AGGREGATES - begin # AGGREGATES - begin
# these parameters are "aggregates" that take precedence. They must have a default value # these parameters are "aggregates" that take precedence. They must have a default value
@@ -88,6 +98,7 @@ menu "Squeezelite-ESP32"
string string
default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP
default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020 default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020
default "model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck" if MUSE
default "" default ""
config SPDIF_CONFIG config SPDIF_CONFIG
string string
@@ -99,6 +110,7 @@ menu "Squeezelite-ESP32"
config SPI_CONFIG config SPI_CONFIG
string string
default "dc=27,data=19,clk=18" if TWATCH2020 default "dc=27,data=19,clk=18" if TWATCH2020
default "mosi=15,miso=2,clk=14" if MUSE
default "" default ""
config DISPLAY_CONFIG config DISPLAY_CONFIG
string string
@@ -107,16 +119,24 @@ menu "Squeezelite-ESP32"
config ETH_CONFIG config ETH_CONFIG
string string
default "" default ""
# AGGREGATES - end
config DAC_CONTROLSET config DAC_CONTROLSET
string string
default '{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and" } ] }' if TWATCH2020 default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020
default "{\"init\":[ {\"reg\":0,\"val\":128}, {\"reg\":0,\"val\":0}, {\"reg\":25,\"val\":4}, {\"reg\":1,\"val\":80}, {\"reg\":2,\"val\":0}, {\"reg\":8,\"val\":0}, {\"reg\":4,\"val\":192}, {\"reg\":0,\"val\":18}, {\"reg\":1,\"val\":0}, {\"reg\":23,\"val\":24}, {\"reg\":24,\"val\":2}, {\"reg\":38,\"val\":9}, {\"reg\":39,\"val\":144}, {\"reg\":42,\"val\":144}, {\"reg\":43,\"val\":128}, {\"reg\":45,\"val\":128}, {\"reg\":27,\"val\":0}, {\"reg\":26,\"val\":0}, {\"reg\":2,\"val\":240}, {\"reg\":2,\"val\":0}, {\"reg\":29,\"val\":28}, {\"reg\":4,\"val\":48}, {\"reg\":25,\"val\":0} ]}" if MUSE
default "" default ""
# AGGREGATES - end config AUDIO_CONTROLS
string
# VARs that must be reset when changign target default "[{\"gpio\":32, \"pull\":true, \"debounce\":10, \"normal\":{\"pressed\":\"ACTRLS_VOLDOWN\"}}, {\"gpio\":19, \"pull\":true, \"debounce\":40, \"normal\":{\"pressed\":\"ACTRLS_VOLUP\"}}, {\"gpio\":12, \"pull\":true, \"debounce\":40, \"longpress\":1000, \"normal\":{\"pressed\":\"ACTRLS_TOGGLE\"},\"longpress\":{\"pressed\":\"ACTRLS_POWER\"}}]" if MUSE
default ""
default -1
config AMP_GPIO
int
default 21 if MUSE
default -1
config JACK_GPIO config JACK_GPIO
int int
default 34 if SQUEEZEAMP default 34 if SQUEEZEAMP || MUSE
default -1 default -1
config SPKFAULT_GPIO config SPKFAULT_GPIO
int int
@@ -129,6 +149,7 @@ menu "Squeezelite-ESP32"
config LED_GREEN_GPIO config LED_GREEN_GPIO
int int
default 12 if SQUEEZEAMP default 12 if SQUEEZEAMP
default 22 if MUSE
default -1 default -1
config LED_RED_GPIO config LED_RED_GPIO
int int
@@ -275,6 +296,14 @@ menu "Squeezelite-ESP32"
Enable Spotify connect using CSpot Enable Spotify connect using CSpot
endmenu endmenu
menu "Controls"
depends on !MUSE
config AUDIO_CONTROLS
string "Audio buttons set (JSON)"
help
Configuration of buttons (see README for syntax)
endmenu
menu "Display Screen" menu "Display Screen"
depends on !TWATCH2020 depends on !TWATCH2020
config DISPLAY_CONFIG config DISPLAY_CONFIG
@@ -320,8 +349,9 @@ menu "Squeezelite-ESP32"
Set parameters of GPIO extender Set parameters of GPIO extender
model=<model>[,addr=<addr>][,base=<100..N>][,count=<0..32>][,intr=<gpio>][,port=dac|system] model=<model>[,addr=<addr>][,base=<100..N>][,count=<0..32>][,intr=<gpio>][,port=dac|system]
endmenu endmenu
menu "LED configuration" menu "LED configuration"
visible if !SQUEEZEAMP && !TWATCH2020 visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
config LED_GREEN_GPIO config LED_GREEN_GPIO
int "Green led GPIO" int "Green led GPIO"
help help
@@ -339,8 +369,9 @@ menu "Squeezelite-ESP32"
default 0 if SQUEEZEAMP default 0 if SQUEEZEAMP
default 1 default 1
endmenu endmenu
menu "Audio JACK" menu "Audio JACK"
visible if !SQUEEZEAMP && !TWATCH2020 visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
config JACK_GPIO config JACK_GPIO
int "Jack insertion GPIO" int "Jack insertion GPIO"
help help
@@ -350,8 +381,21 @@ menu "Squeezelite-ESP32"
int "Level when inserted (0/1)" int "Level when inserted (0/1)"
default 0 default 0
endmenu endmenu
menu "Amplifier"
visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
config AMP_GPIO
int "Amplifier GPIO"
help
GPIO to switch on/off amplifier. Set to -1 for no amplifier.
config AMP_GPIO_LEVEL
depends on AMP_GPIO != -1
int "Active level(0/1)"
default 1
endmenu
menu "Speaker Fault" menu "Speaker Fault"
visible if !SQUEEZEAMP && !TWATCH2020 visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
config SPKFAULT_GPIO config SPKFAULT_GPIO
int "Speaker fault GPIO" int "Speaker fault GPIO"
help help

View File

@@ -71,6 +71,7 @@ extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end");
// as an exception _init function don't need include // as an exception _init function don't need include
extern void services_init(void); extern void services_init(void);
extern void display_init(char *welcome); extern void display_init(char *welcome);
extern void target_init(void);
const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); } const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); }
const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); } const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); }
bool is_recovery_running; bool is_recovery_running;
@@ -446,6 +447,7 @@ void app_main()
ESP_LOGI(TAG,"Initializing display"); ESP_LOGI(TAG,"Initializing display");
display_init("SqueezeESP32"); display_init("SqueezeESP32");
MEMTRACE_PRINT_DELTA(); MEMTRACE_PRINT_DELTA();
target_init();
if(is_recovery_running && display){ if(is_recovery_running && display){
GDS_ClearExt(display, true); GDS_ClearExt(display, true);
GDS_SetFont(display, &Font_line_2 ); GDS_SetFont(display, &Font_line_2 );