mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-03-21 13:59:25 +00:00
Compare commits
9 Commits
I2S-4MFlas
...
I2S-4MFlas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57cd86f538 | ||
|
|
ade446a102 | ||
|
|
10e36b0599 | ||
|
|
a4d2017a07 | ||
|
|
a16a1678e5 | ||
|
|
a39c4ab58f | ||
|
|
7dfab25cb4 | ||
|
|
df777e83d1 | ||
|
|
d0461d55e4 |
@@ -409,6 +409,7 @@ Wired ethernet is supported by esp32 with various options but squeezelite is onl
|
||||
| GPIO25 | RX0 | EMAC_RXD0 |
|
||||
| GPIO26 | RX1 | EMAC_RXD1 |
|
||||
| GPIO27 | CRS_DV | EMAC_RX_DRV |
|
||||
| GPIO0 | REF_CLK | 50MHz clock |
|
||||
|
||||
- SMI (Serial Management Interface) wiring is not fixed and you can change it either in the configuration or using "eth_config" parameter with the following syntax:
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@ idf_component_register(SRC_DIRS . core core/ifaces fonts
|
||||
INCLUDE_DIRS . fonts core
|
||||
REQUIRES platform_config tools esp_common
|
||||
PRIV_REQUIRES services freertos driver
|
||||
EMBED_FILES note.jpg
|
||||
)
|
||||
|
||||
set_source_files_properties(display.c
|
||||
|
||||
@@ -86,6 +86,10 @@ static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
|
||||
Device->WriteCommand( Device, Contrast );
|
||||
}
|
||||
|
||||
static void SPIParams(int Speed, uint8_t *mode, uint8_t *CS_pre, uint8_t *CS_post) {
|
||||
*CS_post = Speed / (8*1000*1000);
|
||||
}
|
||||
|
||||
static bool Init( struct GDS_Device* Device ) {
|
||||
#ifdef SHADOW_BUFFER
|
||||
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
|
||||
@@ -140,7 +144,7 @@ static const struct GDS_Device SH1106 = {
|
||||
.SetLayout = SetLayout,
|
||||
.Update = Update, .Init = Init,
|
||||
.Depth = 1,
|
||||
.CS_post = 2,
|
||||
.SPIParams = SPIParams,
|
||||
#if !defined SHADOW_BUFFER && defined USE_IRAM
|
||||
.Alloc = GDS_ALLOC_IRAM_SPI;
|
||||
#endif
|
||||
|
||||
@@ -235,12 +235,13 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
|
||||
ledc_update_duty( LEDC_HIGH_SPEED_MODE, Device->Backlight.Channel );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) { if (Device->SetLayout) Device->SetLayout( Device, HFlip, VFlip, Rotate ); }
|
||||
void GDS_SetDirty( struct GDS_Device* Device ) { Device->Dirty = true; }
|
||||
int GDS_GetWidth( struct GDS_Device* Device ) { return Device ? Device->Width : 0; }
|
||||
int GDS_GetHeight( struct GDS_Device* Device ) { return Device ? Device->Height : 0; }
|
||||
int GDS_GetDepth( struct GDS_Device* Device ) { return Device ? Device->Depth : 0; }
|
||||
int GDS_GetMode( struct GDS_Device* Device ) { return Device ? Device->Mode : 0; }
|
||||
int GDS_GetWidth( struct GDS_Device* Device ) { return Device ? Device->Width : 0; }
|
||||
void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth ) { Device->TextWidth = Device && TextWidth && TextWidth < Device->Width ? TextWidth : Device->Width; }
|
||||
int GDS_GetHeight( struct GDS_Device* Device ) { return Device ? Device->Height : 0; }
|
||||
int GDS_GetDepth( struct GDS_Device* Device ) { return Device ? Device->Depth : 0; }
|
||||
int GDS_GetMode( struct GDS_Device* Device ) { return Device ? Device->Mode : 0; }
|
||||
void GDS_DisplayOn( struct GDS_Device* Device ) { if (Device->DisplayOn) Device->DisplayOn( Device ); }
|
||||
void GDS_DisplayOff( struct GDS_Device* Device ) { if (Device->DisplayOff) Device->DisplayOff( Device ); }
|
||||
@@ -38,6 +38,7 @@ void GDS_Update( struct GDS_Device* Device );
|
||||
void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate );
|
||||
void GDS_SetDirty( struct GDS_Device* Device );
|
||||
int GDS_GetWidth( struct GDS_Device* Device );
|
||||
void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth );
|
||||
int GDS_GetHeight( struct GDS_Device* Device );
|
||||
int GDS_GetDepth( struct GDS_Device* Device );
|
||||
int GDS_GetMode( struct GDS_Device* Device );
|
||||
|
||||
@@ -73,13 +73,13 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y,
|
||||
CharStartY+= OffsetY;
|
||||
|
||||
/* Do not attempt to draw if this character is entirely offscreen */
|
||||
if ( CharEndX < 0 || CharStartX >= Device->Width || CharEndY < 0 || CharStartY >= Device->Height ) {
|
||||
if ( CharEndX < 0 || CharStartX >= Device->TextWidth || CharEndY < 0 || CharStartY >= Device->Height ) {
|
||||
ClipDebug( x, y );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do not attempt to draw past the end of the screen */
|
||||
CharEndX = ( CharEndX >= Device->Width ) ? Device->Width - 1 : CharEndX;
|
||||
CharEndX = ( CharEndX >= Device->TextWidth ) ? Device->TextWidth - 1 : CharEndX;
|
||||
CharEndY = ( CharEndY >= Device->Height ) ? Device->Height - 1 : CharEndY;
|
||||
Device->Dirty = true;
|
||||
|
||||
@@ -146,7 +146,7 @@ int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ) {
|
||||
}
|
||||
|
||||
int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display ) {
|
||||
return Display->Width / Display->Font->Width;
|
||||
return Display->TextWidth / Display->Font->Width;
|
||||
}
|
||||
|
||||
int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ) {
|
||||
@@ -210,7 +210,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
|
||||
switch ( Anchor ) {
|
||||
case TextAnchor_East: {
|
||||
*OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
|
||||
*OutX = ( Display->Width - StringWidth );
|
||||
*OutX = ( Display->TextWidth - StringWidth );
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -221,19 +221,19 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
|
||||
break;
|
||||
}
|
||||
case TextAnchor_North: {
|
||||
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
|
||||
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
|
||||
*OutY = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case TextAnchor_South: {
|
||||
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
|
||||
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
|
||||
*OutY = ( Display->Height - StringHeight );
|
||||
|
||||
break;
|
||||
}
|
||||
case TextAnchor_NorthEast: {
|
||||
*OutX = ( Display->Width - StringWidth );
|
||||
*OutX = ( Display->TextWidth - StringWidth );
|
||||
*OutY = 0;
|
||||
|
||||
break;
|
||||
@@ -246,7 +246,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
|
||||
}
|
||||
case TextAnchor_SouthEast: {
|
||||
*OutY = ( Display->Height - StringHeight );
|
||||
*OutX = ( Display->Width - StringWidth );
|
||||
*OutX = ( Display->TextWidth - StringWidth );
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int
|
||||
}
|
||||
case TextAnchor_Center: {
|
||||
*OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
|
||||
*OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
|
||||
*OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
|
||||
JpegCtx *Context = (JpegCtx*) Decoder->device;
|
||||
uint8_t *Pixels = (uint8_t*) Bitmap;
|
||||
int Shift = 8 - Context->Depth;
|
||||
|
||||
|
||||
// decoded image is RGB888, shift only make sense for grayscale
|
||||
if (Context->Mode == GDS_RGB888) {
|
||||
OUTHANDLERDIRECT(Scaler888, 0);
|
||||
@@ -167,7 +167,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
|
||||
static void* DecodeJPEG(uint8_t *Source, int *Width, int *Height, float Scale, bool SizeOnly, int RGB_Mode) {
|
||||
JDEC Decoder;
|
||||
JpegCtx Context;
|
||||
char *Scratch = calloc(SCRATCH_SIZE, 1);
|
||||
char *Scratch = malloc(SCRATCH_SIZE);
|
||||
|
||||
if (!Scratch) {
|
||||
ESP_LOGE(TAG, "Cannot allocate workspace");
|
||||
@@ -372,7 +372,7 @@ bool GDS_DrawJPEG(struct GDS_Device* Device, uint8_t *Source, int x, int y, int
|
||||
JDEC Decoder;
|
||||
JpegCtx Context;
|
||||
bool Ret = false;
|
||||
char *Scratch = calloc(SCRATCH_SIZE, 1);
|
||||
char *Scratch = malloc(SCRATCH_SIZE);
|
||||
|
||||
if (!Scratch) {
|
||||
ESP_LOGE(TAG, "Cannot allocate workspace");
|
||||
|
||||
@@ -86,7 +86,6 @@ struct GDS_Device {
|
||||
struct {
|
||||
spi_device_handle_t SPIHandle;
|
||||
int8_t CSPin;
|
||||
int8_t CS_pre, CS_post, SPI_mode;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -96,7 +95,7 @@ struct GDS_Device {
|
||||
const struct GDS_FontDef* Font;
|
||||
} Lines[MAX_LINES];
|
||||
|
||||
uint16_t Width;
|
||||
uint16_t Width, TextWidth;
|
||||
uint16_t Height;
|
||||
uint8_t Depth, Mode;
|
||||
|
||||
@@ -125,6 +124,8 @@ struct GDS_Device {
|
||||
// may provide for optimization
|
||||
void (*DrawRGB)( struct GDS_Device* Device, uint8_t *Image,int x, int y, int Width, int Height, int RGB_Mode );
|
||||
void (*ClearWindow)( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color );
|
||||
// may provide for tweaking
|
||||
void (*SPIParams)(int Speed, uint8_t *mode, uint8_t *CS_pre, uint8_t *CS_post);
|
||||
|
||||
// interface-specific methods
|
||||
WriteCommandProc WriteCommand;
|
||||
|
||||
@@ -99,13 +99,13 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
|
||||
Width = GDS_FontMeasureString( Device, Text );
|
||||
|
||||
// adjusting position, erase only EoL for rigth-justified
|
||||
if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1;
|
||||
else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2;
|
||||
if (Pos == GDS_TEXT_RIGHT) X = Device->TextWidth - Width - 1;
|
||||
else if (Pos == GDS_TEXT_CENTER) X = (Device->TextWidth - Width) / 2;
|
||||
|
||||
// erase if requested
|
||||
if (Attr & GDS_TEXT_CLEAR) {
|
||||
int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
|
||||
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++)
|
||||
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->TextWidth; c++)
|
||||
for (int y = Y_min; y < Y_max; y++)
|
||||
DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
|
||||
}
|
||||
@@ -118,7 +118,7 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
|
||||
Device->Dirty = true;
|
||||
if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
|
||||
|
||||
return Width + X < Device->Width;
|
||||
return Width + X < Device->TextWidth;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
@@ -145,7 +145,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
|
||||
|
||||
// we might already fit
|
||||
GDS_SetFont( Device, Device->Lines[N].Font );
|
||||
if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0;
|
||||
if (GDS_FontMeasureString( Device, String ) <= Device->TextWidth) return 0;
|
||||
|
||||
// add some space for better visual
|
||||
strncat(String, Space, Max-Len);
|
||||
@@ -156,7 +156,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
|
||||
Boundary = GDS_FontMeasureString( Device, String );
|
||||
|
||||
// add a full display width
|
||||
while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) {
|
||||
while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->TextWidth) {
|
||||
String[Len++] = String[Extra++];
|
||||
String[Len] = '\0';
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int
|
||||
Device->RSTPin = RSTPin;
|
||||
Device->Backlight.Pin = BacklightPin;
|
||||
Device->IF = GDS_IF_I2C;
|
||||
Device->Width = Width;
|
||||
Device->Width = Device->TextWidth = Width;
|
||||
Device->Height = Height;
|
||||
|
||||
if ( RSTPin >= 0 ) {
|
||||
|
||||
@@ -35,7 +35,7 @@ bool GDS_SPIInit( int SPI, int DC ) {
|
||||
}
|
||||
|
||||
bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed ) {
|
||||
spi_device_interface_config_t SPIDeviceConfig;
|
||||
spi_device_interface_config_t SPIDeviceConfig = { };
|
||||
spi_device_handle_t SPIDevice;
|
||||
|
||||
NullCheck( Device, return false );
|
||||
@@ -43,18 +43,15 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
|
||||
if (CSPin >= 0) {
|
||||
ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( CSPin, GPIO_MODE_OUTPUT ), return false );
|
||||
ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false );
|
||||
}
|
||||
}
|
||||
|
||||
memset( &SPIDeviceConfig, 0, sizeof( spi_device_interface_config_t ) );
|
||||
|
||||
SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
|
||||
SPIDeviceConfig.spics_io_num = CSPin;
|
||||
SPIDeviceConfig.queue_size = 1;
|
||||
SPIDeviceConfig.flags = SPI_DEVICE_NO_DUMMY;
|
||||
SPIDeviceConfig.cs_ena_pretrans = Device->CS_pre;
|
||||
SPIDeviceConfig.cs_ena_posttrans = Device->CS_post;
|
||||
SPIDeviceConfig.mode = Device->SPI_mode;
|
||||
|
||||
if (Device->SPIParams) Device->SPIParams(SPIDeviceConfig.clock_speed_hz, &SPIDeviceConfig.mode,
|
||||
&SPIDeviceConfig.cs_ena_pretrans, &SPIDeviceConfig.cs_ena_posttrans);
|
||||
|
||||
ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDevice ), return false );
|
||||
|
||||
Device->WriteCommand = SPIDefaultWriteCommand;
|
||||
@@ -64,7 +61,7 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
|
||||
Device->CSPin = CSPin;
|
||||
Device->Backlight.Pin = BackLightPin;
|
||||
Device->IF = GDS_IF_SPI;
|
||||
Device->Width = Width;
|
||||
Device->Width = Device->TextWidth = Width;
|
||||
Device->Height = Height;
|
||||
|
||||
if ( RSTPin >= 0 ) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "gds_draw.h"
|
||||
#include "gds_text.h"
|
||||
#include "gds_font.h"
|
||||
#include "gds_image.h"
|
||||
|
||||
static const char *TAG = "display";
|
||||
|
||||
@@ -30,6 +31,9 @@ static const char *TAG = "display";
|
||||
#define SCROLLABLE_SIZE 384
|
||||
#define HEADER_SIZE 64
|
||||
#define DEFAULT_SLEEP 3600
|
||||
#define ARTWORK_BORDER 1
|
||||
|
||||
extern const uint8_t default_artwork[] asm("_binary_note_jpg_start");
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
TaskHandle_t task;
|
||||
@@ -47,6 +51,13 @@ static EXT_RAM_ATTR struct {
|
||||
char string[8]; // H:MM:SS
|
||||
bool visible;
|
||||
} duration;
|
||||
struct {
|
||||
bool enable, active;
|
||||
bool fit;
|
||||
bool updated;
|
||||
int tick;
|
||||
int offset;
|
||||
} artwork;
|
||||
TickType_t tick;
|
||||
} displayer;
|
||||
|
||||
@@ -147,6 +158,14 @@ void display_init(char *welcome) {
|
||||
GDS_TextSetFontAuto(display, 2, GDS_FONT_LINE_2, -3);
|
||||
|
||||
displayer.metadata_config = config_alloc_get(NVS_TYPE_STR, "metadata_config");
|
||||
|
||||
// leave room for artwork is display is horizontal-style
|
||||
if (strcasestr(displayer.metadata_config, "artwork")) {
|
||||
displayer.artwork.enable = true;
|
||||
displayer.artwork.fit = true;
|
||||
if (height <= 64 && width > height * 2) displayer.artwork.offset = width - height - ARTWORK_BORDER;
|
||||
PARSE_PARAM(displayer.metadata_config, "artwork", ':', displayer.artwork.fit);
|
||||
}
|
||||
}
|
||||
|
||||
free(config);
|
||||
@@ -225,7 +244,12 @@ static void displayer_task(void *args) {
|
||||
// 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);
|
||||
|
||||
|
||||
// if we have not received artwork after 5s, display a default icon
|
||||
if (displayer.artwork.active && !displayer.artwork.updated && tick - displayer.artwork.tick > pdMS_TO_TICKS(5000)) {
|
||||
ESP_LOGI(TAG, "no artwork received, setting default");
|
||||
displayer_artwork((uint8_t*) default_artwork);
|
||||
}
|
||||
timer_sleep = 1000;
|
||||
} else timer_sleep = max(1000 - elapsed, 0);
|
||||
} else timer_sleep = DEFAULT_SLEEP;
|
||||
@@ -238,6 +262,25 @@ static void displayer_task(void *args) {
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void displayer_artwork(uint8_t *data) {
|
||||
if (!displayer.artwork.active) return;
|
||||
|
||||
int x = displayer.artwork.offset ? displayer.artwork.offset + ARTWORK_BORDER : 0;
|
||||
int y = x ? 0 : 32;
|
||||
GDS_ClearWindow(display, x, y, -1, -1, GDS_COLOR_BLACK);
|
||||
if (data) {
|
||||
displayer.artwork.updated = true;
|
||||
GDS_DrawJPEG(display, data, x, y, GDS_IMAGE_CENTER | (displayer.artwork.fit ? GDS_IMAGE_FIT : 0));
|
||||
} else {
|
||||
displayer.artwork.updated = false;
|
||||
displayer.artwork.tick = xTaskGetTickCount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
@@ -378,6 +421,7 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
|
||||
switch(cmd) {
|
||||
case DISPLAYER_ACTIVATE: {
|
||||
char *header = va_arg(args, char*);
|
||||
displayer.artwork.active = displayer.artwork.enable && va_arg(args, int);
|
||||
strncpy(displayer.header, header, HEADER_SIZE);
|
||||
displayer.header[HEADER_SIZE] = '\0';
|
||||
displayer.state = DISPLAYER_ACTIVE;
|
||||
@@ -388,16 +432,20 @@ void displayer_control(enum displayer_cmd_e cmd, ...) {
|
||||
displayer.duration.visible = false;
|
||||
displayer.offset = displayer.boundary = 0;
|
||||
display_bus(&displayer, DISPLAY_BUS_TAKE);
|
||||
if (displayer.artwork.active) GDS_SetTextWidth(display, displayer.artwork.offset);
|
||||
vTaskResume(displayer.task);
|
||||
break;
|
||||
}
|
||||
case DISPLAYER_SUSPEND:
|
||||
// task will display the line 2 from beginning and suspend
|
||||
displayer.state = DISPLAYER_IDLE;
|
||||
displayer_artwork(NULL);
|
||||
display_bus(&displayer, DISPLAY_BUS_GIVE);
|
||||
break;
|
||||
case DISPLAYER_SHUTDOWN:
|
||||
// let the task self-suspend (we might be doing i2c_write)
|
||||
GDS_SetTextWidth(display, 0);
|
||||
displayer_artwork(NULL);
|
||||
displayer.state = DISPLAYER_DOWN;
|
||||
display_bus(&displayer, DISPLAY_BUS_GIVE);
|
||||
break;
|
||||
|
||||
@@ -38,5 +38,6 @@ bool display_is_valid_driver(const char * driver);
|
||||
void displayer_scroll(char *string, int speed, int pause);
|
||||
void displayer_control(enum displayer_cmd_e cmd, ...);
|
||||
void displayer_metadata(char *artist, char *album, char *title);
|
||||
void displayer_artwork(uint8_t *data);
|
||||
void displayer_timer(enum displayer_time_e mode, int elapsed, int duration);
|
||||
char * display_get_supported_drivers(void);
|
||||
|
||||
BIN
components/display/note.jpg
Normal file
BIN
components/display/note.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -172,7 +172,7 @@ static bool cmd_handler(bt_sink_cmd_t cmd, ...) {
|
||||
// now handle events for display
|
||||
switch(cmd) {
|
||||
case BT_SINK_AUDIO_STARTED:
|
||||
displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH");
|
||||
displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH", false);
|
||||
break;
|
||||
case BT_SINK_AUDIO_STOPPED:
|
||||
displayer_control(DISPLAYER_SUSPEND);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "tcpip_adapter.h"
|
||||
@@ -99,8 +100,6 @@ static void initialise_wifi(void)
|
||||
return;
|
||||
}
|
||||
tcpip_adapter_init();
|
||||
// Now moved to esp_app_main: 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) );
|
||||
@@ -112,8 +111,12 @@ static void initialise_wifi(void)
|
||||
led_blink(LED_GREEN, 250, 250);
|
||||
}
|
||||
|
||||
static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
static void wifi_join(void *arg)
|
||||
{
|
||||
const char *ssid = join_args.ssid->sval[0];
|
||||
const char *pass = join_args.password->sval[0];
|
||||
int timeout_ms = join_args.timeout->ival[0];
|
||||
|
||||
initialise_wifi();
|
||||
wifi_config_t wifi_config = { 0 };
|
||||
strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
|
||||
@@ -129,7 +132,12 @@ static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
|
||||
|
||||
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||
pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
|
||||
return (bits & CONNECTED_BIT) != 0;
|
||||
|
||||
if (bits & CONNECTED_BIT) {
|
||||
ESP_LOGI(__func__, "Connected");
|
||||
} else {
|
||||
ESP_LOGW(__func__, "Connection timed out");
|
||||
}
|
||||
}
|
||||
|
||||
//static int set_auto_connect(int argc, char **argv)
|
||||
@@ -172,14 +180,9 @@ static int connect(int argc, char **argv)
|
||||
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");
|
||||
// need to use that trick to make sure we use internal stack
|
||||
xTimerStart(xTimerCreate("wifi_join", 1, pdFALSE, NULL, wifi_join), portMAX_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void register_wifi_join()
|
||||
|
||||
@@ -628,6 +628,9 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock)
|
||||
LOG_INFO("[%p]: received metadata", ctx);
|
||||
settings.ctx = &metadata;
|
||||
memset(&metadata, 0, sizeof(struct metadata_s));
|
||||
if (!dmap_parse(&settings, body, len)) {
|
||||
LOG_INFO("[%p]: received metadata\n\tartist: %s\n\talbum: %s\n\ttitle: %s",
|
||||
ctx, metadata.artist, metadata.album, metadata.title);
|
||||
success = ctx->cmd_cb(RAOP_METADATA, metadata.artist, metadata.album, metadata.title);
|
||||
free_metadata(&metadata);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "audio_controls.h"
|
||||
#include "display.h"
|
||||
#include "accessors.h"
|
||||
|
||||
#include "log_util.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -115,7 +114,7 @@ static bool cmd_handler(raop_event_t event, ...) {
|
||||
switch(event) {
|
||||
case RAOP_SETUP:
|
||||
actrls_set(controls, false, NULL, actrls_ir_action);
|
||||
displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY");
|
||||
displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY", true);
|
||||
break;
|
||||
case RAOP_PLAY:
|
||||
displayer_control(DISPLAYER_TIMER_RUN);
|
||||
@@ -130,8 +129,14 @@ static bool cmd_handler(raop_event_t event, ...) {
|
||||
case RAOP_METADATA: {
|
||||
char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*);
|
||||
displayer_metadata(artist, album, title);
|
||||
displayer_artwork(NULL);
|
||||
break;
|
||||
}
|
||||
case RAOP_ARTWORK: {
|
||||
uint8_t *data = va_arg(args, uint8_t*);
|
||||
displayer_artwork(data);
|
||||
break;
|
||||
}
|
||||
case RAOP_PROGRESS: {
|
||||
int elapsed = va_arg(args, int), duration = va_arg(args, int);
|
||||
displayer_timer(DISPLAYER_ELAPSED, elapsed, duration);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#define RAOP_SAMPLE_RATE 44100
|
||||
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
|
||||
typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_ARTWORK, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP,
|
||||
RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD,
|
||||
RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ;
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) {
|
||||
gpio_intr_enable(config->intr);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Create GPIO expander %s at base %u with INT %d at @%x on port/host %d/%d", config->model, config->base, config->intr, config->phy.addr, config->phy.port, config->phy.host);
|
||||
ESP_LOGI(TAG, "Create GPIO expander %s at base %u with intr %d at @%x on port/host %d/%d", config->model, config->base, config->intr, config->phy.addr, config->phy.port, config->phy.host);
|
||||
return expander;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ void services_init(void) {
|
||||
}
|
||||
|
||||
const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host);
|
||||
ESP_LOGI(TAG,"Configuring SPI data:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
||||
ESP_LOGI(TAG,"Configuring SPI mosi:%d miso:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->miso_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
||||
|
||||
if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
|
||||
spi_bus_initialize( spi_system_host, spi_config, 1 );
|
||||
|
||||
@@ -282,7 +282,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
|
||||
res = i2s_driver_install(CONFIG_I2S_NUM, &i2s_config, 0, NULL);
|
||||
res |= i2s_set_pin(CONFIG_I2S_NUM, &i2s_spdif_pin);
|
||||
LOG_INFO("SPDIF using I2S bck:%u, ws:%u, do:%u", i2s_spdif_pin.bck_io_num, i2s_spdif_pin.ws_io_num, i2s_spdif_pin.data_out_num);
|
||||
LOG_INFO("SPDIF using I2S bck:%d, ws:%d, do:%d", i2s_spdif_pin.bck_io_num, i2s_spdif_pin.ws_io_num, i2s_spdif_pin.data_out_num);
|
||||
} else {
|
||||
i2s_config.sample_rate = output.current_sample_rate;
|
||||
i2s_config.bits_per_sample = BYTES_PER_FRAME * 8 / 2;
|
||||
@@ -492,20 +492,7 @@ static void output_thread_i2s(void *arg) {
|
||||
_output_frames( iframes );
|
||||
// oframes must be a global updated by the write callback
|
||||
output.frames_in_process = oframes;
|
||||
|
||||
/*
|
||||
{
|
||||
ISAMPLE_T *ptr = (ISAMPLE_T*) obuf;
|
||||
for (int i = 0; i < oframes; i++) {
|
||||
*ptr++ = 0; // L
|
||||
#if BYTES_PER_FRAME == 8
|
||||
*ptr++ = rand() >> 4; // R
|
||||
#else
|
||||
*ptr++ = (rand() % 65536) >> 4; // R
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
SET_MIN_MAX_SIZED(oframes,rec,iframes);
|
||||
SET_MIN_MAX_SIZED(_buf_used(outputbuf),o,outputbuf->size);
|
||||
SET_MIN_MAX_SIZED(_buf_used(streambuf),s,streambuf->size);
|
||||
@@ -685,7 +672,7 @@ static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least
|
||||
audio is transmitted first (not the MSB) and that ESP32 libray sends R then L,
|
||||
contrary to what seems to be usually done, so (dst) order had to be changed
|
||||
*/
|
||||
void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
register u16_t hi, lo, aux;
|
||||
size_t cnt = *count;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user