Pārlūkot izejas kodu

add a quick LED helper / prepare SqueezeAMP menuconfig

philippe44 5 gadi atpakaļ
vecāks
revīzija
da63df4d93

+ 2 - 0
README.md

@@ -46,8 +46,10 @@ nvs_set autoexec2 str -v "squeezelite -o \"BT -n 'MySpeaker'\" -b 500:2000 -R -u
 			#pragma GCC optimize ("O0")
 			#pragma GCC pop_options
 - opus & opusfile 
+	- for opus, the ESP-provided library seems to work, but opusfile is still needed
 	- per mad & few others, edit configure and change $ac_link to add -c (faking link)
 	- change ac_files to remove ''
+	- add DEPS_CFLAGS and DEPS_LIBS to avoid pkg-config to be required
 - better use helixaac			
 - set IDF_PATH=/home/esp-idf
 - set ESPPORT=COM9

+ 10 - 0
components/io/component.mk

@@ -0,0 +1,10 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_ADD_INCLUDEDIRS := .

+ 101 - 0
components/io/led.c

@@ -0,0 +1,101 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/timers.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "driver/gpio.h"
+#include "led.h"
+
+#define MAX_LED	8
+#define BLOCKTIME	10	// up to portMAX_DELAY
+
+static struct led_s {
+	gpio_num_t gpio;
+	bool on;
+	int onstate;
+	int ontime, offtime;
+	int waiton, waitoff;
+	TimerHandle_t timer;
+} leds[MAX_LED];
+
+static void vCallbackFunction( TimerHandle_t xTimer ) {
+	struct led_s *led = (struct led_s*) pvTimerGetTimerID (xTimer);
+	
+	if (!led->timer) return;
+	
+	led->on = !led->on;
+	gpio_set_level(led->gpio, led->on ? led->onstate : !led->onstate);
+	
+	// was just on for a while
+	if (!led->on && led->offtime == -1) return;
+	
+	// regular blinking
+	xTimerChangePeriod(xTimer, (led->on ? led->ontime : led->offtime) / portTICK_RATE_MS, BLOCKTIME);
+}
+
+bool led_blink_core(int idx, int ontime, int offtime, bool wait) {
+	if (!leds[idx].gpio) return false;
+	
+	if (leds[idx].timer) {
+		// low priority timers will wait	
+		if (wait && xTimerIsTimerActive(leds[idx].timer)) {
+			leds[idx].waiton = ontime; 
+			leds[idx].waitoff = offtime; 
+			return true;
+		}
+		xTimerStop(leds[idx].timer, BLOCKTIME);
+	}
+	
+	leds[idx].ontime = ontime;
+	leds[idx].offtime = offtime;	
+			
+	if (ontime == 0) {
+		gpio_set_level(leds[idx].gpio, !leds[idx].onstate);
+	} else if (offtime == 0) {
+		gpio_set_level(leds[idx].gpio, leds[idx].onstate);
+	} else {
+		if (!leds[idx].timer) leds[idx].timer = xTimerCreate("ledTimer", ontime / portTICK_RATE_MS, pdFALSE, (void *)&leds[idx], vCallbackFunction);
+        leds[idx].on = true;
+		gpio_set_level(leds[idx].gpio, leds[idx].onstate);
+		if (xTimerStart(leds[idx].timer, BLOCKTIME) == pdFAIL) return false;
+	}
+	
+	return true;
+} 
+
+bool led_release(int idx) {
+	if (!leds[idx].gpio) return false;
+	
+	if (leds[idx].waiton) {
+		led_blink_core(idx, leds[idx].waiton, leds[idx].waitoff, false);
+		leds[idx].waiton = 0;
+	} else {
+		gpio_set_level(leds[idx].gpio, !leds[idx].onstate);
+	}	
+	
+	return true;
+}	
+
+bool led_config(int idx, gpio_num_t gpio, int onstate) {
+	if (idx >= MAX_LED) return false;
+	leds[idx].gpio = gpio;
+	leds[idx].onstate = onstate;
+	
+	gpio_pad_select_gpio(gpio);
+	gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
+	gpio_set_level(gpio, !onstate);
+	
+	return true;
+}

+ 37 - 0
components/io/led.h

@@ -0,0 +1,37 @@
+/* 
+ *  Squeezelite for esp32
+ *
+ *  (c) Sebastien 2019
+ *      Philippe G. 2019, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+ 
+#ifndef LED_H
+
+#include "driver/gpio.h"
+
+enum { LED_GREEN = 0, LED_RED };
+
+#define led_on(idx)						led_blink_core(idx, 1, 0, false)
+#define led_off(idx)					led_blink_core(idx, 0, 0, false)
+#define led_blink(idx, on, off)			led_blink_core(idx, on, off, false)
+#define led_blink_wait(idx, on, off)	led_blink_core(idx, on, off, true)
+
+bool led_blink_core(int idx, int ontime, int offtime, bool wait);
+bool led_release(int idx);
+bool led_config(int idx, gpio_num_t gpio, int onstate);
+
+#endif

+ 1 - 1
components/squeezelite/component.mk

@@ -2,7 +2,7 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
-CFLAGS += -O3 -DLINKALL -DLOOPBACK -DTAS575x -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 	\
+CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 	\
 	-I$(COMPONENT_PATH)/../codecs/inc			\
 	-I$(COMPONENT_PATH)/../codecs/inc/mad 		\
 	-I$(COMPONENT_PATH)/../codecs/inc/alac		\

+ 36 - 3
components/squeezelite/output_i2s.c

@@ -43,9 +43,11 @@ sure that using rate_delay would fix that
 #include "squeezelite.h"
 #include "driver/i2s.h"
 #include "driver/i2c.h"
+#include "driver/gpio.h"
 #include "perf_trace.h"
 #include <signal.h>
 #include "time.h"
+#include "led.h"
 
 #define LOCK   mutex_lock(outputbuf->mutex)
 #define UNLOCK mutex_unlock(outputbuf->mutex)
@@ -109,7 +111,18 @@ static void *output_thread_i2s();
 static void *output_thread_i2s_stats();
 static void dac_cmd(dac_cmd_e cmd, ...);
 
-#ifdef TAS575x
+#ifdef CONFIG_SQUEEZEAMP
+
+#define TAS575x
+
+#undef	CONFIG_I2S_BCK_IO 
+#define CONFIG_I2S_BCK_IO 	33
+#undef 	CONFIG_I2S_WS_IO	
+#define CONFIG_I2S_WS_IO	25
+#undef 	CONFIG_I2S_DO_IO
+#define CONFIG_I2S_DO_IO	32
+#undef 	CONFIG_I2S_NUM
+#define CONFIG_I2S_NUM		0
 
 #define I2C_PORT	0
 #define I2C_ADDR	0x4c
@@ -151,7 +164,13 @@ static const struct tas575x_cmd_s tas575x_cmd[] = {
 void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
 	loglevel = level;
 	
-#ifdef TAS575x	
+#ifdef TAS575x
+	gpio_pad_select_gpio(39);
+	gpio_set_direction(39, GPIO_MODE_INPUT);
+	
+	adc1_config_width(ADC_WIDTH_BIT_12);
+    adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_0);
+    			
 	// init volume & mute
 	gpio_pad_select_gpio(VOLUME_GPIO);
 	gpio_set_direction(VOLUME_GPIO, GPIO_MODE_OUTPUT);
@@ -333,6 +352,9 @@ static void *output_thread_i2s() {
 	int discard = 0;
 	uint32_t fullness = gettime_ms();
 	bool synced;
+#ifdef TAS575x					
+	output_state state = OUTPUT_OFF;
+#endif	
 		
 	while (running) {
 			
@@ -340,6 +362,16 @@ static void *output_thread_i2s() {
 		
 		LOCK;
 		
+#ifdef TAS575x						
+		// manage led display
+		if (state != output.state) {
+			if (output.state == OUTPUT_OFF) led_blink(LED_GREEN, 100, 2500);
+			else if (output.state == OUTPUT_STOPPED) led_blink_wait(LED_GREEN, 200, 1000);
+			else if (output.state == OUTPUT_RUNNING) led_on(LED_GREEN);
+		}
+		state = output.state;
+#endif				
+		
 		if (output.state == OUTPUT_OFF) {
 			UNLOCK;
 			LOG_INFO("Output state is off.");
@@ -348,6 +380,7 @@ static void *output_thread_i2s() {
 				i2s_stop(CONFIG_I2S_NUM);
 				dac_cmd(DAC_OFF);
 			}
+			LOG_ERROR("Jack %d Voltage %.2fV", !gpio_get_level(39), adc1_get_raw(ADC1_CHANNEL_0) / 4095. * (10+169)/10. * 1.1);
 			usleep(200000);
 			continue;
 		} else if (output.state == OUTPUT_STOPPED) {
@@ -389,7 +422,7 @@ static void *output_thread_i2s() {
 			LOG_INFO("Restarting I2S.");
 			i2s_zero_dma_buffer(CONFIG_I2S_NUM);
 			i2s_start(CONFIG_I2S_NUM);
-			dac_cmd(DAC_ON);			
+			dac_cmd(DAC_ON);	
 		} 
 		
 		// this does not work well as set_sample_rates resets the fifos (and it's too early)

+ 10 - 18
main/Kconfig.projbuild

@@ -123,26 +123,17 @@ menu "Squeezelite-ESP32"
 	menu "Audio Output"
 		choice OUTPUT_TYPE
 	        prompt "Output Type"
-	        default DACAUDIO
+	        default BASIC_I2C_BT
 	        help
-	            Type of output for squeezelite to send audio to
-	        config DACAUDIO
-	            bool "DAC over I2S"
-	        config BTAUDIO
-	            bool "Bluetooth A2DP"
+	            Type of hardware platform
+	        config SQUEEZEAMP 
+	            bool "SqueezeAMP (TAS575x & Bluetooth)"
+	        config BASIC_I2C_BT
+	            bool "Generic I2S & Bluetooth"
 	    endchoice
-	  	config OUTPUT_NAME 
-			string 
-			default ""
-		    default "BT" if BTAUDIO
-		    default "DAC" if DACAUDIO
-		    
-		config OUTPUT_RATES
-			string "Output rates"
-			default "44100"
-			help
-				<rates>[:<delay>]	Sample rates supported, allows output to be off when squeezelite is started; rates = <maxrate>|<minrate>-<maxrate>|<rate1>,<rate2>,<rate3>; delay = optional delay switching rates in ms
-		menu "DAC I2S settings"  
+	  	
+		menu "DAC I2S settings" 
+			depends on BASIC_I2C_BT
 	    	config I2S_NUM         
 		        int "I2S channel (0 or 1). "
 		        default 0
@@ -180,6 +171,7 @@ menu "Squeezelite-ESP32"
 			    default 24 if I2S_BITS_PER_CHANNEL_24
 			    default 8 if I2S_BITS_PER_CHANNEL_8
 		endmenu
+		
 		menu "A2DP settings"
 		    config A2DP_SINK_NAME
 		        string "Name of Bluetooth A2DP device"

+ 4 - 0
main/cmd_wifi.c

@@ -21,6 +21,7 @@
 #include "esp_wifi.h"
 #include "tcpip_adapter.h"
 #include "esp_event.h"
+#include "led.h"
 
 #define JOIN_TIMEOUT_MS (10000)
 
@@ -46,8 +47,10 @@ static void event_handler(void* arg, esp_event_base_t event_base,
 {
     if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
         esp_wifi_connect();
+		led_blink(LED_GREEN, 250, 250);
         xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
     } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+		led_release(LED_GREEN);
         xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
     }
 }
@@ -89,6 +92,7 @@ static void initialise_wifi(void)
     ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) );
     ESP_ERROR_CHECK( esp_wifi_start() );
     initialized = true;
+	led_blink(LED_GREEN, 250, 250);
 }
 
 static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)

+ 12 - 1
main/esp_app_main.c

@@ -18,10 +18,21 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
- 
 #include "platform_esp32.h"
+#include "led.h"
+
+#ifdef CONFIG_SQUEEZEAMP
+#define LED_GREEN_GPIO 	12
+#define LED_RED_GPIO	13
+#else
+#define LED_GREEN_GPIO 	0
+#define LED_RED_GPIO	0
+#endif
 
 void app_main()
 {
+	led_config(LED_GREEN, LED_GREEN_GPIO, 0);
+	led_config(LED_RED, LED_RED_GPIO, 0);
+	
 	console_start();
 }