Give some love to AIrPlay/BT screens + better "safe TCB release" - release

This commit is contained in:
Philippe G
2021-12-18 15:20:22 -08:00
parent f872623785
commit 975f34f01b
9 changed files with 92 additions and 34 deletions

View File

@@ -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->FontForceProportional = false;
Display->FontForceMonospace = false; Display->FontForceMonospace = false;
Display->Font = Font; Display->Font = Font;
return true; return OldFont;
} }
void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) { void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) {

View File

@@ -46,7 +46,7 @@ typedef enum {
TextAnchor_Center TextAnchor_Center
} TextAnchor; } 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_FontForceProportional( struct GDS_Device* Display, bool Force );
void GDS_FontForceMonospace( 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_FontGetCharWidth( struct GDS_Device* Display, char Character );
int GDS_FontGetCharHeight( struct GDS_Device* Display ); 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_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 ); void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color );

View File

@@ -121,6 +121,19 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
return Width + X < Device->Width; 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 * Try to align string for better scrolling visual. there is probably much better to do
*/ */

View File

@@ -31,5 +31,6 @@ struct GDS_Device;
bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space); 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_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); 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); 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, ...); void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...);

View File

@@ -41,7 +41,12 @@ static EXT_RAM_ATTR struct {
int offset, boundary; int offset, boundary;
char *metadata_config; char *metadata_config;
bool timer, refresh; 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; TickType_t tick;
} displayer; } displayer;
@@ -126,7 +131,7 @@ void display_init(char *welcome) {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __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_SetFont(display, &Font_droid_sans_fallback_15x17 );
GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome); 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 // handler elapsed track time
if (displayer.timer && displayer.state == DISPLAYER_ACTIVE) { 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(); TickType_t tick = xTaskGetTickCount();
uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS; uint32_t elapsed = (tick - displayer.tick) * portTICK_PERIOD_MS;
if (elapsed >= 1000) { if (elapsed >= 1000) {
xSemaphoreTake(displayer.mutex, portMAX_DELAY); xSemaphoreTake(displayer.mutex, portMAX_DELAY);
displayer.tick = tick; displayer.tick = tick;
displayer.elapsed += elapsed / 1000; elapsed = displayer.elapsed += elapsed / 1000;
xSemaphoreGive(displayer.mutex); xSemaphoreGive(displayer.mutex);
if (displayer.duration > 0) {
if (displayer.duration < 3600) snprintf(duration, sizeof(duration), " / %u:%02u", displayer.duration / 60, displayer.duration % 60); // when we have duration but no space, display remaining time
else snprintf(duration, sizeof(duration), " / %u:%02u:%02u", (displayer.duration / 3600) % 100, (displayer.duration % 3600) / 60, displayer.duration % 60); 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--;
} }
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); // just re-write the whole line it's easier
strcat(line, duration); GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, displayer.header);
GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, line); GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line);
timer_sleep = 1000; timer_sleep = 1000;
} else timer_sleep = max(1000 - elapsed, 0); } else timer_sleep = max(1000 - elapsed, 0);
} else timer_sleep = DEFAULT_SLEEP; } 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); 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 (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); xSemaphoreGive(displayer.mutex);
} }
@@ -350,7 +384,8 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
displayer.timer = false; displayer.timer = false;
displayer.refresh = true; displayer.refresh = true;
displayer.string[0] = '\0'; displayer.string[0] = '\0';
displayer.elapsed = displayer.duration = 0; displayer.elapsed = displayer.duration.value = 0;
displayer.duration.visible = false;
displayer.offset = displayer.boundary = 0; displayer.offset = displayer.boundary = 0;
display_bus(&displayer, DISPLAY_BUS_TAKE); display_bus(&displayer, DISPLAY_BUS_TAKE);
vTaskResume(displayer.task); vTaskResume(displayer.task);

View File

@@ -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 , 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 - 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 . 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, 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, 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 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

View File

@@ -255,7 +255,7 @@ void raop_delete(struct raop_ctx_s *ctx) {
// brute-force exit of accept() // brute-force exit of accept()
shutdown(ctx->sock, SHUT_RDWR); shutdown(ctx->sock, SHUT_RDWR);
closesocket(ctx->sock); closesocket(ctx->sock);
// wait to make sure LWIP if scheduled (avoid issue with NotifyTake) // wait to make sure LWIP if scheduled (avoid issue with NotifyTake)
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);
@@ -607,7 +607,6 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
volume = (volume == -144.0) ? 0 : (1 + volume / 30); volume = (volume == -144.0) ? 0 : (1 + volume / 30);
success = ctx->cmd_cb(RAOP_VOLUME, volume); success = ctx->cmd_cb(RAOP_VOLUME, volume);
} else if (body && (p = strcasestr(body, "progress")) != NULL) { } else if (body && (p = strcasestr(body, "progress")) != NULL) {
int start, current, stop = 0;
int start, current, stop = 0; int start, current, stop = 0;
// we want ms, not s // we want ms, not s
@@ -674,7 +673,7 @@ void cleanup_rtsp(raop_ctx_t *ctx, bool abort) {
if (ctx->active_remote.running) { if (ctx->active_remote.running) {
#ifdef WIN32 #ifdef WIN32
pthread_join(ctx->active_remote.thread, NULL); pthread_join(ctx->active_remote.thread, NULL);
close_mDNS(ctx->active_remote.handle); close_mDNS(ctx->active_remote.handle);
#else #else
// need to make sure no search is on-going and reclaim task memory // need to make sure no search is on-going and reclaim task memory
ctx->active_remote.running = false; ctx->active_remote.running = false;

View File

@@ -313,7 +313,7 @@ void rtp_end(rtp_t *ctx)
#else #else
ulTaskNotifyTake(pdFALSE, portMAX_DELAY); ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
vTaskDelete(ctx->thread); vTaskDelete(ctx->thread);
SAFE_TCB_FREE(ctx->xTaskBuffer); SAFE_PTR_FREE(ctx->xTaskBuffer);
#endif #endif
} }

View File

@@ -18,6 +18,11 @@
#include "platform.h" #include "platform.h"
#include "pthread.h" #include "pthread.h"
#ifndef WIN32
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
#endif
#define NFREE(p) if (p) { free(p); p = NULL; } #define NFREE(p) if (p) { free(p); p = NULL; }
typedef struct metadata_s { typedef struct metadata_s {
@@ -46,19 +51,21 @@ char *strndup(const char *s, size_t n);
char *strndup(const char *s, size_t n); char *strndup(const char *s, size_t n);
int asprintf(char **strp, const char *fmt, ...); int asprintf(char **strp, const char *fmt, ...);
void winsock_init(void); void winsock_init(void);
void winsock_close(void); void winsock_close(void);
#define SAFE_PTR_FREE(P) free(P) #define SAFE_PTR_FREE(P) free(P)
#else #else
char *strlwr(char *str); char *strlwr(char *str);
// reason is that TCB might be cleanup in idle task // reason is that TCB might be cleanup in idle task
#define SAFE_TCB_FREE(T) \ #define SAFE_PTR_FREE(P) \
do { \ do { \
int priority = uxTaskPriorityGet(NULL); \
vTaskPrioritySet(NULL, tskIDLE_PRIORITY); \
vTaskDelay(1); \
TimerHandle_t timer = xTimerCreate("cleanup", pdMS_TO_TICKS(5000), pdFALSE, P, _delayed_free); \ 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); xTimerDelete(xTimer, portMAX_DELAY);
}
#endif #endif
char* strextract(char *s1, char *beg, char *end); char* strextract(char *s1, char *beg, char *end);