mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-10 13:37:03 +03:00
Console support WIP!
Some instabilities to tackle. BT Ring buffer were taken out. DAC is crashing with stack overflow. So does A2DP after playing for a little while. This needs to be investigated.
This commit is contained in:
7
components/platform_esp32/CMakeLists.txt
Normal file
7
components/platform_esp32/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
set(COMPONENT_ADD_INCLUDEDIRS . )
|
||||
|
||||
set(COMPONENT_SRCS "esp_app_main.c" "platform_esp32.c" "bt_app_core.c" "cmd_wifi.c" "console.c" "nvs_utilities.c" "cmd_squeezelite.c")
|
||||
set(REQUIRES esp_common)
|
||||
set(REQUIRES_COMPONENTS freertos nvs_flash esp32 spi_flash newlib log console )
|
||||
|
||||
register_component()
|
||||
122
components/platform_esp32/bt_app_core.c
Normal file
122
components/platform_esp32/bt_app_core.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
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 <stdint.h>
|
||||
#include "bt_app_core.h"
|
||||
#include "esp_system.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char * TAG = "platform_esp32";
|
||||
|
||||
static void bt_app_task_handler(void *arg);
|
||||
static bool bt_app_send_msg(bt_app_msg_t *msg);
|
||||
static void bt_app_work_dispatched(bt_app_msg_t *msg);
|
||||
|
||||
static xQueueHandle s_bt_app_task_queue = NULL;
|
||||
static xTaskHandle s_bt_app_task_handle = NULL;
|
||||
|
||||
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s event 0x%x, param len %d", __func__, event, param_len);
|
||||
|
||||
bt_app_msg_t msg;
|
||||
memset(&msg, 0, sizeof(bt_app_msg_t));
|
||||
|
||||
msg.sig = BT_APP_SIG_WORK_DISPATCH;
|
||||
msg.event = event;
|
||||
msg.cb = p_cback;
|
||||
|
||||
if (param_len == 0) {
|
||||
return bt_app_send_msg(&msg);
|
||||
} else if (p_params && param_len > 0) {
|
||||
if ((msg.param = malloc(param_len)) != NULL) {
|
||||
memcpy(msg.param, p_params, param_len);
|
||||
/* check if caller has provided a copy callback to do the deep copy */
|
||||
if (p_copy_cback) {
|
||||
p_copy_cback(&msg, msg.param, p_params);
|
||||
}
|
||||
return bt_app_send_msg(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bt_app_send_msg(bt_app_msg_t *msg)
|
||||
{
|
||||
if (msg == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xQueueSend(s_bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
|
||||
ESP_LOGE(TAG,"%s xQueue send failed", __func__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bt_app_work_dispatched(bt_app_msg_t *msg)
|
||||
{
|
||||
if (msg->cb) {
|
||||
msg->cb(msg->event, msg->param);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_task_handler(void *arg)
|
||||
{
|
||||
bt_app_msg_t msg;
|
||||
for (;;) {
|
||||
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
ESP_LOGV(TAG,"%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
|
||||
switch (msg.sig) {
|
||||
case BT_APP_SIG_WORK_DISPATCH:
|
||||
bt_app_work_dispatched(&msg);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG,"%s, unhandled sig: %d", __func__, msg.sig);
|
||||
break;
|
||||
} // switch (msg.sig)
|
||||
|
||||
if (msg.param) {
|
||||
free(msg.param);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG,"No messaged received from queue.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_app_task_start_up(void)
|
||||
{
|
||||
|
||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
assert(s_bt_app_task_queue!=NULL);
|
||||
assert(xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle)==pdPASS);
|
||||
return;
|
||||
}
|
||||
|
||||
void bt_app_task_shut_down(void)
|
||||
{
|
||||
if (s_bt_app_task_handle) {
|
||||
vTaskDelete(s_bt_app_task_handle);
|
||||
s_bt_app_task_handle = NULL;
|
||||
}
|
||||
if (s_bt_app_task_queue) {
|
||||
vQueueDelete(s_bt_app_task_queue);
|
||||
s_bt_app_task_queue = NULL;
|
||||
}
|
||||
}
|
||||
48
components/platform_esp32/bt_app_core.h
Normal file
48
components/platform_esp32/bt_app_core.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __BT_APP_CORE_H__
|
||||
#define __BT_APP_CORE_H__
|
||||
#include "esp_log.h"
|
||||
#include "time.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define BT_APP_CORE_TAG "BT_APP_CORE"
|
||||
|
||||
#define BT_APP_SIG_WORK_DISPATCH (0x01)
|
||||
|
||||
/**
|
||||
* @brief handler for the dispatched work
|
||||
*/
|
||||
typedef void (* bt_app_cb_t) (uint16_t event, void *param);
|
||||
|
||||
/* message to be sent */
|
||||
typedef struct {
|
||||
uint16_t sig; /*!< signal to bt_app_task */
|
||||
uint16_t event; /*!< message event id */
|
||||
bt_app_cb_t cb; /*!< context switch callback */
|
||||
void *param; /*!< parameter area needs to be last */
|
||||
} bt_app_msg_t;
|
||||
|
||||
/**
|
||||
* @brief parameter deep-copy function to be customized
|
||||
*/
|
||||
typedef void (* bt_app_copy_cb_t) (bt_app_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
/**
|
||||
* @brief work dispatcher for the application task
|
||||
*/
|
||||
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
|
||||
|
||||
void bt_app_task_start_up(void);
|
||||
|
||||
void bt_app_task_shut_down(void);
|
||||
|
||||
#endif /* __BT_APP_CORE_H__ */
|
||||
21
components/platform_esp32/cmd_decl.h
Normal file
21
components/platform_esp32/cmd_decl.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Console example — declarations of command registration functions.
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "cmd_system.h"
|
||||
#include "cmd_wifi.h"
|
||||
#include "cmd_nvs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
173
components/platform_esp32/cmd_squeezelite.c
Normal file
173
components/platform_esp32/cmd_squeezelite.c
Normal file
@@ -0,0 +1,173 @@
|
||||
//size_t esp_console_split_argv(char *line, char **argv, size_t argv_size);
|
||||
#include "cmd_squeezelite.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "cmd_decl.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "pthread.h"
|
||||
#include "platform_esp32.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
//extern char current_namespace[];
|
||||
static const char * TAG = "squeezelite_cmd";
|
||||
#define SQUEEZELITE_THREAD_STACK_SIZE 20480
|
||||
extern int main(int argc, char **argv);
|
||||
static int launchsqueezelite(int argc, char **argv);
|
||||
pthread_t thread_squeezelite;
|
||||
pthread_t thread_squeezelite_runner;
|
||||
/** Arguments used by 'squeezelite' function */
|
||||
static struct {
|
||||
struct arg_str *parameters;
|
||||
struct arg_end *end;
|
||||
} squeezelite_args;
|
||||
static struct {
|
||||
int argc;
|
||||
char ** argv;
|
||||
} thread_parms ;
|
||||
static void * squeezelite_runner_thread(){
|
||||
ESP_LOGI(TAG ,"Calling squeezelite");
|
||||
main(thread_parms.argc,thread_parms.argv);
|
||||
return NULL;
|
||||
}
|
||||
#define ADDITIONAL_SQUEEZELILTE_ARGS 5
|
||||
static void * squeezelite_thread(){
|
||||
int * exit_code;
|
||||
static bool isRunning=false;
|
||||
if(isRunning) {
|
||||
ESP_LOGE(TAG,"Squeezelite already running. Exiting!");
|
||||
return NULL;
|
||||
}
|
||||
isRunning=true;
|
||||
ESP_LOGI(TAG,"Waiting for WiFi.");
|
||||
while(!wait_for_wifi()){};
|
||||
ESP_LOGD(TAG ,"Number of args received: %u",thread_parms.argc );
|
||||
ESP_LOGV(TAG ,"Values:");
|
||||
for(int i = 0;i<thread_parms.argc; i++){
|
||||
ESP_LOGV(TAG ," %s",thread_parms.argv[i]);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG,"Starting Squeezelite runner Thread");
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "squeezelite-run";
|
||||
cfg.inherit_cfg = true;
|
||||
cfg.stack_size = SQUEEZELITE_THREAD_STACK_SIZE ;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&thread_squeezelite_runner, &attr, squeezelite_runner_thread,NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
// Wait for thread completion so we can free up memory.
|
||||
pthread_join(thread_squeezelite_runner,(void **)&exit_code);
|
||||
|
||||
ESP_LOGV(TAG ,"Exited from squeezelite's main(). Freeing argv structure.");
|
||||
for(int i=0;i<thread_parms.argc;i++){
|
||||
ESP_LOGV(TAG ,"Freeing char buffer for parameter %u", i+1);
|
||||
free(thread_parms.argv[i]);
|
||||
}
|
||||
ESP_LOGV(TAG ,"Freeing argv pointer");
|
||||
free(thread_parms.argv);
|
||||
isRunning=false;
|
||||
return NULL;
|
||||
}
|
||||
//static int launchsqueezelite_dft(int _argc, char **_argv){
|
||||
// nvs_handle nvs;
|
||||
// esp_err_t err;
|
||||
// optListStruct * curOpt=&optList[0];
|
||||
// ESP_LOGV(TAG ,"preparing to allocate memory ");
|
||||
// int argc =_argc+50; // todo: max number of parms?
|
||||
// char ** argv = malloc(sizeof(char**)*argc);
|
||||
// memset(argv,'\0',sizeof(char**)*argc);
|
||||
// int curOptNum=0;
|
||||
// argv[curOptNum++]=strdup(_argv[0]);
|
||||
// ESP_LOGV(TAG ,"nvs_open\n");
|
||||
// err = nvs_open(current_namespace, NVS_READONLY, &nvs);
|
||||
// if (err != ESP_OK) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// while(curOpt->optName!=NULL){
|
||||
// ESP_LOGV(TAG ,"Checking option %s with default value %s",curOpt->optName, curOpt->defaultValue);
|
||||
// if(!strcmp(curOpt->relatedcommand,"squeezelite"))
|
||||
// {
|
||||
// ESP_LOGV(TAG ,"option is for Squeezelite command, processing it");
|
||||
// // this is a squeezelite option
|
||||
// if(curOpt->cmdLinePrefix!=NULL){
|
||||
// ESP_LOGV(TAG ,"adding prefix %s",curOpt->cmdLinePrefix);
|
||||
// argv[curOptNum++]=strdup(curOpt->cmdLinePrefix);
|
||||
// }
|
||||
// size_t len;
|
||||
// if ( (nvs_get_str(nvs, curOpt->optName, NULL, &len)) == ESP_OK) {
|
||||
// char *str = (char *)malloc(len);
|
||||
// nvs_get_str(nvs, curOpt->optName, str, &len);
|
||||
// ESP_LOGV(TAG ,"assigning retrieved value %s",str);
|
||||
// argv[curOptNum++]=str;
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// curOpt++;
|
||||
// }
|
||||
// nvs_close(nvs);
|
||||
// ESP_LOGV(TAG ,"calling launchsqueezelite with parameters");
|
||||
// launchsqueezelite(argc, argv);
|
||||
// ESP_LOGV(TAG ,"back from calling launchsqueezelite");
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
static int launchsqueezelite(int argc, char **argv)
|
||||
{
|
||||
ESP_LOGV(TAG ,"Begin");
|
||||
|
||||
ESP_LOGV(TAG, "Parameters:");
|
||||
for(int i = 0;i<argc; i++){
|
||||
ESP_LOGV(TAG, " %s",argv[i]);
|
||||
}
|
||||
ESP_LOGV(TAG,"Saving args in thread structure");
|
||||
|
||||
thread_parms.argc=0;
|
||||
thread_parms.argv = malloc(sizeof(char**)*(argc+ADDITIONAL_SQUEEZELILTE_ARGS));
|
||||
memset(thread_parms.argv,'\0',sizeof(char**)*(argc+ADDITIONAL_SQUEEZELILTE_ARGS));
|
||||
|
||||
for(int i=0;i<argc;i++){
|
||||
ESP_LOGD(TAG ,"assigning parm %u : %s",i,argv[i]);
|
||||
thread_parms.argv[thread_parms.argc++]=strdup(argv[i]);
|
||||
}
|
||||
|
||||
if(argc==1){
|
||||
// There isn't a default configuration that would actually work
|
||||
// if no parameter is passed.
|
||||
ESP_LOGV(TAG ,"Adding argv value at %u. Prev value: %s",thread_parms.argc,thread_parms.argv[thread_parms.argc-1]);
|
||||
thread_parms.argv[thread_parms.argc++]=strdup("-?");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG,"Starting Squeezelite Thread");
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "squeezelite";
|
||||
cfg.inherit_cfg = true;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&thread_squeezelite, &attr, squeezelite_thread,NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
ESP_LOGD(TAG ,"Back to console thread!");
|
||||
return 0;
|
||||
}
|
||||
void register_squeezelite(){
|
||||
|
||||
squeezelite_args.parameters = arg_str0(NULL, NULL, "<parms>", "command line for squeezelite. -h for help, --defaults to launch with default values.");
|
||||
squeezelite_args.end = arg_end(1);
|
||||
const esp_console_cmd_t launch_squeezelite = {
|
||||
.command = "squeezelite",
|
||||
.help = "Starts squeezelite",
|
||||
.hint = NULL,
|
||||
.func = &launchsqueezelite,
|
||||
.argtable = &squeezelite_args
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&launch_squeezelite) );
|
||||
|
||||
}
|
||||
13
components/platform_esp32/cmd_squeezelite.h
Normal file
13
components/platform_esp32/cmd_squeezelite.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Register WiFi functions
|
||||
void register_squeezelite();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
185
components/platform_esp32/cmd_wifi.c
Normal file
185
components/platform_esp32/cmd_wifi.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/* Console example — WiFi commands
|
||||
|
||||
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 "cmd_wifi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmd_decl.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "tcpip_adapter.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
#define JOIN_TIMEOUT_MS (10000)
|
||||
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
static const char * TAG = "cmd_wifi";
|
||||
/** Arguments used by 'join' function */
|
||||
static struct {
|
||||
struct arg_int *timeout;
|
||||
struct arg_str *ssid;
|
||||
struct arg_str *password;
|
||||
struct arg_end *end;
|
||||
} join_args;
|
||||
|
||||
///** Arguments used by 'join' function */
|
||||
//static struct {
|
||||
// struct arg_int *autoconnect;
|
||||
// struct arg_end *end;
|
||||
//} auto_connect_args;
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
bool wait_for_wifi(){
|
||||
|
||||
bool connected=(xEventGroupGetBits(wifi_event_group) & CONNECTED_BIT)!=0;
|
||||
|
||||
if(!connected){
|
||||
ESP_LOGD(TAG,"Waiting for WiFi...");
|
||||
connected = (xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS)& CONNECTED_BIT)!=0;
|
||||
if(!connected){
|
||||
ESP_LOGD(TAG,"wifi timeout.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG,"WiFi Connected!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return connected;
|
||||
|
||||
}
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
tcpip_adapter_init();
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
{
|
||||
initialise_wifi();
|
||||
wifi_config_t wifi_config = { 0 };
|
||||
strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
|
||||
if (pass) {
|
||||
strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_connect() );
|
||||
|
||||
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
|
||||
return (bits & CONNECTED_BIT) != 0;
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
// return 1;
|
||||
// }
|
||||
// ESP_LOGI(__func__, "Connecting to '%s'",
|
||||
// join_args.ssid->sval[0]);
|
||||
//
|
||||
// /* set default value*/
|
||||
// if (join_args.timeout->count == 0) {
|
||||
// join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
|
||||
// }
|
||||
//
|
||||
// bool connected = wifi_join(join_args.ssid->sval[0],
|
||||
// join_args.password->sval[0],
|
||||
// join_args.timeout->ival[0]);
|
||||
// if (!connected) {
|
||||
// ESP_LOGW(__func__, "Connection timed out");
|
||||
// return 1;
|
||||
// }
|
||||
// ESP_LOGI(__func__, "Connected");
|
||||
return 0;
|
||||
}
|
||||
static int 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]);
|
||||
return 1;
|
||||
}
|
||||
ESP_LOGI(__func__, "Connecting to '%s'",
|
||||
join_args.ssid->sval[0]);
|
||||
|
||||
/* set default value*/
|
||||
if (join_args.timeout->count == 0) {
|
||||
join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
bool connected = wifi_join(join_args.ssid->sval[0],
|
||||
join_args.password->sval[0],
|
||||
join_args.timeout->ival[0]);
|
||||
if (!connected) {
|
||||
ESP_LOGW(__func__, "Connection timed out");
|
||||
return 1;
|
||||
}
|
||||
ESP_LOGI(__func__, "Connected");
|
||||
return 0;
|
||||
}
|
||||
void register_wifi_join()
|
||||
{
|
||||
join_args.timeout = arg_int0(NULL, "timeout", "<t>", "Connection timeout, ms");
|
||||
join_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
|
||||
join_args.password = arg_str0(NULL, NULL, "<pass>", "PSK of AP");
|
||||
join_args.end = arg_end(2);
|
||||
|
||||
const esp_console_cmd_t join_cmd = {
|
||||
.command = "join",
|
||||
.help = "Join WiFi AP as a station",
|
||||
.hint = NULL,
|
||||
.func = &connect,
|
||||
.argtable = &join_args
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&join_cmd) );
|
||||
}
|
||||
|
||||
void register_wifi()
|
||||
{
|
||||
register_wifi_join();
|
||||
initialise_wifi();
|
||||
}
|
||||
|
||||
21
components/platform_esp32/cmd_wifi.h
Normal file
21
components/platform_esp32/cmd_wifi.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Console example — declarations of command registration functions.
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Register WiFi functions
|
||||
void register_wifi();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
10
components/platform_esp32/component.mk
Normal file
10
components/platform_esp32/component.mk
Normal file
@@ -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.
|
||||
#
|
||||
CFLAGS += -Os -DPOSIX -DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4
|
||||
CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG
|
||||
316
components/platform_esp32/console.c
Normal file
316
components/platform_esp32/console.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/* Console example
|
||||
|
||||
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 <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "pthread.h"
|
||||
#include "platform_esp32.h"
|
||||
#include "cmd_decl.h"
|
||||
#include "console.h"
|
||||
|
||||
#include "cmd_squeezelite.h"
|
||||
#include "nvs_utilities.h"
|
||||
pthread_t thread_console;
|
||||
static void * console_thread();
|
||||
void console_start();
|
||||
static const char * TAG = "console";
|
||||
extern char current_namespace[];
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char* prompt = LOG_COLOR_I "squeezelite-esp32> " LOG_RESET_COLOR;
|
||||
|
||||
/* Console command history can be stored to and loaded from a file.
|
||||
* The easiest way to do this is to use FATFS filesystem on top of
|
||||
* wear_levelling library.
|
||||
*/
|
||||
|
||||
#define MOUNT_PATH "/data"
|
||||
#define HISTORY_PATH MOUNT_PATH "/history.txt"
|
||||
void run_command(char * line);
|
||||
//optListStruct * getOptionByName(char * option){
|
||||
// optListStruct * curOpt=&optList[0];
|
||||
// while(curOpt->optName !=NULL){
|
||||
// if(!strcmp(curOpt->optName, option)){
|
||||
// return curOpt;
|
||||
// }
|
||||
// curOpt++;
|
||||
// }
|
||||
// return NULL;
|
||||
//}
|
||||
//
|
||||
//static int list_options(int argc, char **argv)
|
||||
//{
|
||||
// nvs_handle nvs;
|
||||
// esp_err_t err;
|
||||
//
|
||||
// err = nvs_open(current_namespace, NVS_READONLY, &nvs);
|
||||
// if (err != ESP_OK) {
|
||||
// return err;
|
||||
// }
|
||||
// //
|
||||
// optListStruct * curOpt=&optList[0];
|
||||
// printf("System Configuration Options.\n");
|
||||
// while(curOpt->optName!=NULL){
|
||||
// printf("Option: %s\n"
|
||||
// " Description: %20s\n"
|
||||
// " Default Value: %20s\n"
|
||||
// " Current Value: ",curOpt->optName, curOpt->description, curOpt->defaultValue);
|
||||
// size_t len;
|
||||
// if ( (nvs_get_str(nvs, curOpt->optName, NULL, &len)) == ESP_OK) {
|
||||
// char *str = (char *)malloc(len);
|
||||
// if ( (nvs_get_str(nvs, curOpt->optName, str, &len)) == ESP_OK) {
|
||||
// printf("%20s\n", str);
|
||||
// }
|
||||
// free(str);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if(store_nvs_value(NVS_TYPE_STR, curOpt->optName,curOpt->defaultValue, strlen(curOpt->defaultValue))==ESP_OK)
|
||||
// {
|
||||
// printf("%20s\n", curOpt->defaultValue);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// printf("Error. Invalid key\n");
|
||||
// }
|
||||
// }
|
||||
// curOpt++;
|
||||
// }
|
||||
// printf("\n");
|
||||
// nvs_close(nvs);
|
||||
// return 0;
|
||||
//}
|
||||
//void register_list_options(){
|
||||
// const esp_console_cmd_t config_list = {
|
||||
// .command = "config-list",
|
||||
// .help = "Lists available configuration options.",
|
||||
// .hint = NULL,
|
||||
// .func = &list_options,
|
||||
// .argtable = NULL
|
||||
// };
|
||||
//
|
||||
// ESP_ERROR_CHECK( esp_console_cmd_register(&config_list) );
|
||||
//
|
||||
//}
|
||||
void process_autoexec(){
|
||||
int i=1;
|
||||
char autoexec_name[21]={0};
|
||||
char * autoexec_value=NULL;
|
||||
int * autoexec_flag = get_nvs_value_alloc(NVS_TYPE_U8, "autoexec");
|
||||
if(autoexec_flag!=NULL)
|
||||
{
|
||||
ESP_LOGI(TAG,"autoexec flag value found with value %d", *autoexec_flag);
|
||||
printf("printf -- autoexec flag value found with value %d", *autoexec_flag);
|
||||
if(*autoexec_flag == 1)
|
||||
{
|
||||
do {
|
||||
snprintf(autoexec_name,sizeof(autoexec_name)-1,"autoexec%u",i++);
|
||||
ESP_LOGD(TAG,"Getting command name %s", autoexec_name);
|
||||
autoexec_value= get_nvs_value_alloc(NVS_TYPE_STR, autoexec_name);
|
||||
if(autoexec_value!=NULL){
|
||||
ESP_LOGI(TAG,"Running command %s = %s", autoexec_name, autoexec_value);
|
||||
run_command(autoexec_value);
|
||||
free(autoexec_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG,"No matching command found for name %s", autoexec_name);
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
free(autoexec_flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG,"No matching command found for name autoexec. Adding default entries");
|
||||
uint8_t autoexec_dft=0;
|
||||
char autoexec1_dft[]="join " CONFIG_WIFI_SSID CONFIG_WIFI_PASSWORD;
|
||||
char autoexec2_dft[]="squeezelite -o \"DAC\" -b 500:2000 -d all=debug -M esp32 -r \"44100,4800\" -N \"playername.txt\"";
|
||||
store_nvs_value(NVS_TYPE_U8,"autoexec",&autoexec_dft);
|
||||
store_nvs_value(NVS_TYPE_U8,"autoexec1",autoexec1_dft);
|
||||
store_nvs_value(NVS_TYPE_U8,"autoexec2",autoexec2_dft);
|
||||
}
|
||||
}
|
||||
static void initialize_filesystem() {
|
||||
static wl_handle_t wl_handle;
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 10,
|
||||
.format_if_mount_failed = true,
|
||||
.allocation_unit_size = 4096
|
||||
};
|
||||
esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage",
|
||||
&mount_config, &wl_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_nvs() {
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
void initialize_console() {
|
||||
|
||||
/* Disable buffering on stdin */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
|
||||
* correct while APB frequency is changing in light sleep mode.
|
||||
*/
|
||||
const uart_config_t uart_config = { .baud_rate =
|
||||
CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1,
|
||||
.use_ref_tick = true };
|
||||
ESP_ERROR_CHECK(uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config));
|
||||
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK(
|
||||
uart_driver_install(CONFIG_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
|
||||
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
|
||||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = { .max_cmdline_args = 8,
|
||||
.max_cmdline_length = 256,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_init(&console_config));
|
||||
|
||||
/* Configure linenoise line completion library */
|
||||
/* Enable multiline editing. If not set, long commands will scroll within
|
||||
* single line.
|
||||
*/
|
||||
linenoiseSetMultiLine(1);
|
||||
|
||||
/* Tell linenoise where to get command completions and hints */
|
||||
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
||||
linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
|
||||
|
||||
/* Set command history size */
|
||||
linenoiseHistorySetMaxLen(100);
|
||||
|
||||
/* Load command history from filesystem */
|
||||
linenoiseHistoryLoad(HISTORY_PATH);
|
||||
}
|
||||
|
||||
void console_start() {
|
||||
initialize_nvs();
|
||||
initialize_filesystem();
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_system();
|
||||
register_wifi();
|
||||
register_nvs();
|
||||
register_squeezelite();
|
||||
printf("\n"
|
||||
"Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||
"Press TAB when typing command name to auto-complete.\n"
|
||||
"\n"
|
||||
"To automatically execute lines at startup:\n"
|
||||
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
|
||||
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n"
|
||||
"\n"
|
||||
"\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n****************************\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n"
|
||||
"****************************\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
prompt = "squeezelite-esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
|
||||
}
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name= "console";
|
||||
cfg.inherit_cfg = true;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&thread_console, &attr, console_thread, NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
void run_command(char * line){
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_ERR_INVALID_ARG) {
|
||||
// command was empty
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("Command returned non-zero error code: 0x%x (%s)\n", ret,
|
||||
esp_err_to_name(err));
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: %s\n", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
static void * console_thread() {
|
||||
process_autoexec();
|
||||
/* Main loop */
|
||||
while (1) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char* line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
|
||||
/* Save command history to filesystem */
|
||||
linenoiseHistorySave(HISTORY_PATH);
|
||||
printf("\n");
|
||||
run_command(line);
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
18
components/platform_esp32/console.h
Normal file
18
components/platform_esp32/console.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Console example — declarations of command registration functions.
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
147
components/platform_esp32/esp_app_main.c
Normal file
147
components/platform_esp32/esp_app_main.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/* Scan Example
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
This example shows how to use the All Channel Scan or Fast Scan to connect
|
||||
to a Wi-Fi network.
|
||||
|
||||
In the Fast Scan mode, the scan will stop as soon as the first network matching
|
||||
the SSID is found. In this mode, an application can set threshold for the
|
||||
authentication mode and the Signal strength. Networks that do not meet the
|
||||
threshold requirements will be ignored.
|
||||
|
||||
In the All Channel Scan mode, the scan will end only after all the channels
|
||||
are scanned, and connection will start with the best network. The networks
|
||||
can be sorted based on Authentication Mode or Signal Strength. The priority
|
||||
for the Authentication mode is: WPA2 > WPA > WEP > Open
|
||||
*/
|
||||
#include "platform_esp32.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include "esp_avrc_api.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_utilities.h"
|
||||
#include "pthread.h"
|
||||
#include "string.h"
|
||||
#include "sys/socket.h"
|
||||
#include <signal.h>
|
||||
#include "esp_system.h"
|
||||
#include <signal.h>
|
||||
|
||||
/*Set the SSID and Password via "make menuconfig"*/
|
||||
#define DEFAULT_SSID CONFIG_WIFI_SSID
|
||||
#define DEFAULT_PWD CONFIG_WIFI_PASSWORD
|
||||
|
||||
#if CONFIG_WIFI_ALL_CHANNEL_SCAN
|
||||
#define DEFAULT_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
|
||||
#elif CONFIG_WIFI_FAST_SCAN
|
||||
#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
|
||||
#else
|
||||
#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
|
||||
#endif /*CONFIG_SCAN_METHOD*/
|
||||
|
||||
#if CONFIG_WIFI_CONNECT_AP_BY_SIGNAL
|
||||
#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
|
||||
#elif CONFIG_WIFI_CONNECT_AP_BY_SECURITY
|
||||
#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY
|
||||
#else
|
||||
#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
|
||||
#endif /*CONFIG_SORT_METHOD*/
|
||||
|
||||
#if CONFIG_FAST_SCAN_THRESHOLD
|
||||
#define DEFAULT_RSSI CONFIG_FAST_SCAN_MINIMUM_SIGNAL
|
||||
#if CONFIG_EXAMPLE_OPEN
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
|
||||
#elif CONFIG_EXAMPLE_WEP
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_WEP
|
||||
#elif CONFIG_EXAMPLE_WPA
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_WPA_PSK
|
||||
#elif CONFIG_EXAMPLE_WPA2
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_WPA2_PSK
|
||||
#else
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
|
||||
#endif
|
||||
#else
|
||||
#define DEFAULT_RSSI -127
|
||||
#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
|
||||
#endif /*CONFIG_FAST_SCAN_THRESHOLD*/
|
||||
extern char current_namespace[];
|
||||
static const char * TAG = "platform_esp32";
|
||||
|
||||
|
||||
|
||||
//static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
// int32_t event_id, void* event_data)
|
||||
//{
|
||||
// if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
// esp_wifi_connect();
|
||||
// } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
// esp_wifi_connect();
|
||||
// } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
// ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
// ESP_LOGI(TAG, "got ip: %s.", ip4addr_ntoa(&event->ip_info.ip));
|
||||
// ESP_LOGD(TAG,"Signaling wifi connected. Locking.\n");
|
||||
// pthread_mutex_lock(&wifi_connect_suspend_mutex);
|
||||
// ESP_LOGD(TAG,"Signaling wifi connected. Broadcasting.\n");
|
||||
// pthread_cond_broadcast(&wifi_connect_suspend_cond);
|
||||
// ESP_LOGD(TAG,"Signaling wifi connected. Unlocking.\n");
|
||||
// pthread_mutex_unlock(&wifi_connect_suspend_mutex);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
///* Initialize Wi-Fi as sta and set scan method */
|
||||
//static void wifi_scan(void)
|
||||
//{
|
||||
//
|
||||
// tcpip_adapter_init();
|
||||
// ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
//
|
||||
// wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
// ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
//
|
||||
// ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
// ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
|
||||
//
|
||||
// wifi_config_t wifi_config = {
|
||||
// .sta = {
|
||||
// .ssid = DEFAULT_SSID,
|
||||
// .password = DEFAULT_PWD,
|
||||
// .scan_method = DEFAULT_SCAN_METHOD,
|
||||
// .sort_method = DEFAULT_SORT_METHOD,
|
||||
// .threshold.rssi = DEFAULT_RSSI,
|
||||
// .threshold.authmode = DEFAULT_AUTHMODE,
|
||||
// },
|
||||
// };
|
||||
// ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
// ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||
// ESP_ERROR_CHECK(esp_wifi_start());
|
||||
//}
|
||||
|
||||
|
||||
void app_main()
|
||||
{
|
||||
|
||||
console_start();
|
||||
}
|
||||
179
components/platform_esp32/nvs_utilities.c
Normal file
179
components/platform_esp32/nvs_utilities.c
Normal file
@@ -0,0 +1,179 @@
|
||||
#include "nvs_utilities.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "cmd_decl.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
extern char current_namespace[];
|
||||
static const char * TAG = "platform_esp32";
|
||||
|
||||
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data) {
|
||||
if (type == NVS_TYPE_BLOB)
|
||||
return ESP_ERR_NVS_TYPE_MISMATCH;
|
||||
return store_nvs_value_len(type, key, data,0);
|
||||
}
|
||||
esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data,
|
||||
size_t data_len) {
|
||||
esp_err_t err;
|
||||
nvs_handle nvs;
|
||||
|
||||
if (type == NVS_TYPE_ANY) {
|
||||
return ESP_ERR_NVS_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (type == NVS_TYPE_I8) {
|
||||
err = nvs_set_i8(nvs, key, *(int8_t *) data);
|
||||
} else if (type == NVS_TYPE_U8) {
|
||||
err = nvs_set_u8(nvs, key, *(uint8_t *) data);
|
||||
} else if (type == NVS_TYPE_I16) {
|
||||
err = nvs_set_i16(nvs, key, *(int16_t *) data);
|
||||
} else if (type == NVS_TYPE_U16) {
|
||||
err = nvs_set_u16(nvs, key, *(uint16_t *) data);
|
||||
} else if (type == NVS_TYPE_I32) {
|
||||
err = nvs_set_i32(nvs, key, *(int32_t *) data);
|
||||
} else if (type == NVS_TYPE_U32) {
|
||||
err = nvs_set_u32(nvs, key, *(uint32_t *) data);
|
||||
} else if (type == NVS_TYPE_I64) {
|
||||
err = nvs_set_i64(nvs, key, *(int64_t *) data);
|
||||
} else if (type == NVS_TYPE_U64) {
|
||||
err = nvs_set_u64(nvs, key, *(uint64_t *) data);
|
||||
} else if (type == NVS_TYPE_STR) {
|
||||
err = nvs_set_str(nvs, key, data);
|
||||
} else if (type == NVS_TYPE_BLOB) {
|
||||
err = nvs_set_blob(nvs, key, (void *) data, data_len);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_commit(nvs);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Value stored under key '%s'", key);
|
||||
}
|
||||
}
|
||||
nvs_close(nvs);
|
||||
return err;
|
||||
}
|
||||
void * get_nvs_value_alloc(nvs_type_t type, const char *key) {
|
||||
nvs_handle nvs;
|
||||
esp_err_t err;
|
||||
void * value=NULL;
|
||||
|
||||
err = nvs_open(current_namespace, NVS_READONLY, &nvs);
|
||||
if (err != ESP_OK) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (type == NVS_TYPE_I8) {
|
||||
value=malloc(sizeof(int8_t));
|
||||
err = nvs_get_i8(nvs, key, (int8_t *) value);
|
||||
printf("value found = %d\n",*(int8_t *)value);
|
||||
} else if (type == NVS_TYPE_U8) {
|
||||
value=malloc(sizeof(uint8_t));
|
||||
err = nvs_get_u8(nvs, key, (uint8_t *) value);
|
||||
printf("value found = %u\n",*(uint8_t *)value);
|
||||
} else if (type == NVS_TYPE_I16) {
|
||||
value=malloc(sizeof(int16_t));
|
||||
err = nvs_get_i16(nvs, key, (int16_t *) value);
|
||||
printf("value found = %d\n",*(int16_t *)value);
|
||||
} else if (type == NVS_TYPE_U16) {
|
||||
value=malloc(sizeof(uint16_t));
|
||||
err = nvs_get_u16(nvs, key, (uint16_t *) value);
|
||||
printf("value found = %u\n",*(uint16_t *)value);
|
||||
} else if (type == NVS_TYPE_I32) {
|
||||
value=malloc(sizeof(int32_t));
|
||||
err = nvs_get_i32(nvs, key, (int32_t *) value);
|
||||
} else if (type == NVS_TYPE_U32) {
|
||||
value=malloc(sizeof(uint32_t));
|
||||
err = nvs_get_u32(nvs, key, (uint32_t *) value);
|
||||
} else if (type == NVS_TYPE_I64) {
|
||||
value=malloc(sizeof(int64_t));
|
||||
err = nvs_get_i64(nvs, key, (int64_t *) value);
|
||||
} else if (type == NVS_TYPE_U64) {
|
||||
value=malloc(sizeof(uint64_t));
|
||||
err = nvs_get_u64(nvs, key, (uint64_t *) value);
|
||||
} else if (type == NVS_TYPE_STR) {
|
||||
size_t len;
|
||||
if ((err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
|
||||
value=malloc(sizeof(len+1));
|
||||
err = nvs_get_str(nvs, key, value, &len);
|
||||
}
|
||||
} else if (type == NVS_TYPE_BLOB) {
|
||||
size_t len;
|
||||
if ((err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
|
||||
value=malloc(sizeof(len+1));
|
||||
err = nvs_get_blob(nvs, key, value, &len);
|
||||
}
|
||||
}
|
||||
if(err!=ESP_OK){
|
||||
free(value);
|
||||
value=NULL;
|
||||
}
|
||||
nvs_close(nvs);
|
||||
return value;
|
||||
}
|
||||
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size) {
|
||||
nvs_handle nvs;
|
||||
esp_err_t err;
|
||||
|
||||
err = nvs_open(current_namespace, NVS_READONLY, &nvs);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (type == NVS_TYPE_I8) {
|
||||
err = nvs_get_i8(nvs, key, (int8_t *) value);
|
||||
} else if (type == NVS_TYPE_U8) {
|
||||
err = nvs_get_u8(nvs, key, (uint8_t *) value);
|
||||
} else if (type == NVS_TYPE_I16) {
|
||||
err = nvs_get_i16(nvs, key, (int16_t *) value);
|
||||
} else if (type == NVS_TYPE_U16) {
|
||||
err = nvs_get_u16(nvs, key, (uint16_t *) value);
|
||||
} else if (type == NVS_TYPE_I32) {
|
||||
err = nvs_get_i32(nvs, key, (int32_t *) value);
|
||||
} else if (type == NVS_TYPE_U32) {
|
||||
err = nvs_get_u32(nvs, key, (uint32_t *) value);
|
||||
} else if (type == NVS_TYPE_I64) {
|
||||
err = nvs_get_i64(nvs, key, (int64_t *) value);
|
||||
} else if (type == NVS_TYPE_U64) {
|
||||
err = nvs_get_u64(nvs, key, (uint64_t *) value);
|
||||
} else if (type == NVS_TYPE_STR) {
|
||||
size_t len;
|
||||
if ((err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
|
||||
if (len > buf_size) {
|
||||
//ESP_LOGE("Error reading value for %s. Buffer size: %d, Value Length: %d", key, buf_size, len);
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
err = nvs_get_str(nvs, key, value, &len);
|
||||
}
|
||||
}
|
||||
} else if (type == NVS_TYPE_BLOB) {
|
||||
size_t len;
|
||||
if ((err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
|
||||
|
||||
if (len > buf_size) {
|
||||
//ESP_LOGE("Error reading value for %s. Buffer size: %d, Value Length: %d",
|
||||
// key, buf_size, len);
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
err = nvs_get_blob(nvs, key, value, &len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvs_close(nvs);
|
||||
return err;
|
||||
}
|
||||
|
||||
13
components/platform_esp32/nvs_utilities.h
Normal file
13
components/platform_esp32/nvs_utilities.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "esp_err.h"
|
||||
#include "nvs.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, size_t data_len);
|
||||
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data);
|
||||
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size);
|
||||
void * get_nvs_value_alloc(nvs_type_t type, const char *key);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
68
components/platform_esp32/perf_trace.h
Normal file
68
components/platform_esp32/perf_trace.h
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#pragma once
|
||||
#include "time.h"
|
||||
#include "sys/time.h"
|
||||
#include "esp_system.h"
|
||||
#define PERF_MAX LONG_MAX
|
||||
#define MIN_MAX_VAL(x) x==PERF_MAX?0:x
|
||||
#define CURR_SAMPLE_RATE output.current_sample_rate>0?output.current_sample_rate:1
|
||||
#define FRAMES_TO_MS(f) (uint32_t)f*(uint32_t)1000/(uint32_t)(CURR_SAMPLE_RATE)
|
||||
#ifdef BYTES_TO_FRAME
|
||||
#define BYTES_TO_MS(b) FRAMES_TO_MS(BYTES_TO_FRAME(b))
|
||||
#else
|
||||
#define BYTES_TO_MS(b) FRAMES_TO_MS(b/BYTES_PER_FRAME)
|
||||
#endif
|
||||
#define SET_MIN_MAX(val,var) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var; count_##var++; avgtot_##var+= var
|
||||
#define SET_MIN_MAX_SIZED(val,var,siz) var=val; if(var<min_##var) min_##var=var; if(var>max_##var) max_##var=var; count_##var++; avgtot_##var+= var;size_##var=siz
|
||||
#define RESET_MIN_MAX(var) min_##var=PERF_MAX; max_##var=0; avgtot_##var=0;count_##var=0;var=0;size_##var=0
|
||||
#define RESET_MIN_MAX_DURATION(var) min_##var=PERF_MAX; max_##var=0; avgtot_##var=0;count_##var=0;var=0
|
||||
#define DECLARE_MIN_MAX(var) static uint32_t min_##var = PERF_MAX, max_##var = 0, size_##var = 0,avgtot_##var = 0, count_##var=0; uint32_t var=0
|
||||
#define DECLARE_MIN_MAX_DURATION(var) static uint32_t min_##var = PERF_MAX, max_##var = 0, avgtot_##var = 0, count_##var=0; uint32_t var=0
|
||||
#define LINE_MIN_MAX_AVG(var) (count_##var>0?avgtot_##var/count_##var:0)
|
||||
|
||||
#define LINE_MIN_MAX_FORMAT_HEAD1 " +----------+----------+----------------+-----+----------------+"
|
||||
#define LINE_MIN_MAX_FORMAT_HEAD2 " | max | min | average | | count |"
|
||||
#define LINE_MIN_MAX_FORMAT_HEAD3 " | (bytes) | (bytes) | (bytes) | | |"
|
||||
#define LINE_MIN_MAX_FORMAT_HEAD4 " +----------+----------+----------------+-----+----------------+"
|
||||
#define LINE_MIN_MAX_FORMAT_FOOTER " +----------+----------+----------------+-----+----------------+"
|
||||
#define LINE_MIN_MAX_FORMAT "%14s|%10u|%10u|%16u|%5u|%16u|"
|
||||
#define LINE_MIN_MAX(name,var) name,\
|
||||
MIN_MAX_VAL(max_##var),\
|
||||
MIN_MAX_VAL(min_##var),\
|
||||
LINE_MIN_MAX_AVG(var),\
|
||||
size_##var!=0?100*LINE_MIN_MAX_AVG(var)/size_##var:0,\
|
||||
count_##var
|
||||
|
||||
#define LINE_MIN_MAX_FORMAT_STREAM "%14s|%10u|%10u|%16u|%5u|%16u|"
|
||||
#define LINE_MIN_MAX_STREAM(name,var) name,\
|
||||
MIN_MAX_VAL(max_##var),\
|
||||
MIN_MAX_VAL(min_##var),\
|
||||
LINE_MIN_MAX_AVG(var),\
|
||||
size_##var!=0?100*LINE_MIN_MAX_AVG(var)/size_##var:0,\
|
||||
count_##var
|
||||
#define LINE_MIN_MAX_DURATION_FORMAT "%14s%10u|%10u|%11u|%11u|"
|
||||
#define LINE_MIN_MAX_DURATION(name,var) name,MIN_MAX_VAL(max_##var),MIN_MAX_VAL(min_##var), LINE_MIN_MAX_AVG(var), count_##var
|
||||
|
||||
|
||||
#define TIME_MEASUREMENT_START(x) x=esp_timer_get_time()
|
||||
#define TIME_MEASUREMENT_GET(x) (esp_timer_get_time()-x)
|
||||
|
||||
#define TIMED_SECTION_START_MS_FORCE(x,force) if(hasTimeElapsed(x,force)) {
|
||||
#define TIMED_SECTION_START_MS(x) if(hasTimeElapsed(x,false)){
|
||||
#define TIMED_SECTION_START_FORCE(x,force) TIMED_SECTION_START_MS(x * 1000UL,force)
|
||||
#define TIMED_SECTION_START(x) TIMED_SECTION_START_MS(x * 1000UL)
|
||||
#define TIMED_SECTION_END }
|
||||
static inline bool hasTimeElapsed(time_t delayMS, bool bforce)
|
||||
{
|
||||
static time_t lastTime=0;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if (lastTime <= tv.tv_sec * 1000 + tv.tv_usec / 1000 ||bforce)
|
||||
{
|
||||
lastTime = tv.tv_sec * 1000 + tv.tv_usec / 1000 + delayMS;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
954
components/platform_esp32/platform_esp32.c
Normal file
954
components/platform_esp32/platform_esp32.c
Normal file
@@ -0,0 +1,954 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_a2dp_api.h"
|
||||
#include "esp_avrc_api.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_utilities.h"
|
||||
#include "pthread.h"
|
||||
#include "string.h"
|
||||
//#include "esp_event.h"
|
||||
#include "sys/socket.h"
|
||||
#include <signal.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include "platform_esp32.h"
|
||||
#include "../../main/squeezelite.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#define STATS_REPORT_DELAY_MS 15000
|
||||
static const char * TAG = "platform_esp32";
|
||||
extern char * get_output_state_desc(output_state state);
|
||||
|
||||
extern struct outputstate output;
|
||||
extern struct buffer *outputbuf;
|
||||
extern struct buffer *streambuf;
|
||||
extern uint8_t * btout;
|
||||
time_t disconnect_time=0;
|
||||
#define LOCK_S pthread_mutex_lock(&(streambuf->mutex))
|
||||
#define UNLOCK_S pthread_mutex_unlock(&(streambuf->mutex))
|
||||
|
||||
#define LOCK pthread_mutex_lock(&(outputbuf->mutex))
|
||||
#define UNLOCK pthread_mutex_unlock(&(outputbuf->mutex))
|
||||
int64_t connecting_timeout = 0;
|
||||
static const char * art_a2dp_connected[]={"\n",
|
||||
" ___ _____ _____ _____ _ _ _ ",
|
||||
" /\\ |__ \\| __ \\| __ \\ / ____| | | | | |",
|
||||
" / \\ ) | | | | |__) | | | ___ _ __ _ __ ___ ___| |_ ___ __| | |",
|
||||
" / /\\ \\ / /| | | | ___/ | | / _ \\| '_ \\| '_ \\ / _ \\/ __| __/ _ \\/ _` | |",
|
||||
" / ____ \\ / /_| |__| | | | |___| (_) | | | | | | | __/ (__| || __/ (_| |_|",
|
||||
" /_/ \\_\\____|_____/|_| \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__\\___|\\__,_(_)\n",
|
||||
"\0"};
|
||||
static const char * art_a2dp_connecting[]= {"\n",
|
||||
" ___ _____ _____ _____ _ _ ",
|
||||
" /\\ |__ \\| __ \\| __ \\ / ____| | | (_) ",
|
||||
" / \\ ) | | | | |__) | | | ___ _ __ _ __ ___ ___| |_ _ _ __ __ _ ",
|
||||
" / /\\ \\ / /| | | | ___/ | | / _ \\| '_ \\| '_ \\ / _ \\/ __| __| | '_ \\ / _` | ",
|
||||
" / ____ \\ / /_| |__| | | | |___| (_) | | | | | | | __/ (__| |_| | | | | (_| |_ _ _ ",
|
||||
" /_/ \\_\\____|_____/|_| \\_____\\___/|_| |_|_| |_|\\___|\\___|\\__|_|_| |_|\\__, (_|_|_)",
|
||||
" __/ | ",
|
||||
" |___/ \n",
|
||||
"\0"};
|
||||
|
||||
static void bt_app_av_state_connecting(uint16_t event, void *param);
|
||||
|
||||
|
||||
#define A2DP_TIMER_INIT connecting_timeout = esp_timer_get_time() +(CONFIG_A2DP_CONNECT_TIMEOUT_MS * 1000)
|
||||
#define IS_A2DP_TIMER_OVER esp_timer_get_time() >= connecting_timeout
|
||||
|
||||
#define FRAME_TO_BYTES(f) f*BYTES_PER_FRAME
|
||||
#define BYTES_TO_FRAME(b) b/BYTES_PER_FRAME
|
||||
|
||||
|
||||
#define RESET_ALL_MIN_MAX RESET_MIN_MAX(req); RESET_MIN_MAX(rec); RESET_MIN_MAX(bt);RESET_MIN_MAX(under); RESET_MIN_MAX_DURATION(stream_buf); RESET_MIN_MAX_DURATION(lock_out_time)
|
||||
|
||||
DECLARE_MIN_MAX(stream_buf);
|
||||
DECLARE_MIN_MAX(req);
|
||||
DECLARE_MIN_MAX(rec);
|
||||
DECLARE_MIN_MAX(bt);
|
||||
DECLARE_MIN_MAX(under);
|
||||
DECLARE_MIN_MAX_DURATION(lock_out_time);
|
||||
|
||||
static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param);
|
||||
|
||||
void get_mac(u8_t mac[]) {
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
}
|
||||
|
||||
_sig_func_ptr signal(int sig, _sig_func_ptr func) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *audio_calloc(size_t nmemb, size_t size) {
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
|
||||
/* event for handler "bt_av_hdl_stack_up */
|
||||
enum {
|
||||
BT_APP_EVT_STACK_UP = 0,
|
||||
};
|
||||
|
||||
/* A2DP global state */
|
||||
enum {
|
||||
APP_AV_STATE_IDLE,
|
||||
APP_AV_STATE_DISCOVERING,
|
||||
APP_AV_STATE_DISCOVERED,
|
||||
APP_AV_STATE_UNCONNECTED,
|
||||
APP_AV_STATE_CONNECTING,
|
||||
APP_AV_STATE_CONNECTED,
|
||||
APP_AV_STATE_DISCONNECTING,
|
||||
};
|
||||
|
||||
char * APP_AV_STATE_DESC[] = {
|
||||
"APP_AV_STATE_IDLE",
|
||||
"APP_AV_STATE_DISCOVERING",
|
||||
"APP_AV_STATE_DISCOVERED",
|
||||
"APP_AV_STATE_UNCONNECTED",
|
||||
"APP_AV_STATE_CONNECTING",
|
||||
"APP_AV_STATE_CONNECTED",
|
||||
"APP_AV_STATE_DISCONNECTING"
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* sub states of APP_AV_STATE_CONNECTED */
|
||||
|
||||
enum {
|
||||
APP_AV_MEDIA_STATE_IDLE,
|
||||
APP_AV_MEDIA_STATE_STARTING,
|
||||
APP_AV_MEDIA_STATE_BUFFERING,
|
||||
APP_AV_MEDIA_STATE_STARTED,
|
||||
APP_AV_MEDIA_STATE_STOPPING,
|
||||
APP_AV_MEDIA_STATE_WAIT_DISCONNECT
|
||||
};
|
||||
|
||||
#define BT_APP_HEART_BEAT_EVT (0xff00)
|
||||
|
||||
/// handler for bluetooth stack enabled events
|
||||
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
|
||||
|
||||
/// callback function for A2DP source
|
||||
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
|
||||
|
||||
/// callback function for A2DP source audio data stream
|
||||
static void a2d_app_heart_beat(void *arg);
|
||||
|
||||
/// A2DP application state machine
|
||||
static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
||||
|
||||
/* A2DP application state machine handler for each state */
|
||||
static void bt_app_av_state_unconnected(uint16_t event, void *param);
|
||||
static void bt_app_av_state_connecting(uint16_t event, void *param);
|
||||
static void bt_app_av_state_connected(uint16_t event, void *param);
|
||||
static void bt_app_av_state_disconnecting(uint16_t event, void *param);
|
||||
|
||||
static esp_bd_addr_t s_peer_bda = {0};
|
||||
static uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
static int s_a2d_state = APP_AV_STATE_IDLE;
|
||||
static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
static uint32_t s_pkt_cnt = 0;
|
||||
|
||||
static TimerHandle_t s_tmr;
|
||||
|
||||
static struct {
|
||||
struct arg_str *sink_name;
|
||||
struct arg_int *control_delay;
|
||||
struct arg_int *connect_timeout_delay;
|
||||
struct arg_end *end;
|
||||
} squeezelite_args;
|
||||
|
||||
void hal_bluetooth_init(const char * options)
|
||||
{
|
||||
ESP_LOGD(TAG,"Initializing Bluetooth HAL");
|
||||
//CONFIG_A2DP_SINK_NAME
|
||||
//CONFIG_A2DP_CONTROL_DELAY_MS
|
||||
//CONFIG_A2DP_CONNECT_TIMEOUT_MS
|
||||
|
||||
squeezelite_args.sink_name = arg_str1("n", "name", "<sink name>", "the name of the bluetooth to connect to");
|
||||
squeezelite_args.control_delay = arg_int0("d", "delay", "<control delay>", "the delay between each pass at the A2DP control loop");
|
||||
squeezelite_args.connect_timeout_delay = arg_int0("t","timeout", "<timeout>", "the timeout duration for connecting to the A2DP sink");
|
||||
squeezelite_args.end = arg_end(2);
|
||||
|
||||
|
||||
ESP_LOGD(TAG,"Copying parameters");
|
||||
char * opts = strdup(options);
|
||||
char **argv = malloc(sizeof(char**)*15);
|
||||
|
||||
size_t argv_size=15;
|
||||
|
||||
// change parms so ' appear as " for parsing the options
|
||||
for (char* p = opts; (p = strchr(p, '\'')); ++p) *p = '"';
|
||||
ESP_LOGD(TAG,"Splitting arg line: %s", opts);
|
||||
|
||||
argv_size = esp_console_split_argv(opts, argv, argv_size);
|
||||
ESP_LOGD(TAG,"Parsing parameters");
|
||||
int nerrors = arg_parse(argv_size , argv, (void **) &squeezelite_args);
|
||||
if (nerrors != 0) {
|
||||
ESP_LOGD(TAG,"Parsing Errors");
|
||||
arg_print_errors(stdout, squeezelite_args.end, "BT");
|
||||
arg_print_glossary_gnu(stdout, (void **) &squeezelite_args);
|
||||
free(opts);
|
||||
free(argv);
|
||||
return;
|
||||
}
|
||||
if(squeezelite_args.sink_name->count == 0)
|
||||
{
|
||||
ESP_LOGD(TAG,"Using default sink name : %s",CONFIG_A2DP_SINK_NAME);
|
||||
squeezelite_args.sink_name->sval[0] = CONFIG_A2DP_SINK_NAME;
|
||||
}
|
||||
if(squeezelite_args.connect_timeout_delay->count == 0)
|
||||
{
|
||||
ESP_LOGD(TAG,"Using default connect timeout");
|
||||
squeezelite_args.connect_timeout_delay->ival[0]=CONFIG_A2DP_CONNECT_TIMEOUT_MS;
|
||||
}
|
||||
if(squeezelite_args.control_delay->count == 0)
|
||||
{
|
||||
ESP_LOGD(TAG,"Using default control delay");
|
||||
squeezelite_args.control_delay->ival[0]=CONFIG_A2DP_CONTROL_DELAY_MS;
|
||||
}
|
||||
ESP_LOGD(TAG,"Freeing options");
|
||||
free(argv);
|
||||
free(opts);
|
||||
|
||||
/*
|
||||
* Bluetooth audio source init Start
|
||||
*/
|
||||
//running_test = false;
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
|
||||
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
|
||||
ESP_LOGE(TAG,"%s initialize controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
|
||||
ESP_LOGE(TAG,"%s enable controller failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG,"%s initialize bluedroid failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_enable() != ESP_OK) {
|
||||
ESP_LOGE(TAG,"%s enable bluedroid failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
/* create application task */
|
||||
bt_app_task_start_up();
|
||||
|
||||
/* Bluetooth device name, connection mode and profile set up */
|
||||
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
|
||||
|
||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||
/* Set default parameters for Secure Simple Pairing */
|
||||
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
||||
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
||||
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set default parameters for Legacy Pairing
|
||||
* Use variable pin, input pin code when pairing
|
||||
*/
|
||||
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
|
||||
esp_bt_pin_code_t pin_code;
|
||||
esp_bt_gap_set_pin(pin_type, 0, pin_code);
|
||||
|
||||
}
|
||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||
{
|
||||
int32_t avail_data=0,wanted_len=0, start_timer=0;
|
||||
|
||||
if (len < 0 || data == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
btout=data;
|
||||
|
||||
// This is how the BTC layer calculates the number of bytes to
|
||||
// for us to send. (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes
|
||||
wanted_len=len;
|
||||
SET_MIN_MAX(len,req);
|
||||
TIME_MEASUREMENT_START(start_timer);
|
||||
LOCK;
|
||||
SET_MIN_MAX_SIZED(_buf_used(outputbuf),bt,outputbuf->size);
|
||||
do {
|
||||
avail_data = _output_frames( wanted_len/BYTES_PER_FRAME )*BYTES_PER_FRAME; // Keep the transfer buffer full
|
||||
wanted_len-=avail_data;
|
||||
} while (wanted_len > 0 && avail_data != 0);
|
||||
if(wanted_len>0)
|
||||
{
|
||||
SET_MIN_MAX(wanted_len, under);
|
||||
}
|
||||
output.device_frames = 0; // todo: check if this is the right way do to this.
|
||||
output.updated = gettime_ms();
|
||||
output.frames_played_dmp = output.frames_played;
|
||||
UNLOCK;
|
||||
SET_MIN_MAX(TIME_MEASUREMENT_GET(start_timer),lock_out_time);
|
||||
SET_MIN_MAX((len-wanted_len), rec);
|
||||
TIME_MEASUREMENT_START(start_timer);
|
||||
output_bt_check_buffer();
|
||||
|
||||
return len-wanted_len;
|
||||
}
|
||||
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
{
|
||||
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case ESP_BT_GAP_DISC_RES_EVT: {
|
||||
filter_inquiry_scan_result(param);
|
||||
break;
|
||||
}
|
||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
|
||||
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED)
|
||||
{
|
||||
if (s_a2d_state == APP_AV_STATE_DISCOVERED)
|
||||
{
|
||||
ESP_LOGI(TAG,"Discovery completed. Ready to start connecting to %s. ",s_peer_bdname);
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not discovered, continue to discover
|
||||
ESP_LOGI(TAG,"Device discovery failed, continue to discover...");
|
||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
}
|
||||
}
|
||||
else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
|
||||
ESP_LOGI(TAG,"Discovery started.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG,"This shouldn't happen. Discovery has only 2 states (for now).");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BT_GAP_RMT_SRVCS_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_BT_GAP_RMT_SRVCS_EVT);
|
||||
break;
|
||||
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_BT_GAP_RMT_SRVC_REC_EVT);
|
||||
break;
|
||||
case ESP_BT_GAP_AUTH_CMPL_EVT: {
|
||||
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGI(TAG,"authentication success: %s", param->auth_cmpl.device_name);
|
||||
//esp_log_buffer_hex(param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
|
||||
} else {
|
||||
ESP_LOGE(TAG,"authentication failed, status:%d", param->auth_cmpl.stat);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BT_GAP_PIN_REQ_EVT: {
|
||||
ESP_LOGI(TAG,"ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
|
||||
if (param->pin_req.min_16_digit) {
|
||||
ESP_LOGI(TAG,"Input pin code: 0000 0000 0000 0000");
|
||||
esp_bt_pin_code_t pin_code = {0};
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
|
||||
} else {
|
||||
ESP_LOGI(TAG,"Input pin code: 1234");
|
||||
esp_bt_pin_code_t pin_code;
|
||||
pin_code[0] = '1';
|
||||
pin_code[1] = '2';
|
||||
pin_code[2] = '3';
|
||||
pin_code[3] = '4';
|
||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||
case ESP_BT_GAP_CFM_REQ_EVT:
|
||||
ESP_LOGI(TAG,"ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
||||
break;
|
||||
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
||||
ESP_LOGI(TAG,"ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
|
||||
break;
|
||||
ESP_LOGI(TAG,"ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default: {
|
||||
ESP_LOGI(TAG,"event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void a2d_app_heart_beat(void *arg)
|
||||
{
|
||||
bt_app_work_dispatch(bt_app_av_sm_hdlr, BT_APP_HEART_BEAT_EVT, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static void bt_app_av_sm_hdlr(uint16_t event, void *param)
|
||||
{
|
||||
//ESP_LOGD(TAG,"%s state %s, evt 0x%x, output state: %d", __func__, APP_AV_STATE_DESC[s_a2d_state], event, output.state);
|
||||
switch (s_a2d_state) {
|
||||
case APP_AV_STATE_DISCOVERING:
|
||||
ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
|
||||
break;
|
||||
case APP_AV_STATE_DISCOVERED:
|
||||
ESP_LOGV(TAG,"state %s, evt 0x%x, output state: %s", APP_AV_STATE_DESC[s_a2d_state], event, get_output_state_desc(output.state));
|
||||
break;
|
||||
case APP_AV_STATE_UNCONNECTED:
|
||||
bt_app_av_state_unconnected(event, param);
|
||||
break;
|
||||
case APP_AV_STATE_CONNECTING:
|
||||
bt_app_av_state_connecting(event, param);
|
||||
break;
|
||||
case APP_AV_STATE_CONNECTED:
|
||||
bt_app_av_state_connected(event, param);
|
||||
break;
|
||||
case APP_AV_STATE_DISCONNECTING:
|
||||
bt_app_av_state_disconnecting(event, param);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s invalid state %d", __func__, s_a2d_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
||||
{
|
||||
if (bda == NULL || str == NULL || size < 18) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *p = bda;
|
||||
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
return str;
|
||||
}
|
||||
static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
|
||||
{
|
||||
uint8_t *rmt_bdname = NULL;
|
||||
uint8_t rmt_bdname_len = 0;
|
||||
|
||||
if (!eir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
|
||||
if (!rmt_bdname) {
|
||||
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
|
||||
}
|
||||
|
||||
if (rmt_bdname) {
|
||||
if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
|
||||
rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
|
||||
}
|
||||
|
||||
if (bdname) {
|
||||
memcpy(bdname, rmt_bdname, rmt_bdname_len);
|
||||
bdname[rmt_bdname_len] = '\0';
|
||||
}
|
||||
if (bdname_len) {
|
||||
*bdname_len = rmt_bdname_len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
char bda_str[18];
|
||||
uint32_t cod = 0;
|
||||
int32_t rssi = -129; /* invalid value */
|
||||
uint8_t *eir = NULL;
|
||||
uint8_t nameLen = 0;
|
||||
esp_bt_gap_dev_prop_t *p;
|
||||
memset(s_peer_bdname, 0x00,sizeof(s_peer_bdname));
|
||||
|
||||
ESP_LOGI(TAG,"\n=======================\nScanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
|
||||
for (int i = 0; i < param->disc_res.num_prop; i++) {
|
||||
p = param->disc_res.prop + i;
|
||||
switch (p->type) {
|
||||
case ESP_BT_GAP_DEV_PROP_COD:
|
||||
cod = *(uint32_t *)(p->val);
|
||||
ESP_LOGI(TAG,"-- Class of Device: 0x%x", cod);
|
||||
break;
|
||||
case ESP_BT_GAP_DEV_PROP_RSSI:
|
||||
rssi = *(int8_t *)(p->val);
|
||||
ESP_LOGI(TAG,"-- RSSI: %d", rssi);
|
||||
break;
|
||||
case ESP_BT_GAP_DEV_PROP_EIR:
|
||||
eir = (uint8_t *)(p->val);
|
||||
ESP_LOGI(TAG,"-- EIR: %u", *eir);
|
||||
break;
|
||||
case ESP_BT_GAP_DEV_PROP_BDNAME:
|
||||
nameLen = (p->len > ESP_BT_GAP_MAX_BDNAME_LEN) ? ESP_BT_GAP_MAX_BDNAME_LEN : (uint8_t)p->len;
|
||||
memcpy(s_peer_bdname, (uint8_t *)(p->val), nameLen);
|
||||
s_peer_bdname[nameLen] = '\0';
|
||||
ESP_LOGI(TAG,"-- Name: %s", s_peer_bdname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!esp_bt_gap_is_valid_cod(cod)){
|
||||
/* search for device with MAJOR service class as "rendering" in COD */
|
||||
ESP_LOGI(TAG,"--Invalid class of device. Skipping.\n");
|
||||
return;
|
||||
}
|
||||
else if (!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING))
|
||||
{
|
||||
ESP_LOGI(TAG,"--Not a rendering device. Skipping.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* search for device named "ESP_SPEAKER" in its extended inqury response */
|
||||
if (eir) {
|
||||
ESP_LOGI(TAG,"--Getting details from eir.\n");
|
||||
get_name_from_eir(eir, s_peer_bdname, NULL);
|
||||
ESP_LOGI(TAG,"--Device name is %s\n",s_peer_bdname);
|
||||
}
|
||||
|
||||
if (strcmp((char *)s_peer_bdname, CONFIG_A2DP_SINK_NAME) == 0) {
|
||||
ESP_LOGI(TAG,"Found a target device! address %s, name %s", bda_str, s_peer_bdname);
|
||||
ESP_LOGI(TAG,"=======================\n");
|
||||
if(esp_bt_gap_cancel_discovery()!=ESP_ERR_INVALID_STATE)
|
||||
{
|
||||
ESP_LOGI(TAG,"Cancel device discovery ...");
|
||||
memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
||||
s_a2d_state = APP_AV_STATE_DISCOVERED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG,"Cancel device discovery failed...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG,"Not the device we are looking for. Continuing scan.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
|
||||
switch (event) {
|
||||
case BT_APP_EVT_STACK_UP: {
|
||||
ESP_LOGI(TAG,"BT Stack going up.");
|
||||
/* set up device name */
|
||||
char *dev_name = CONFIG_A2DP_DEV_NAME;
|
||||
esp_bt_dev_set_device_name(dev_name);
|
||||
ESP_LOGI(TAG,"Preparing to connect to device: %s",CONFIG_A2DP_SINK_NAME);
|
||||
|
||||
/* register GAP callback function */
|
||||
esp_bt_gap_register_callback(bt_app_gap_cb);
|
||||
|
||||
/* initialize A2DP source */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_source_register_data_callback(bt_app_a2d_data_cb);
|
||||
esp_a2d_source_init();
|
||||
|
||||
/* set discoverable and connectable mode */
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
|
||||
/* start device discovery */
|
||||
ESP_LOGI(TAG,"Starting device discovery...");
|
||||
s_a2d_state = APP_AV_STATE_DISCOVERING;
|
||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
|
||||
/* create and start heart beat timer */
|
||||
do {
|
||||
int tmr_id = 0;
|
||||
s_tmr = xTimerCreate("connTmr", (CONFIG_A2DP_CONTROL_DELAY_MS / portTICK_RATE_MS),
|
||||
pdTRUE, (void *)tmr_id, a2d_app_heart_beat);
|
||||
xTimerStart(s_tmr, portMAX_DELAY);
|
||||
} while (0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BTAUDIO
|
||||
bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
|
||||
|
||||
// running_test = true;
|
||||
// while(running_test)
|
||||
// {
|
||||
// // wait until BT playback has started
|
||||
// // this will allow querying the sample rate
|
||||
// usleep(100000);
|
||||
// }
|
||||
|
||||
memset(rates, 0, MAX_SUPPORTED_SAMPLERATES * sizeof(unsigned));
|
||||
if (!strcmp(device, "BT")) {
|
||||
rates[0] = 44100;
|
||||
} else {
|
||||
unsigned _rates[] = { 96000, 88200, 48000, 44100, 32000, 0 };
|
||||
memcpy(rates, _rates, sizeof(_rates));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
static void bt_app_av_media_proc(uint16_t event, void *param)
|
||||
{
|
||||
esp_a2d_cb_param_t *a2d = NULL;
|
||||
LOCK;
|
||||
output_state out_state=output.state;
|
||||
UNLOCK;
|
||||
switch (s_media_state) {
|
||||
case APP_AV_MEDIA_STATE_IDLE: {
|
||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||
if(out_state > OUTPUT_STOPPED)
|
||||
{
|
||||
ESP_LOGI(TAG,"Output state is %s, a2dp media ready and connected. Checking if A2DP is ready.", get_output_state_desc(out_state));
|
||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
|
||||
}
|
||||
|
||||
} else if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY &&
|
||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS
|
||||
) {
|
||||
ESP_LOGI(TAG,"a2dp media ready, waiting for media buffering ...");
|
||||
s_media_state = APP_AV_MEDIA_STATE_BUFFERING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APP_AV_MEDIA_STATE_BUFFERING: {
|
||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||
switch (out_state) {
|
||||
case OUTPUT_RUNNING :
|
||||
case OUTPUT_PAUSE_FRAMES :
|
||||
case OUTPUT_SKIP_FRAMES:
|
||||
case OUTPUT_START_AT:
|
||||
case OUTPUT_BUFFER:
|
||||
// Buffer is ready, local buffer has some data, start playback!
|
||||
ESP_LOGI(TAG,"Out state is %s, a2dp media ready and connected. Starting playback! ", get_output_state_desc(out_state));
|
||||
s_media_state = APP_AV_MEDIA_STATE_STARTING;
|
||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
|
||||
break;
|
||||
case OUTPUT_STOPPED:
|
||||
case OUTPUT_OFF:
|
||||
ESP_LOGD(TAG,"Output state is %s. Changing app status to ",get_output_state_desc(out_state));
|
||||
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG,"Unknown output status while waiting for buffering to complete %d",out_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
ESP_LOGW(TAG,"Received unknown event while in state APP_AV_MEDIA_STATE_BUFFERING");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case APP_AV_MEDIA_STATE_STARTING: {
|
||||
if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
|
||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
||||
ESP_LOGI(TAG,"a2dp media started successfully.");
|
||||
s_media_state = APP_AV_MEDIA_STATE_STARTED;
|
||||
} else {
|
||||
// not started succesfully, transfer to idle state
|
||||
ESP_LOGI(TAG,"a2dp media start failed.");
|
||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APP_AV_MEDIA_STATE_STARTED: {
|
||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||
if(out_state <= OUTPUT_STOPPED) {
|
||||
ESP_LOGI(TAG,"Output state is stopped. Stopping a2dp media ...");
|
||||
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOCK_S;
|
||||
SET_MIN_MAX_SIZED(_buf_used(streambuf),stream_buf,streambuf->size);
|
||||
UNLOCK_S;
|
||||
static time_t lastTime=0;
|
||||
if (lastTime <= gettime_ms() )
|
||||
{
|
||||
lastTime = gettime_ms() + 15000;
|
||||
ESP_LOGD(TAG, "Statistics over %u secs. " , STATS_REPORT_DELAY_MS/1000);
|
||||
ESP_LOGD(TAG, " +==========+==========+================+=====+================+");
|
||||
ESP_LOGD(TAG, " | max | min | average | avg | count |");
|
||||
ESP_LOGD(TAG, " | (bytes) | (bytes) | (bytes) | pct | |");
|
||||
ESP_LOGD(TAG, " +==========+==========+================+=====+================+");
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("stream avl",stream_buf));
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("output avl",bt));
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("requested",req));
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("received",rec));
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_FORMAT,LINE_MIN_MAX("underrun",under));
|
||||
ESP_LOGD(TAG, " +==========+==========+================+=====+================+");
|
||||
ESP_LOGD(TAG,"\n");
|
||||
ESP_LOGD(TAG," ==========+==========+===========+===========+ ");
|
||||
ESP_LOGD(TAG," max (us) | min (us) | avg(us) | count | ");
|
||||
ESP_LOGD(TAG," ==========+==========+===========+===========+ ");
|
||||
ESP_LOGD(TAG,LINE_MIN_MAX_DURATION_FORMAT,LINE_MIN_MAX_DURATION("Out Buf Lock",lock_out_time));
|
||||
ESP_LOGD(TAG," ==========+==========+===========+===========+");
|
||||
RESET_ALL_MIN_MAX;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APP_AV_MEDIA_STATE_STOPPING: {
|
||||
ESP_LOG_DEBUG_EVENT(TAG,APP_AV_MEDIA_STATE_STOPPING);
|
||||
if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP &&
|
||||
a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
|
||||
ESP_LOGI(TAG,"a2dp media stopped successfully...");
|
||||
//s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT;
|
||||
// if(CONFIG_A2DP_DISCONNECT_MS==0){
|
||||
// we're not going to disconnect.
|
||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// disconnect_time = gettime_ms()+CONFIG_A2DP_DISCONNECT_MS;
|
||||
// s_media_state = APP_AV_MEDIA_STATE_WAIT_DISCONNECT;
|
||||
// }
|
||||
} else {
|
||||
ESP_LOGI(TAG,"a2dp media stopping...");
|
||||
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case APP_AV_MEDIA_STATE_WAIT_DISCONNECT:{
|
||||
if(gettime_ms()>disconnect_time){
|
||||
// we've reached timeout
|
||||
esp_a2d_source_disconnect(s_peer_bda);
|
||||
s_a2d_state = APP_AV_STATE_DISCONNECTING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_av_state_unconnected(uint16_t event, void *param)
|
||||
{
|
||||
// LOCK;
|
||||
// output_state out_state= output.state;
|
||||
// UNLOCK;
|
||||
switch (event) {
|
||||
case ESP_A2D_CONNECTION_STATE_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_CONNECTION_STATE_EVT);
|
||||
// this could happen if connection was established
|
||||
// right after we timed out. Pass the call down to the connecting
|
||||
// handler.
|
||||
esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
|
||||
bt_app_av_state_connecting(event, param);
|
||||
}
|
||||
|
||||
break;
|
||||
case ESP_A2D_AUDIO_STATE_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_STATE_EVT);
|
||||
|
||||
break;
|
||||
case ESP_A2D_AUDIO_CFG_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_CFG_EVT);
|
||||
break;
|
||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
||||
break;
|
||||
case BT_APP_HEART_BEAT_EVT: {
|
||||
// uint8_t *p = s_peer_bda;
|
||||
// ESP_LOGI(TAG,"BT_APP_HEART_BEAT_EVT a2dp connecting to peer: %02x:%02x:%02x:%02x:%02x:%02x",p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
switch (esp_bluedroid_get_status()) {
|
||||
case ESP_BLUEDROID_STATUS_UNINITIALIZED:
|
||||
ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_UNINITIALIZED.");
|
||||
break;
|
||||
case ESP_BLUEDROID_STATUS_INITIALIZED:
|
||||
ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_INITIALIZED.");
|
||||
break;
|
||||
case ESP_BLUEDROID_STATUS_ENABLED:
|
||||
ESP_LOGV(TAG,"BlueDroid Status is ESP_BLUEDROID_STATUS_ENABLED.");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// if(out_state > OUTPUT_STOPPED){
|
||||
// only attempt a connect when playback isn't stopped
|
||||
if(esp_a2d_source_connect(s_peer_bda)==ESP_OK) {
|
||||
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||
for(uint8_t l=0;art_a2dp_connecting[l][0]!='\0';l++){
|
||||
ESP_LOGI(TAG,"%s",art_a2dp_connecting[l]);
|
||||
}
|
||||
ESP_LOGI(TAG,"********** A2DP CONNECTING TO %s", s_peer_bdname);
|
||||
A2DP_TIMER_INIT;
|
||||
}
|
||||
else {
|
||||
// there was an issue connecting... continue to discover
|
||||
ESP_LOGE(TAG,"Attempt at connecting failed, restart at discover...");
|
||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
// }
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_av_state_connecting(uint16_t event, void *param)
|
||||
{
|
||||
esp_a2d_cb_param_t *a2d = NULL;
|
||||
|
||||
switch (event) {
|
||||
case ESP_A2D_CONNECTION_STATE_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
|
||||
s_a2d_state = APP_AV_STATE_CONNECTED;
|
||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
for(uint8_t l=0;art_a2dp_connected[l][0]!='\0';l++){
|
||||
ESP_LOGI(TAG,"%s",art_a2dp_connected[l]);
|
||||
}
|
||||
ESP_LOGD(TAG,"Setting scan mode to ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE");
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
||||
ESP_LOGD(TAG,"Done setting scan mode. App state is now CONNECTED and media state IDLE.");
|
||||
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_AUDIO_STATE_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_STATE_EVT);
|
||||
break;
|
||||
case ESP_A2D_AUDIO_CFG_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_CFG_EVT);
|
||||
break;
|
||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
||||
break;
|
||||
case BT_APP_HEART_BEAT_EVT:
|
||||
if (IS_A2DP_TIMER_OVER)
|
||||
{
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
ESP_LOGE(TAG,"A2DP Connect time out! Setting state to Unconnected. ");
|
||||
A2DP_TIMER_INIT;
|
||||
}
|
||||
ESP_LOGV(TAG,"BT_APP_HEART_BEAT_EVT");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void bt_app_av_state_connected(uint16_t event, void *param)
|
||||
{
|
||||
esp_a2d_cb_param_t *a2d = NULL;
|
||||
switch (event) {
|
||||
case ESP_A2D_CONNECTION_STATE_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
ESP_LOGI(TAG,"a2dp disconnected");
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_AUDIO_STATE_EVT: {
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_STATE_EVT);
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
|
||||
s_pkt_cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_AUDIO_CFG_EVT:
|
||||
// not suppposed to occur for A2DP source
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_CFG_EVT);
|
||||
break;
|
||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:{
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
||||
bt_app_av_media_proc(event, param);
|
||||
break;
|
||||
}
|
||||
case BT_APP_HEART_BEAT_EVT: {
|
||||
ESP_LOG_DEBUG_EVENT(TAG,BT_APP_HEART_BEAT_EVT);
|
||||
bt_app_av_media_proc(event, param);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_av_state_disconnecting(uint16_t event, void *param)
|
||||
{
|
||||
esp_a2d_cb_param_t *a2d = NULL;
|
||||
switch (event) {
|
||||
case ESP_A2D_CONNECTION_STATE_EVT: {
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_CONNECTION_STATE_EVT);
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
ESP_LOGI(TAG,"a2dp disconnected");
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_AUDIO_STATE_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_STATE_EVT);
|
||||
break;
|
||||
case ESP_A2D_AUDIO_CFG_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_AUDIO_CFG_EVT);
|
||||
break;
|
||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,ESP_A2D_MEDIA_CTRL_ACK_EVT);
|
||||
break;
|
||||
case BT_APP_HEART_BEAT_EVT:
|
||||
ESP_LOG_DEBUG_EVENT(TAG,BT_APP_HEART_BEAT_EVT);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG,"%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
165
components/platform_esp32/platform_esp32.h
Normal file
165
components/platform_esp32/platform_esp32.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "bt_app_core.h"
|
||||
#include "perf_trace.h"
|
||||
#include "esp_pthread.h"
|
||||
#ifndef QUOTE
|
||||
#define QUOTE(name) #name
|
||||
#define STR(macro) QUOTE(macro)
|
||||
#endif
|
||||
extern void run_command(char * line);
|
||||
extern bool wait_for_wifi();
|
||||
|
||||
//typedef struct {
|
||||
// char opt_slimproto_logging[11];
|
||||
// char opt_stream_logging[11];
|
||||
// char opt_decode_logging[11];
|
||||
// char opt_output_logging[11];
|
||||
// char opt_player_name[11];
|
||||
// char opt_output_rates[21];
|
||||
// char opt_buffer[11];
|
||||
//} str_squeezelite_options ;
|
||||
extern void console_start();
|
||||
extern pthread_cond_t wifi_connect_suspend_cond;
|
||||
extern pthread_t wifi_connect_suspend_mutex;
|
||||
//static const char * art_wifi[]={
|
||||
// "\n",
|
||||
// "o `O ooOoOOo OOooOoO ooOoOOo\n",
|
||||
// "O o O o O \n",
|
||||
// "o O o O o \n",
|
||||
// "O O O oOooO O \n",
|
||||
// "o o o o O o \n",
|
||||
// "O O O O o O \n",
|
||||
// "`o O o O' O o O \n",
|
||||
// " `OoO' `OoO' ooOOoOo O' ooOOoOo\n",
|
||||
// "\n",
|
||||
// ""
|
||||
//};
|
||||
//static const char * art_wifi_connecting[]={
|
||||
// " .oOOOo.",
|
||||
// ".O o o \n",
|
||||
// "o O \n",
|
||||
// "o oOo \n",
|
||||
// "o .oOo. 'OoOo. 'OoOo. .oOo. .oOo o O 'OoOo. .oOoO \n",
|
||||
// "O O o o O o O OooO' O O o o O o O \n",
|
||||
// "`o .o o O O o O o O o o O O o O o \n",
|
||||
// " `OoooO' `OoO' o O o O `OoO' `OoO' `oO o' o O `OoOo \n",
|
||||
// " O \n",
|
||||
// " OoO' \n",
|
||||
// "\n",
|
||||
// ""
|
||||
//};
|
||||
//static const char * art_wifi_connected[]={
|
||||
// " .oOOOo. o oO\n",
|
||||
// ".O o O OO\n",
|
||||
// "o O o oO\n",
|
||||
// "o oOo o Oo\n",
|
||||
// "o .oOo. 'OoOo. 'OoOo. .oOo. .oOo o .oOo. .oOoO oO\n",
|
||||
// "O O o o O o O OooO' O O OooO' o O \n",
|
||||
// "`o .o o O O o O o O o o O O o Oo\n",
|
||||
// " `OoooO' `OoO' o O o O `OoO' `OoO' `oO `OoO' `OoO'o oO\n",
|
||||
// "\n",
|
||||
// ""
|
||||
//};
|
||||
#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " QUOTE(e))
|
||||
typedef struct {
|
||||
char * optName;
|
||||
char * cmdLinePrefix;
|
||||
char * description;
|
||||
char * defaultValue;
|
||||
char * relatedcommand;
|
||||
} optListStruct;
|
||||
optListStruct * getOptionByName(char * option);
|
||||
//static optListStruct optList[] = {
|
||||
// {
|
||||
// .optName= "log_slimproto",
|
||||
// .cmdLinePrefix="-d slimproto=",
|
||||
// .description="Slimproto Logging Level info|debug|sdebug",
|
||||
// .defaultValue=(CONFIG_LOGGING_SLIMPROTO),
|
||||
// .relatedcommand="squeezelite"
|
||||
// },
|
||||
// {
|
||||
// .optName="log_stream",
|
||||
// .cmdLinePrefix="-d stream=",
|
||||
// .description="Stream Logging Level info|debug|sdebug",
|
||||
// .defaultValue=(CONFIG_LOGGING_STREAM),
|
||||
// .relatedcommand="squeezelite"
|
||||
// },
|
||||
// {
|
||||
// .optName="log_decode",
|
||||
// .cmdLinePrefix="-d decode=",
|
||||
// .description="Decode Logging Level info|debug|sdebug",
|
||||
// .defaultValue=(CONFIG_LOGGING_DECODE),
|
||||
// .relatedcommand="squeezelite"
|
||||
// },
|
||||
// {
|
||||
// .optName="log_output",
|
||||
// .cmdLinePrefix="-d output=",
|
||||
// .description="Output Logging Level info|debug|sdebug",
|
||||
// .defaultValue=(CONFIG_LOGGING_OUTPUT),
|
||||
// .relatedcommand="squeezelite"
|
||||
// },
|
||||
// {
|
||||
// .optName="output_rates",
|
||||
// .cmdLinePrefix="-r ",
|
||||
// .description="Supported rates",
|
||||
// .defaultValue=(CONFIG_OUTPUT_RATES),
|
||||
// .relatedcommand="squeezelite"
|
||||
// },
|
||||
// {
|
||||
// .optName="output_dev",
|
||||
// .cmdLinePrefix="-O",
|
||||
// .description="Output device to use. BT for Bluetooth, DAC for i2s DAC.",
|
||||
// .defaultValue=(CONFIG_A2DP_SINK_NAME),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="a2dp_sink_name",
|
||||
// .cmdLinePrefix="",
|
||||
// .description="Bluetooth sink name to connect to.",
|
||||
// .defaultValue=(CONFIG_A2DP_SINK_NAME),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="a2dp_dev_name",
|
||||
// .cmdLinePrefix="",
|
||||
// .description="A2DP Device name to use when connecting to audio sink.",
|
||||
// .defaultValue=(CONFIG_A2DP_DEV_NAME),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="a2dp_cntrldelay",
|
||||
// .cmdLinePrefix="",
|
||||
// .description="Delay (ms) for each pass of the A2DP control loop.",
|
||||
// .defaultValue=STR(CONFIG_A2DP_CONTROL_DELAY_MS),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="a2dp_timeout",
|
||||
// .cmdLinePrefix="",
|
||||
// .description="Delay (ms) for A2DP timeout on connect.",
|
||||
// .defaultValue=STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="wifi_ssid",
|
||||
// .cmdLinePrefix="",
|
||||
// .description="WiFi access point name to connect to.",
|
||||
// .defaultValue= (CONFIG_WIFI_SSID),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {
|
||||
// .optName="wifi_password",
|
||||
// .cmdLinePrefix= "",
|
||||
// .description="WiFi access point password.",
|
||||
// .defaultValue=(CONFIG_WIFI_PASSWORD),
|
||||
// .relatedcommand=""
|
||||
// },
|
||||
// {}
|
||||
//};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user