mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-03-31 11:49:30 +01:00
applied platformio structure
This commit is contained in:
11
lib/tools/CMakeLists.txt
Normal file
11
lib/tools/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
idf_component_register( SRCS operator.cpp tools.c trace.c
|
||||
REQUIRES esp_common pthread
|
||||
PRIV_REQUIRES esp_http_client esp-tls
|
||||
INCLUDE_DIRS .
|
||||
)
|
||||
|
||||
#doing our own implementation of new operator for some pre-compiled binaries
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _ZdlPv")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _Znwj")
|
||||
|
||||
|
||||
11
lib/tools/component.mk
Normal file
11
lib/tools/component.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
||||
22
lib/tools/operator.cpp
Normal file
22
lib/tools/operator.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <memory>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
void* operator new(std::size_t count) {
|
||||
return heap_caps_malloc(count, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr) noexcept {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
// C++17 only
|
||||
void* operator new (std::size_t count, std::align_val_t alignment) {
|
||||
return heap_caps_malloc(count, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
// C++17 only
|
||||
void operator delete(void* ptr, std::align_val_t alignment) noexcept {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
*/
|
||||
78
lib/tools/perf_trace.h
Normal file
78
lib/tools/perf_trace.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sys/time.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, count_##var=0;static uint64_t avgtot_##var = 0; static uint32_t var=0
|
||||
#define DECLARE_MIN_MAX_DURATION(var) static uint32_t min_##var = PERF_MAX, max_##var = 0, count_##var=0; uint64_t avgtot_##var = 0; uint32_t var=0
|
||||
#define LINE_MIN_MAX_AVG(var) (uint32_t)(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;
|
||||
}
|
||||
|
||||
37
lib/tools/platform_esp32.h
Normal file
37
lib/tools/platform_esp32.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_pthread.h"
|
||||
#include "esp_log.h"
|
||||
#ifndef SQUEEZELITE_ESP32_RELEASE_URL
|
||||
#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
|
||||
#endif
|
||||
extern bool is_recovery_running;
|
||||
extern bool wait_for_wifi();
|
||||
extern bool console_push(const char * data, size_t size);
|
||||
extern void console_start();
|
||||
extern pthread_cond_t wifi_connect_suspend_cond;
|
||||
extern pthread_t wifi_connect_suspend_mutex;
|
||||
|
||||
extern void (*server_notify)(in_addr_t ip, uint16_t hport, uint16_t cport);
|
||||
extern bool cold_boot;
|
||||
328
lib/tools/tools.c
Normal file
328
lib/tools/tools.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* (c) Philippe G. 20201, philippe_44@outlook.com
|
||||
* see other copyrights below
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_task.h"
|
||||
#include "esp_tls.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "tools.h"
|
||||
|
||||
#if CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS < 2
|
||||
#error CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS must be at least 2
|
||||
#endif
|
||||
|
||||
const static char TAG[] = "tools";
|
||||
|
||||
/****************************************************************************************
|
||||
* UTF-8 tools
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
// Copyright (c) 2017 ZephRay <zephray@outlook.com>
|
||||
//
|
||||
// utf8to1252 - almost equivalent to iconv -f utf-8 -t windows-1252, but better
|
||||
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 1
|
||||
|
||||
static const uint8_t utf8d[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
|
||||
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
|
||||
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
|
||||
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
|
||||
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
|
||||
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
|
||||
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
|
||||
};
|
||||
|
||||
static uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
|
||||
uint32_t type = utf8d[byte];
|
||||
|
||||
*codep = (*state != UTF8_ACCEPT) ?
|
||||
(byte & 0x3fu) | (*codep << 6) :
|
||||
(0xff >> type) & (byte);
|
||||
|
||||
*state = utf8d[256 + *state*16 + type];
|
||||
return *state;
|
||||
}
|
||||
|
||||
static uint8_t UNICODEtoCP1252(uint16_t chr) {
|
||||
if (chr <= 0xff)
|
||||
return (chr&0xff);
|
||||
else {
|
||||
ESP_LOGI(TAG, "some multi-byte %hx", chr);
|
||||
switch(chr) {
|
||||
case 0x20ac: return 0x80; break;
|
||||
case 0x201a: return 0x82; break;
|
||||
case 0x0192: return 0x83; break;
|
||||
case 0x201e: return 0x84; break;
|
||||
case 0x2026: return 0x85; break;
|
||||
case 0x2020: return 0x86; break;
|
||||
case 0x2021: return 0x87; break;
|
||||
case 0x02c6: return 0x88; break;
|
||||
case 0x2030: return 0x89; break;
|
||||
case 0x0160: return 0x8a; break;
|
||||
case 0x2039: return 0x8b; break;
|
||||
case 0x0152: return 0x8c; break;
|
||||
case 0x017d: return 0x8e; break;
|
||||
case 0x2018: return 0x91; break;
|
||||
case 0x2019: return 0x92; break;
|
||||
case 0x201c: return 0x93; break;
|
||||
case 0x201d: return 0x94; break;
|
||||
case 0x2022: return 0x95; break;
|
||||
case 0x2013: return 0x96; break;
|
||||
case 0x2014: return 0x97; break;
|
||||
case 0x02dc: return 0x98; break;
|
||||
case 0x2122: return 0x99; break;
|
||||
case 0x0161: return 0x9a; break;
|
||||
case 0x203a: return 0x9b; break;
|
||||
case 0x0153: return 0x9c; break;
|
||||
case 0x017e: return 0x9e; break;
|
||||
case 0x0178: return 0x9f; break;
|
||||
default: return 0x00; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void utf8_decode(char *src) {
|
||||
uint32_t codep = 0, state = UTF8_ACCEPT;
|
||||
char *dst = src;
|
||||
|
||||
while (src && *src) {
|
||||
if (!decode(&state, &codep, *src++)) *dst++ = UNICODEtoCP1252(codep);
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* URL tools
|
||||
*/
|
||||
|
||||
static inline char from_hex(char ch) {
|
||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||
}
|
||||
|
||||
void url_decode(char *url) {
|
||||
char *p, *src = strdup(url);
|
||||
for (p = src; *src; url++) {
|
||||
*url = *src++;
|
||||
if (*url == '%') {
|
||||
*url = from_hex(*src++) << 4;
|
||||
*url |= from_hex(*src++);
|
||||
} else if (*url == '+') {
|
||||
*url = ' ';
|
||||
}
|
||||
}
|
||||
*url = '\0';
|
||||
free(p);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Memory tools
|
||||
*/
|
||||
|
||||
void * malloc_init_external(size_t sz){
|
||||
void * ptr=NULL;
|
||||
ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if(ptr==NULL){
|
||||
ESP_LOGE(TAG,"malloc_init_external: unable to allocate %d bytes of PSRAM!",sz);
|
||||
}
|
||||
else {
|
||||
memset(ptr,0x00,sz);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * clone_obj_psram(void * source, size_t source_sz){
|
||||
void * ptr=NULL;
|
||||
ptr = heap_caps_malloc(source_sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if(ptr==NULL){
|
||||
ESP_LOGE(TAG,"clone_obj_psram: unable to allocate %d bytes of PSRAM!",source_sz);
|
||||
}
|
||||
else {
|
||||
memcpy(ptr,source,source_sz);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char * strdup_psram(const char * source){
|
||||
void * ptr=NULL;
|
||||
size_t source_sz = strlen(source)+1;
|
||||
ptr = heap_caps_malloc(source_sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if(ptr==NULL){
|
||||
ESP_LOGE(TAG,"strdup_psram: unable to allocate %d bytes of PSRAM! Cannot clone string %s",source_sz,source);
|
||||
}
|
||||
else {
|
||||
memset(ptr,0x00,source_sz);
|
||||
strcpy(ptr,source);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Task manager
|
||||
*/
|
||||
#define TASK_TLS_INDEX 1
|
||||
|
||||
typedef struct {
|
||||
StaticTask_t *xTaskBuffer;
|
||||
StackType_t *xStack;
|
||||
} task_context_t;
|
||||
|
||||
static void task_cleanup(int index, task_context_t *context) {
|
||||
free(context->xTaskBuffer);
|
||||
free(context->xStack);
|
||||
free(context);
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreateEXTRAM( TaskFunction_t pvTaskCode,
|
||||
const char * const pcName,
|
||||
configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void *pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *pxCreatedTask) {
|
||||
// create the worker task as a static
|
||||
task_context_t *context = calloc(1, sizeof(task_context_t));
|
||||
context->xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
|
||||
context->xStack = heap_caps_malloc(usStackDepth,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
|
||||
TaskHandle_t handle = xTaskCreateStatic(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, context->xStack, context->xTaskBuffer);
|
||||
|
||||
// store context in TCB or free everything in case of failure
|
||||
if (!handle) {
|
||||
free(context->xTaskBuffer);
|
||||
free(context->xStack);
|
||||
free(context);
|
||||
} else {
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback( handle, TASK_TLS_INDEX, context, (TlsDeleteCallbackFunction_t) task_cleanup);
|
||||
}
|
||||
|
||||
if (pxCreatedTask) *pxCreatedTask = handle;
|
||||
return handle != NULL ? pdPASS : pdFAIL;
|
||||
}
|
||||
|
||||
void vTaskDeleteEXTRAM(TaskHandle_t xTask) {
|
||||
/* At this point we leverage FreeRTOS extension to have callbacks on task deletion.
|
||||
* If not, we need to have here our own deletion implementation that include delayed
|
||||
* free for when this is called with NULL (self-deletion)
|
||||
*/
|
||||
vTaskDelete(xTask);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* URL download
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
void *user_context;
|
||||
http_download_cb_t callback;
|
||||
size_t max, bytes;
|
||||
bool abort;
|
||||
uint8_t *data;
|
||||
esp_http_client_handle_t client;
|
||||
} http_context_t;
|
||||
|
||||
static void http_downloader(void *arg);
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void http_download(char *url, size_t max, http_download_cb_t callback, void *context) {
|
||||
http_context_t *http_context = (http_context_t*) heap_caps_calloc(sizeof(http_context_t), 1, MALLOC_CAP_SPIRAM);
|
||||
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.event_handler = http_event_handler,
|
||||
.user_data = http_context,
|
||||
};
|
||||
|
||||
http_context->callback = callback;
|
||||
http_context->user_context = context;
|
||||
http_context->max = max;
|
||||
http_context->client = esp_http_client_init(&config);
|
||||
|
||||
xTaskCreateEXTRAM(http_downloader, "downloader", 8*1024, http_context, ESP_TASK_PRIO_MIN + 1, NULL);
|
||||
}
|
||||
|
||||
static void http_downloader(void *arg) {
|
||||
http_context_t *http_context = (http_context_t*) arg;
|
||||
|
||||
esp_http_client_perform(http_context->client);
|
||||
esp_http_client_cleanup(http_context->client);
|
||||
|
||||
free(http_context);
|
||||
vTaskDeleteEXTRAM(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt) {
|
||||
http_context_t *http_context = (http_context_t*) evt->user_data;
|
||||
|
||||
if (http_context->abort) return ESP_FAIL;
|
||||
|
||||
switch(evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
http_context->callback(NULL, 0, http_context->user_context);
|
||||
http_context->abort = true;
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
if (!strcasecmp(evt->header_key, "Content-Length")) {
|
||||
size_t len = atoi(evt->header_value);
|
||||
if (!len || len > http_context->max) {
|
||||
ESP_LOGI(TAG, "content-length null or too large %zu / %zu", len, http_context->max);
|
||||
http_context->abort = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA: {
|
||||
size_t len = esp_http_client_get_content_length(evt->client);
|
||||
if (!http_context->data) {
|
||||
if ((http_context->data = (uint8_t*) malloc(len)) == NULL) {
|
||||
http_context->abort = true;
|
||||
ESP_LOGE(TAG, "failed to allocate memory for output buffer %zu", len);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
memcpy(http_context->data + http_context->bytes, evt->data, evt->data_len);
|
||||
http_context->bytes += evt->data_len;
|
||||
break;
|
||||
}
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
http_context->callback(http_context->data, http_context->bytes, http_context->user_context);
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED: {
|
||||
int mbedtls_err = 0;
|
||||
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "HTTP download disconnect %d", err);
|
||||
if (http_context->data) free(http_context->data);
|
||||
http_context->callback(NULL, 0, http_context->user_context);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
75
lib/tools/tools.h
Normal file
75
lib/tools/tools.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Tools
|
||||
*
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef QUOTE
|
||||
#define QUOTE(name) #name
|
||||
#endif
|
||||
|
||||
#ifndef STR
|
||||
#define STR(macro) QUOTE(macro)
|
||||
#endif
|
||||
|
||||
#ifndef STR_OR_ALT
|
||||
#define STR_OR_ALT(str,alt) (str?str:alt)
|
||||
#endif
|
||||
|
||||
#ifndef STR_OR_BLANK
|
||||
#define STR_OR_BLANK(p) p == NULL ? "" : p
|
||||
#endif
|
||||
|
||||
#define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e)
|
||||
|
||||
#ifndef FREE_AND_NULL
|
||||
#define FREE_AND_NULL(x) if(x) { free(x); x=NULL; }
|
||||
#endif
|
||||
|
||||
#ifndef CASE_TO_STR
|
||||
#define CASE_TO_STR(x) case x: return STR(x); break;
|
||||
#endif
|
||||
|
||||
#define ENUM_TO_STRING(g) \
|
||||
case g: \
|
||||
return STR(g); \
|
||||
break;
|
||||
|
||||
void utf8_decode(char *src);
|
||||
void url_decode(char *url);
|
||||
void* malloc_init_external(size_t sz);
|
||||
void* clone_obj_psram(void * source, size_t source_sz);
|
||||
char* strdup_psram(const char * source);
|
||||
const char* str_or_unknown(const char * str);
|
||||
const char* str_or_null(const char * str);
|
||||
|
||||
typedef void (*http_download_cb_t)(uint8_t* data, size_t len, void *context);
|
||||
void http_download(char *url, size_t max, http_download_cb_t callback, void *context);
|
||||
|
||||
/* Use these to dynamically create tasks whose stack is on EXTRAM. Be aware that it
|
||||
* requires configNUM_THREAD_LOCAL_STORAGE_POINTERS to bet set to 2 at least (index 0
|
||||
* is used by pthread and this uses index 1, obviously
|
||||
*/
|
||||
BaseType_t xTaskCreateEXTRAM( TaskFunction_t pvTaskCode,
|
||||
const char * const pcName,
|
||||
configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void *pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *pxCreatedTask);
|
||||
void vTaskDeleteEXTRAM(TaskHandle_t xTask);
|
||||
|
||||
extern const char unknown_string_placeholder[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
120
lib/tools/trace.c
Normal file
120
lib/tools/trace.c
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <stdint.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"
|
||||
#include "esp_event.h"
|
||||
#include "tools.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
static const char TAG[] = "TRACE";
|
||||
// typedef struct mem_usage_trace_for_thread {
|
||||
// TaskHandle_t task;
|
||||
// size_t malloc_int_last;
|
||||
// size_t malloc_spiram_last;
|
||||
// size_t malloc_dma_last;
|
||||
// const char *name;
|
||||
// SLIST_ENTRY(mem_usage_trace_for_thread) next;
|
||||
// } mem_usage_trace_for_thread_t;
|
||||
|
||||
// static EXT_RAM_ATTR SLIST_HEAD(memtrace, mem_usage_trace_for_thread) s_memtrace;
|
||||
|
||||
// mem_usage_trace_for_thread_t* memtrace_get_thread_entry(TaskHandle_t task) {
|
||||
// if(!task) {
|
||||
// ESP_LOGE(TAG, "memtrace_get_thread_entry: task is NULL");
|
||||
// return NULL;
|
||||
// }
|
||||
// ESP_LOGD(TAG,"Looking for task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
|
||||
// mem_usage_trace_for_thread_t* it;
|
||||
// SLIST_FOREACH(it, &s_memtrace, next) {
|
||||
// if ( it->task == task ) {
|
||||
// ESP_LOGD(TAG,"Found task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
|
||||
// return it;
|
||||
// }
|
||||
// }
|
||||
// return NULL;
|
||||
// }
|
||||
// void memtrace_add_thread_entry(TaskHandle_t task) {
|
||||
// if(!task) {
|
||||
// ESP_LOGE(TAG, "memtrace_get_thread_entry: task is NULL");
|
||||
// return ;
|
||||
// }
|
||||
// mem_usage_trace_for_thread_t* it = memtrace_get_thread_entry(task);
|
||||
// if (it) {
|
||||
// ESP_LOGW(TAG, "memtrace_add_thread_entry: thread already in list");
|
||||
// return;
|
||||
// }
|
||||
// it = (mem_usage_trace_for_thread_t*)malloc_init_external(sizeof(mem_usage_trace_for_thread_t));
|
||||
// if (!it) {
|
||||
// ESP_LOGE(TAG, "memtrace_add_thread_entry: malloc failed");
|
||||
// return;
|
||||
// }
|
||||
// it->task = task;
|
||||
// it->malloc_int_last = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
// it->malloc_spiram_last = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
// it->malloc_dma_last = heap_caps_get_free_size(MALLOC_CAP_DMA);
|
||||
// it->name = pcTaskGetName(task);
|
||||
// SLIST_INSERT_HEAD(&s_memtrace, it, next);
|
||||
// return;
|
||||
// }
|
||||
// void memtrace_print_delta(){
|
||||
// TaskHandle_t task = xTaskGetCurrentTaskHandle();
|
||||
// mem_usage_trace_for_thread_t* it = memtrace_get_thread_entry(task);
|
||||
// if (!it) {
|
||||
// memtrace_add_thread_entry(task);
|
||||
// ESP_LOGW(TAG, "memtrace_print_delta: added new entry for task %s",STR_OR_ALT(pcTaskGetName(task ), "unknown"));
|
||||
// return;
|
||||
// }
|
||||
// size_t malloc_int_delta = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) - it->malloc_int_last;
|
||||
// size_t malloc_spiram_delta = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) - it->malloc_spiram_last;
|
||||
// size_t malloc_dma_delta = heap_caps_get_free_size(MALLOC_CAP_DMA) - it->malloc_dma_last;
|
||||
// ESP_LOG(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
|
||||
// heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
|
||||
// heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
|
||||
// heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
|
||||
// heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
|
||||
// heap_caps_get_free_size(MALLOC_CAP_DMA),
|
||||
// heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
|
||||
// ESP_LOGW(TAG, "memtrace_print_delta: %s: malloc_int_delta=%d, malloc_spiram_delta=%d, malloc_dma_delta=%d",
|
||||
// STR_OR_ALT(it->name, "unknown"),
|
||||
// malloc_int_delta,
|
||||
// malloc_spiram_delta,
|
||||
// malloc_dma_delta);
|
||||
// it->malloc_int_last = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
// it->malloc_spiram_last = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
// it->malloc_dma_last = heap_caps_get_free_size(MALLOC_CAP_DMA);
|
||||
|
||||
// }
|
||||
size_t malloc_int = 0;
|
||||
size_t malloc_spiram =0;
|
||||
size_t malloc_dma = 0;
|
||||
void memtrace_print_delta(const char * msg, const char * tag, const char * function){
|
||||
size_t malloc_int_delta = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) - malloc_int;
|
||||
size_t malloc_spiram_delta = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) - malloc_spiram;
|
||||
size_t malloc_dma_delta = heap_caps_get_free_size(MALLOC_CAP_DMA) - malloc_dma;
|
||||
ESP_LOGW(TAG, "Heap internal:%zu (min:%zu)(chg:%d)/external:%zu (min:%zu)(chg:%d)/dma:%zu (min:%zu)(chg:%d) : %s%s%s%s%s",
|
||||
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
|
||||
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
|
||||
malloc_int_delta,
|
||||
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
|
||||
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
|
||||
malloc_spiram_delta,
|
||||
heap_caps_get_free_size(MALLOC_CAP_DMA),
|
||||
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA),
|
||||
malloc_dma_delta,
|
||||
STR_OR_BLANK(tag),
|
||||
tag?" ":"",
|
||||
STR_OR_BLANK(function),
|
||||
function?" ":"",
|
||||
STR_OR_BLANK(msg)
|
||||
);
|
||||
malloc_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
malloc_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
malloc_dma = heap_caps_get_free_size(MALLOC_CAP_DMA);
|
||||
}
|
||||
20
lib/tools/trace.h
Normal file
20
lib/tools/trace.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Sebastien 2019
|
||||
* Philippe G. 2019, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ENABLE_MEMTRACE
|
||||
#define MEMTRACE_PRINT_DELTA() memtrace_print_delta(NULL,TAG,__FUNCTION__);
|
||||
#define MEMTRACE_PRINT_DELTA_MESSAGE(x) memtrace_print_delta(x,TAG,__FUNCTION__);
|
||||
#else
|
||||
#define MEMTRACE_PRINT_DELTA()
|
||||
#define MEMTRACE_PRINT_DELTA_MESSAGE(x) ESP_LOGD(TAG,"%s",x);
|
||||
#endif
|
||||
Reference in New Issue
Block a user