2
0
Philippe G 3 жил өмнө
parent
commit
533ee5e408

+ 13 - 0
build-scripts/I2S-4MFlash-sdkconfig.defaults

@@ -281,6 +281,19 @@ CONFIG_LED_GREEN_GPIO=-1
 CONFIG_LED_RED_GPIO=-1
 # 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
 #

+ 12 - 0
build-scripts/SqueezeAmp-sdkconfig.defaults

@@ -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"
 # 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
 #

+ 3 - 0
components/services/battery.c

@@ -41,6 +41,8 @@ static struct {
 	.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) {
 		battery.avg = battery.sum / battery.count;
 		battery.sum = battery.count = 0;
+		if (battery_handler_svc) (battery_handler_svc)(battery.avg);
 		ESP_LOGI(TAG, "Voltage %.2fV", battery.avg);
 	}	
 }

+ 1 - 0
components/services/monitor.h

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

+ 17 - 9
components/squeezelite/output_i2s.c

@@ -75,6 +75,10 @@ sure that using rate_delay would fix that
 #define STATS_PERIOD_MS 5000
 #define STAT_STACK_SIZE	(3*1024)
 
+#ifndef CONFIG_AMP_GPIO_LEVEL
+#define CONFIG_AMP_GPIO_LEVEL 1
+#endif
+
 extern struct outputstate output;
 extern struct buffer *streambuf;
 extern struct buffer *outputbuf;
@@ -101,7 +105,7 @@ static TaskHandle_t stats_task, output_i2s_task;
 static bool stats;
 static struct {
 	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 };
 
 DECLARE_ALL_MIN_MAX;
@@ -171,20 +175,16 @@ static void jack_handler(bool inserted) {
 /****************************************************************************************
  * amp GPIO
  */
+#ifndef AMP_GPIO_LOCKED 
 static void set_amp_gpio(int gpio, char *value) {
 	char *p;
 	
 	if (strcasestr(value, "amp")) {
 		amp_control.gpio = gpio;
 		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
@@ -347,13 +347,21 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
 	jack_handler_chain = jack_handler_svc;
 	jack_handler_svc = jack_handler;
 	
+#ifndef AMP_GPIO_LOCKED	
 	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);
 	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
 	{

+ 13 - 0
components/targets/CMakeLists.txt

@@ -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
+)

+ 3 - 0
components/targets/init.c

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

+ 137 - 0
components/targets/muse/muse.c

@@ -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;
+    }
+  }
+  }
+

+ 64 - 20
main/Kconfig.projbuild

@@ -26,6 +26,8 @@ menu "Squeezelite-ESP32"
 			help
 				Set logging level info|debug|sdebug
 	endmenu
+	config AMP_LOCKED
+		bool
 	config JACK_LOCKED
 		bool
 	config BAT_LOCKED
@@ -55,11 +57,17 @@ menu "Squeezelite-ESP32"
 				select LED_LOCKED
 				select SPKFAULT_LOCKED
 			config BASIC_I2C_BT
-				bool "Generic I2S & Bluetooth"
-			config TWATCH2020
-				bool "T-WATCH2020 by LilyGo"
+				bool "Generic I2S & Bluetooth"				
+			config TWATCH2020	
+				bool "T-WATCH2020 by LilyGo"				
+				select I2C_LOCKED		
+			config MUSE
+				bool "Muse"
+				select JACK_LOCKED
+				select BAT_LOCKED
 				select I2C_LOCKED
-		endchoice
+				select AMP_LOCKED
+		endchoice	
 		config RELEASE_API
 			string "Software update URL"
 			default "https://api.github.com/repos/sle118/squeezelite-esp32/releases"
@@ -76,11 +84,13 @@ menu "Squeezelite-ESP32"
 			string
 			default "SqueezeAMP" if SQUEEZEAMP
 			default "Squeezelite-TWATCH" if TWATCH2020
+			default "Muse" if MUSE
 			default "Squeezelite-ESP32"
 		config FW_PLATFORM_NAME
 			string
 			default "SqueezeAmp" if SQUEEZEAMP
 			default "TWATCH" if TWATCH2020
+			default "Muse" if MUSE
 			default "ESP32"
 		# AGGREGATES - begin
 		# these parameters are "aggregates"	that take precedence. They must have a default value
@@ -88,6 +98,7 @@ menu "Squeezelite-ESP32"
 			string
 			default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP
 			default "model=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 ""
 		config SPDIF_CONFIG
 			string
@@ -98,7 +109,8 @@ menu "Squeezelite-ESP32"
 			default	""
 		config SPI_CONFIG
 			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	""
 		config DISPLAY_CONFIG
 			string
@@ -107,17 +119,25 @@ menu "Squeezelite-ESP32"
 		config ETH_CONFIG
 			string
 			default ""
+		# AGGREGATES - end							
 		config DAC_CONTROLSET
 			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 ""		
+		config AUDIO_CONTROLS
+			string
+			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 ""
-		# AGGREGATES - end
-
-		# VARs that must be reset when changign target
-		config JACK_GPIO
+			default -1
+		config AMP_GPIO		
 			int
-			default 34 if SQUEEZEAMP
+			default 21 if MUSE
 			default -1
+		config JACK_GPIO
+			int
+			default 34 if SQUEEZEAMP || MUSE
+			default -1			
 		config SPKFAULT_GPIO
 			int
 			default 2 if SQUEEZEAMP
@@ -129,6 +149,7 @@ menu "Squeezelite-ESP32"
 		config LED_GREEN_GPIO
 			int 
 			default 12 if SQUEEZEAMP
+			default 22 if MUSE
 			default -1
 		config LED_RED_GPIO
 			int
@@ -274,6 +295,14 @@ menu "Squeezelite-ESP32"
 			help
 				Enable Spotify connect using CSpot		
 	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"
 		depends on !TWATCH2020
@@ -320,8 +349,9 @@ menu "Squeezelite-ESP32"
 				Set parameters of GPIO extender
 				model=<model>[,addr=<addr>][,base=<100..N>][,count=<0..32>][,intr=<gpio>][,port=dac|system]				
 	endmenu
+	
 	menu "LED configuration"
-		visible if !SQUEEZEAMP && !TWATCH2020
+		visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
 		config LED_GREEN_GPIO
 			int "Green led GPIO"
 			help
@@ -329,7 +359,7 @@ menu "Squeezelite-ESP32"
 		config LED_GREEN_GPIO_LEVEL
 			int "Green led ON level"
 			depends on LED_GREEN_GPIO != -1
-		config LED_RED_GPIO
+		config LED_RED_GPIO				
 			int "Red led GPIO"
 			help
 				Set to -1 for no LED
@@ -339,9 +369,10 @@ menu "Squeezelite-ESP32"
 			default 0 if SQUEEZEAMP
 			default 1
 	endmenu
-	menu "Audio JACK"
-		visible if !SQUEEZEAMP && !TWATCH2020
-		config JACK_GPIO
+	
+    menu "Audio JACK"	
+		visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
+		config JACK_GPIO		
 			int "Jack insertion GPIO"
 			help
 				GPIO to detect speaker jack insertion. Set to -1 for no detection.
@@ -349,10 +380,23 @@ menu "Squeezelite-ESP32"
 			depends on JACK_GPIO != -1
 			int "Level when inserted (0/1)"
 			default 0
-	endmenu
-	menu "Speaker Fault"
-		visible if !SQUEEZEAMP && !TWATCH2020
-		config SPKFAULT_GPIO
+	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"	
+		visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE
+		config SPKFAULT_GPIO		
 			int "Speaker fault GPIO"
 			help
 				GPIO to detect speaker fault condition. Set to -1 for no detection.

+ 2 - 0
main/esp_app_main.c

@@ -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
 extern void services_init(void);
 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_null(const char * str) { return (str?str:null_string_placeholder); }
 bool is_recovery_running;
@@ -446,6 +447,7 @@ void app_main()
 	ESP_LOGI(TAG,"Initializing display");
 	display_init("SqueezeESP32");
 	MEMTRACE_PRINT_DELTA();
+	target_init();
 	if(is_recovery_running && display){
 		GDS_ClearExt(display, true);
 		GDS_SetFont(display, &Font_line_2 );