diff --git a/components/targets/CMakeLists.txt b/components/targets/CMakeLists.txt new file mode 100644 index 00000000..f8a5b188 --- /dev/null +++ b/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 +) diff --git a/components/targets/init.c b/components/targets/init.c new file mode 100644 index 00000000..2db96c56 --- /dev/null +++ b/components/targets/init.c @@ -0,0 +1,3 @@ +# weak should do the job but it does not + __attribute__((weak)) void target_init(void) { +} diff --git a/components/targets/muse/muse.c b/components/targets/muse/muse.c new file mode 100644 index 00000000..d09fa402 --- /dev/null +++ b/components/targets/muse/muse.c @@ -0,0 +1,137 @@ +/* + YOUR LICENSE + */ +#include +#include +#include +#include +#include +#include +#include +#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 = 0; + S = 0; + for(int i=0;i 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; + } + } + } + diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index b377b0c1..8fe1275d 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -114,12 +114,16 @@ 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\":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 "" - # AGGREGATES - end + 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 "" endmenu menu "Ethernet Options" @@ -286,29 +290,37 @@ menu "Squeezelite-ESP32" config BT_NAME depends on BT_SINK string "Name of Bluetooth A2DP device" - default "ESP32-BT" + default "ESP32-BT" help This is the name of the bluetooth speaker that will be broadcasted config BT_SINK_PIN depends on BT_SINK int "Bluetooth PIN code" - default 1234 + default 1234 config AIRPLAY_SINK bool "AirPlay receiver" default y config AIRPLAY_NAME depends on AIRPLAY_SINK string "Name of AirPlay device" - default "ESP32-AirPlay" + default "ESP32-AirPlay" help This is the name of the AirPlay speaker that will be broadcasted config AIRPLAY_PORT depends on AIRPLAY_SINK string "AirPlay listening port" - default 5000 + default 5000 help AirPlay service listening port 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 @@ -355,6 +367,7 @@ menu "Squeezelite-ESP32" Set parameters of GPIO extender model=[,addr=][,base=<100..N>][,count=<0..32>][,intr=][,port=dac|system] endmenu + menu "LED configuration" visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE config LED_GREEN_GPIO @@ -381,6 +394,7 @@ menu "Squeezelite-ESP32" default 0 if SQUEEZEAMP default 1 endmenu + menu "Audio JACK" visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE config JACK_GPIO @@ -394,6 +408,7 @@ menu "Squeezelite-ESP32" int "Level when inserted (0/1)" default 0 endmenu + menu "Amplifier" visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE config AMP_GPIO @@ -407,6 +422,7 @@ menu "Squeezelite-ESP32" int "Active level(0/1)" default 1 endmenu + menu "Speaker Fault" visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE config SPKFAULT_GPIO @@ -420,6 +436,7 @@ menu "Squeezelite-ESP32" int "Level when fault (0/1)" default 0 endmenu + menu "Battery measure" visible if !SQUEEZEAMP && !TWATCH2020 config BAT_CHANNEL diff --git a/main/esp_app_main.c b/main/esp_app_main.c index f42adcef..67d3507d 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -68,6 +68,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; @@ -473,6 +474,8 @@ void app_main() ESP_LOGI(TAG,"Initializing display"); display_init("SqueezeESP32"); + + target_init(); if(is_recovery_running && display){ GDS_ClearExt(display, true); @@ -501,7 +504,7 @@ void app_main() if(!is_recovery_running){ ESP_LOGD(TAG,"Getting audio control mapping "); - char *actrls_config = config_alloc_get_default(NVS_TYPE_STR, "actrls_config", NULL, 0); + char *actrls_config = config_alloc_get_default(NVS_TYPE_STR, "actrls_config", CONFIG_AUDIO_CONTROLS, 0); if (actrls_init(actrls_config) == ESP_OK) { ESP_LOGD(TAG,"Initializing audio control buttons type %s", actrls_config); } else {