From 975f34f01bfe68eb409ee1ce38f79da20af6c464 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Sat, 18 Dec 2021 15:20:22 -0800 Subject: [PATCH] Give some love to AIrPlay/BT screens + better "safe TCB release" - release --- components/display/core/gds_font.c | 6 ++- components/display/core/gds_font.h | 5 +- components/display/core/gds_text.c | 13 +++++ components/display/core/gds_text.h | 1 + components/display/display.c | 69 +++++++++++++++++++------- components/display/fonts/font_line_1.c | 2 +- components/raop/raop.c | 5 +- components/raop/rtp.c | 2 +- components/raop/util.h | 23 ++++++--- 9 files changed, 92 insertions(+), 34 deletions(-) diff --git a/components/display/core/gds_font.c b/components/display/core/gds_font.c index e22ebe28..0137b0f4 100644 --- a/components/display/core/gds_font.c +++ b/components/display/core/gds_font.c @@ -98,12 +98,14 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y, } } -bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) { +struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) { + const struct GDS_FontDef* OldFont = Display->Font; + Display->FontForceProportional = false; Display->FontForceMonospace = false; Display->Font = Font; - return true; + return OldFont; } void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) { diff --git a/components/display/core/gds_font.h b/components/display/core/gds_font.h index f80c9825..42875287 100644 --- a/components/display/core/gds_font.h +++ b/components/display/core/gds_font.h @@ -46,7 +46,7 @@ typedef enum { TextAnchor_Center } TextAnchor; -bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ); +struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ); void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ); void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force ); @@ -59,7 +59,8 @@ int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ); int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ); int GDS_FontGetCharHeight( struct GDS_Device* Display ); -int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );\ +int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text ); +int GDS_FontMeasureStringLine( struct GDS_Device* Display, int Line, const char* Text ); void GDS_FontDrawChar( struct GDS_Device* Display, char Character, int x, int y, int Color ); void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color ); diff --git a/components/display/core/gds_text.c b/components/display/core/gds_text.c index eab28883..e77999ca 100644 --- a/components/display/core/gds_text.c +++ b/components/display/core/gds_text.c @@ -121,6 +121,19 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex return Width + X < Device->Width; } +/**************************************************************************************** + * + */ +int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text) { + struct GDS_FontDef *Font = GDS_SetFont( Device, Device->Lines[N-1].Font ); + + if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true ); + int Width = GDS_FontMeasureString( Device, Text ); + GDS_SetFont( Device, Font ); + + return Width; +} + /**************************************************************************************** * Try to align string for better scrolling visual. there is probably much better to do */ diff --git a/components/display/core/gds_text.h b/components/display/core/gds_text.h index 3b888157..80d1a995 100644 --- a/components/display/core/gds_text.h +++ b/components/display/core/gds_text.h @@ -31,5 +31,6 @@ struct GDS_Device; bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space); bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space); bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text); +int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text); int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max); void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...); \ No newline at end of file diff --git a/components/display/display.c b/components/display/display.c index 657dd356..192c834a 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -41,7 +41,12 @@ static EXT_RAM_ATTR struct { int offset, boundary; char *metadata_config; bool timer, refresh; - uint32_t elapsed, duration; + uint32_t elapsed; + struct { + uint32_t value; + char string[8]; // H:MM:SS + bool visible; + } duration; TickType_t tick; } displayer; @@ -126,7 +131,7 @@ void display_init(char *welcome) { static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4))); - GDS_SetLayout( display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate")); + GDS_SetLayout(display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate")); GDS_SetFont(display, &Font_droid_sans_fallback_15x17 ); GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome); @@ -193,23 +198,34 @@ static void displayer_task(void *args) { // handler elapsed track time if (displayer.timer && displayer.state == DISPLAYER_ACTIVE) { - char line[20], duration[12] = ""; + char line[19] = "-", *_line = line + 1; // [-]H:MM:SS / H:MM:SS TickType_t tick = xTaskGetTickCount(); uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS; - + if (elapsed >= 1000) { xSemaphoreTake(displayer.mutex, portMAX_DELAY); displayer.tick = tick; - displayer.elapsed += elapsed / 1000; - xSemaphoreGive(displayer.mutex); - if (displayer.duration > 0) { - if (displayer.duration < 3600) snprintf(duration, sizeof(duration), " / %u:%02u", displayer.duration / 60, displayer.duration % 60); - else snprintf(duration, sizeof(duration), " / %u:%02u:%02u", (displayer.duration / 3600) % 100, (displayer.duration % 3600) / 60, displayer.duration % 60); - } - if (displayer.elapsed < 3600) snprintf(line, sizeof(line), "%*u:%02u", sizeof(line) - 1 - strlen(duration) - 3, displayer.elapsed / 60, displayer.elapsed % 60); - else snprintf(line, sizeof(line), "%*u:%02u:%02u", sizeof(line) - 1 - strlen(duration) - 6, (displayer.elapsed / 3600) % 100, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60); - strcat(line, duration); - GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, line); + elapsed = displayer.elapsed += elapsed / 1000; + xSemaphoreGive(displayer.mutex); + + // when we have duration but no space, display remaining time + if (displayer.duration.value && !displayer.duration.visible) elapsed = displayer.duration.value - elapsed; + + if (elapsed < 3600) sprintf(_line, "%u:%02u", elapsed / 60, elapsed % 60); + else sprintf(_line, "%u:%02u:%02u", (elapsed / 3600) % 100, (elapsed % 3600) / 60, elapsed % 60); + + // concatenate if we have room for elapsed / duration + if (displayer.duration.visible) { + strcat(_line, "/"); + strcat(_line, displayer.duration.string); + } else if (displayer.duration.value) { + _line--; + } + + // just re-write the whole line it's easier + GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, displayer.header); + GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line); + timer_sleep = 1000; } else timer_sleep = max(1000 - elapsed, 0); } else timer_sleep = DEFAULT_SLEEP; @@ -323,9 +339,27 @@ void displayer_timer(enum displayer_time_e mode, int elapsed, int duration) { xSemaphoreTake(displayer.mutex, portMAX_DELAY); - if (elapsed >= 0) displayer.elapsed = elapsed / 1000; - if (duration >= 0) displayer.duration = duration / 1000; if (displayer.timer) displayer.tick = xTaskGetTickCount(); + if (elapsed >= 0) displayer.elapsed = elapsed / 1000; + if (duration > 0) { + displayer.duration.visible = true; + displayer.duration.value = duration / 1000; + + if (displayer.duration.value > 3600) sprintf(displayer.duration.string, "%u:%02u:%02u", (displayer.duration.value / 3600) % 10, + (displayer.duration.value % 3600) / 60, displayer.duration.value % 60); + else sprintf(displayer.duration.string, "%u:%02u", displayer.duration.value / 60, displayer.duration.value % 60); + + char *buf; + asprintf(&buf, "%s %s/%s", displayer.header, displayer.duration.string, displayer.duration.string); + if (GDS_GetTextWidth(display, 1, 0, buf) > GDS_GetWidth(display)) { + ESP_LOGW(TAG, "Can't fit duration %s (%d) on screen using elapsed only", buf, GDS_GetTextWidth(display, 1, 0, buf)); + displayer.duration.visible = false; + } + free(buf); + } else if (!duration) { + displayer.duration.visible = false; + displayer.duration.value = 0; + } xSemaphoreGive(displayer.mutex); } @@ -350,7 +384,8 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { displayer.timer = false; displayer.refresh = true; displayer.string[0] = '\0'; - displayer.elapsed = displayer.duration = 0; + displayer.elapsed = displayer.duration.value = 0; + displayer.duration.visible = false; displayer.offset = displayer.boundary = 0; display_bus(&displayer, DISPLAY_BUS_TAKE); vTaskResume(displayer.task); diff --git a/components/display/fonts/font_line_1.c b/components/display/fonts/font_line_1.c index 1047bcdf..7f967418 100644 --- a/components/display/fonts/font_line_1.c +++ b/components/display/fonts/font_line_1.c @@ -26,7 +26,7 @@ static const uint8_t Square721_BT11x14[] = { 0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char , 0x04, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char . - 0x04, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char / + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x80, 0x03, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char / 0x08, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 0 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x04, 0x08, 0x04, 0xF8, 0x07, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 1 0x08, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x08, 0x05, 0x88, 0x04, 0x88, 0x04, 0x88, 0x04, 0x70, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char 2 diff --git a/components/raop/raop.c b/components/raop/raop.c index 23032502..e419736d 100644 --- a/components/raop/raop.c +++ b/components/raop/raop.c @@ -255,7 +255,7 @@ void raop_delete(struct raop_ctx_s *ctx) { vTaskDelay(100 / portTICK_PERIOD_MS); ulTaskNotifyTake(pdFALSE, portMAX_DELAY); vTaskDelete(ctx->thread); - SAFE_TCB_FREE(ctx->xTaskBuffer); + SAFE_PTR_FREE(ctx->xTaskBuffer); // cleanup all session-created items cleanup_rtsp(ctx, true); @@ -607,7 +607,6 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock) sscanf(p, "%*[^:]:%u/%u/%u", &start, ¤t, &stop); current = ((current - start) / 44100) * 1000; if (stop) stop = ((stop - start) / 44100) * 1000; - else stop = -1; LOG_INFO("[%p]: SET PARAMETER progress %d/%u %s", ctx, current, stop, p); success = ctx->cmd_cb(RAOP_PROGRESS, max(current, 0), stop); } else if (body && ((p = kd_lookup(headers, "Content-Type")) != NULL) && !strcasecmp(p, "application/x-dmap-tagged")) { @@ -674,7 +673,7 @@ void cleanup_rtsp(raop_ctx_t *ctx, bool abort) { ctx->active_remote.running = false; xSemaphoreTake(ctx->active_remote.destroy_mutex, portMAX_DELAY); vTaskDelete(ctx->active_remote.thread); - SAFE_TCB_FREE(ctx->active_remote.xTaskBuffer); + SAFE_PTR_FREE(ctx->active_remote.xTaskBuffer); vSemaphoreDelete(ctx->active_remote.thread); #endif memset(&ctx->active_remote, 0, sizeof(ctx->active_remote)); diff --git a/components/raop/rtp.c b/components/raop/rtp.c index e332bd27..11218483 100644 --- a/components/raop/rtp.c +++ b/components/raop/rtp.c @@ -313,7 +313,7 @@ void rtp_end(rtp_t *ctx) #else ulTaskNotifyTake(pdFALSE, portMAX_DELAY); vTaskDelete(ctx->thread); - SAFE_TCB_FREE(ctx->xTaskBuffer); + SAFE_PTR_FREE(ctx->xTaskBuffer); #endif } diff --git a/components/raop/util.h b/components/raop/util.h index 2ea5d8f0..94001895 100644 --- a/components/raop/util.h +++ b/components/raop/util.h @@ -18,6 +18,11 @@ #include "platform.h" #include "pthread.h" +#ifndef WIN32 +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" +#endif + #define NFREE(p) if (p) { free(p); p = NULL; } typedef struct metadata_s { @@ -46,19 +51,21 @@ char *strndup(const char *s, size_t n); int asprintf(char **strp, const char *fmt, ...); void winsock_init(void); void winsock_close(void); - #else +#define SAFE_PTR_FREE(P) free(P) #else char *strlwr(char *str); // reason is that TCB might be cleanup in idle task -#define SAFE_TCB_FREE(T) \ +#define SAFE_PTR_FREE(P) \ do { \ - int priority = uxTaskPriorityGet(NULL); \ - vTaskPrioritySet(NULL, tskIDLE_PRIORITY); \ - vTaskDelay(1); \ - vTaskPrioritySet(NULL, priority); \ - heap_caps_free(T); \ - } while (0) + TimerHandle_t timer = xTimerCreate("cleanup", pdMS_TO_TICKS(5000), pdFALSE, P, _delayed_free); \ + xTimerStart(timer, portMAX_DELAY); \ + } while (0) +static void inline _delayed_free(TimerHandle_t xTimer) { + free(pvTimerGetTimerID(xTimer)); + xTimerDelete(xTimer, portMAX_DELAY); +} #endif + char* strextract(char *s1, char *beg, char *end); in_addr_t get_localhost(char **name); void get_mac(u8_t mac[]);