mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 03:57:07 +03:00
refactor display
- part of components - separation between LMS & driver - move slimp message to squeezelite
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
#
|
|
||||||
# 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 += -I$(COMPONENT_PATH)/../squeezelite
|
|
||||||
COMPONENT_SRCDIRS := . tarablessd1306 tarablessd1306/fonts tarablessd1306/ifaces
|
|
||||||
COMPONENT_ADD_INCLUDEDIRS := .
|
|
||||||
COMPONENT_ADD_INCLUDEDIRS += ./tarablessd1306
|
|
||||||
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* (c) 2004,2006 Richard Titmuss for SlimProtoLib
|
|
||||||
* (c) 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "embedded.h"
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
static const char *TAG = "display";
|
|
||||||
|
|
||||||
static bool (*slimp_handler_chain)(u8_t *data, int len);
|
|
||||||
static struct display_handle_s *handle;
|
|
||||||
static void (*chained_notify)(in_addr_t ip, u16_t hport, u16_t cport);
|
|
||||||
|
|
||||||
static void server_attach(in_addr_t ip, u16_t hport, u16_t cport);
|
|
||||||
static bool display_handler(u8_t *data, int len);
|
|
||||||
|
|
||||||
/* scrolling undocumented information
|
|
||||||
grfs
|
|
||||||
B: screen number
|
|
||||||
B:1 = left, 2 = right,
|
|
||||||
Q: scroll pause once done (ms)
|
|
||||||
Q: scroll speed (ms)
|
|
||||||
W: # of pixels to scroll each time
|
|
||||||
W: 0 = continue scrolling after pause, 1 = scroll to scrollend and then stop, 2 = scroll to scrollend and then end animation (causing new update)
|
|
||||||
W: width of total scroll area in pixels
|
|
||||||
|
|
||||||
grfd
|
|
||||||
W: screen number
|
|
||||||
W: width of scrollable area in pixels
|
|
||||||
|
|
||||||
ANIC flags
|
|
||||||
ANIM_TRANSITION 0x01 # A transition animation has finished
|
|
||||||
ANIM_SCROLL_ONCE 0x02 # A scrollonce has finished
|
|
||||||
ANIM_SCREEN_1 0x04 # For scrollonce only, screen 1 was scrolling
|
|
||||||
ANIM_SCREEN_2 0x08 # For scrollonce only, screen 2 was scrolling
|
|
||||||
*/
|
|
||||||
|
|
||||||
/****************************************************************************************
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void display_init(char *welcome) {
|
|
||||||
char *item = config_alloc_get(NVS_TYPE_STR, "display_config");
|
|
||||||
|
|
||||||
if (item && *item) {
|
|
||||||
char * drivername=strstr(item,"driver");
|
|
||||||
if (!drivername || (drivername && strcasestr(drivername,"SSD1306"))) {
|
|
||||||
handle = &SSD1306_handle;
|
|
||||||
if (handle->init(item, welcome)) {
|
|
||||||
slimp_handler_chain = slimp_handler;
|
|
||||||
slimp_handler = display_handler;
|
|
||||||
ESP_LOGI(TAG, "Display initialization successful");
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "Display initialization failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG,"Unknown display driver name in display config: %s",item);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "no display");
|
|
||||||
}
|
|
||||||
|
|
||||||
chained_notify = server_notify;
|
|
||||||
server_notify = server_attach;
|
|
||||||
|
|
||||||
if (item) free(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void server_attach(in_addr_t ip, u16_t hport, u16_t cport) {
|
|
||||||
char msg[32];
|
|
||||||
sprintf(msg, "%s:%hu", inet_ntoa(ip), hport);
|
|
||||||
handle->print_message(msg);
|
|
||||||
if (chained_notify) (*chained_notify)(ip, hport, cport);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
|
||||||
* Process graphic display data
|
|
||||||
*/
|
|
||||||
static bool display_handler(u8_t *data, int len){
|
|
||||||
bool res = true;
|
|
||||||
|
|
||||||
if (!strncmp((char*) data, "vfdc", 4)) {
|
|
||||||
handle->vfdc_handler(data, len);
|
|
||||||
} else if (!strncmp((char*) data, "grfe", 4)) {
|
|
||||||
handle->grfe_handler(data, len);
|
|
||||||
} else if (!strncmp((char*) data, "grfb", 4)) {
|
|
||||||
handle->grfb_handler(data, len);
|
|
||||||
} else {
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// chain protocol handlers (bitwise or is fine)
|
|
||||||
if (*slimp_handler_chain) res |= (*slimp_handler_chain)(data, len);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Get stored id
|
* Get stored id
|
||||||
*/
|
*/
|
||||||
void button_get_client(int gpio) {
|
void *button_get_client(int gpio) {
|
||||||
for (int i = 0; i < n_buttons; i++) {
|
for (int i = 0; i < n_buttons; i++) {
|
||||||
if (buttons[i].gpio == gpio) return buttons[i].client;
|
if (buttons[i].gpio == gpio) return buttons[i].client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ NOTE: shifter buttons *must* be created before shiftee
|
|||||||
|
|
||||||
void button_create(void *client, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio);
|
void button_create(void *client, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio);
|
||||||
void *button_remap(void *client, int gpio, button_handler handler, int long_press, int shifter_gpio);
|
void *button_remap(void *client, int gpio, button_handler handler, int long_press, int shifter_gpio);
|
||||||
void button_get_client(int gpio);
|
void *button_get_client(int gpio);
|
||||||
|
|||||||
@@ -7,4 +7,7 @@
|
|||||||
# please read the SDK documents if you need to do this.
|
# please read the SDK documents if you need to do this.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
COMPONENT_SRCDIRS := . tarablessd1306 tarablessd1306/fonts tarablessd1306/ifaces
|
||||||
COMPONENT_ADD_INCLUDEDIRS := .
|
COMPONENT_ADD_INCLUDEDIRS := .
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS := .
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS += ./tarablessd1306
|
||||||
|
|||||||
58
components/services/display.c
Normal file
58
components/services/display.c
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* (c) 2004,2006 Richard Titmuss for SlimProtoLib
|
||||||
|
* (c) 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
// here we should include all possible drivers
|
||||||
|
extern struct display_s SSD1306_display;
|
||||||
|
|
||||||
|
struct display_s *display;
|
||||||
|
|
||||||
|
static const char *TAG = "display";
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void display_init(char *welcome) {
|
||||||
|
char *item = config_alloc_get(NVS_TYPE_STR, "display_config");
|
||||||
|
|
||||||
|
if (item && *item) {
|
||||||
|
char * drivername=strstr(item,"driver");
|
||||||
|
if (!drivername || (drivername && strcasestr(drivername,"SSD1306"))) {
|
||||||
|
display = &SSD1306_display;
|
||||||
|
if (display->init(item, welcome)) {
|
||||||
|
ESP_LOGI(TAG, "Display initialization successful");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Display initialization failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG,"Unknown display driver name in display config: %s",item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "no display");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item) free(item);
|
||||||
|
}
|
||||||
@@ -18,16 +18,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct display_handle_s {
|
#define DISPLAY_CLEAR 0x01
|
||||||
bool (*init)(char *config, char* welcome);
|
#define DISPLAY_UPDATE 0x02
|
||||||
void (*print_message)(char *msg);
|
|
||||||
void (*vfdc_handler)(u8_t *data, int len);
|
|
||||||
void (*grfe_handler)(u8_t *data, int len);
|
|
||||||
void (*grfb_handler)(u8_t *data, int len);
|
|
||||||
void (*visu_handler)(u8_t *data, int len);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct display_handle_s SSD1306_handle;
|
|
||||||
|
|
||||||
|
|
||||||
|
enum display_pos_e { DISPLAY_TOP_LEFT, DISPLAY_MIDDLE_LEFT, DISPLAY_BOTTOM_LEFT, DISPLAY_CENTER };
|
||||||
|
|
||||||
|
extern struct display_s {
|
||||||
|
bool (*init)(char *config, char *welcome);
|
||||||
|
void (*on)(bool state);
|
||||||
|
void (*brightness)(u8_t level);
|
||||||
|
void (*text)(enum display_pos_e pos, int attribute, char *msg);
|
||||||
|
void (*update)(void);
|
||||||
|
void (*v_draw)(u8_t *data);
|
||||||
|
} *display;
|
||||||
@@ -31,24 +31,21 @@
|
|||||||
#include "ssd1306_default_if.h"
|
#include "ssd1306_default_if.h"
|
||||||
|
|
||||||
#define I2C_ADDRESS 0x3C
|
#define I2C_ADDRESS 0x3C
|
||||||
#define LINELEN 40
|
|
||||||
static const char *TAG = "display";
|
static const char *TAG = "display";
|
||||||
|
|
||||||
static void vfdc_handler( u8_t *_data, int bytes_read);
|
// handlers
|
||||||
static void grfe_handler( u8_t *data, int len);
|
static bool init(char *config, char *welcome);
|
||||||
static void grfb_handler( u8_t *data, int len);
|
static void text(enum display_pos_e pos, int attribute, char *text);
|
||||||
static bool display_init(char *config, char *welcome);
|
static void v_draw(u8_t *data);
|
||||||
static void print_message(char *msg);
|
static void brightness(u8_t level);
|
||||||
|
static void on(bool state);
|
||||||
|
static void update(void);
|
||||||
|
|
||||||
struct display_handle_s SSD1306_handle = {
|
// display structure for others to use
|
||||||
display_init,
|
struct display_s SSD1306_display = { init, on, brightness, text, update, v_draw, NULL };
|
||||||
print_message,
|
|
||||||
vfdc_handler,
|
|
||||||
grfe_handler,
|
|
||||||
grfb_handler,
|
|
||||||
NULL, NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// SSD1306 specific function
|
||||||
static struct SSD1306_Device Display;
|
static struct SSD1306_Device Display;
|
||||||
static SSD1306_AddressMode AddressMode = AddressMode_Invalid;
|
static SSD1306_AddressMode AddressMode = AddressMode_Invalid;
|
||||||
|
|
||||||
@@ -75,11 +72,11 @@ static const unsigned char BitReverseTable256[] =
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static bool display_init(char *config, char *welcome) {
|
static bool init(char *config, char *welcome) {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
if (strstr(config, "I2C")) {
|
if (strstr(config, "I2C")) {
|
||||||
int width = -1, height = -1, address=I2C_ADDRESS;
|
int width = -1, height = -1, address = I2C_ADDRESS;
|
||||||
char *p;
|
char *p;
|
||||||
ESP_LOGI(TAG, "Initializing I2C display with config: %s",config);
|
ESP_LOGI(TAG, "Initializing I2C display with config: %s",config);
|
||||||
// no time for smart parsing - this is for tinkerers
|
// no time for smart parsing - this is for tinkerers
|
||||||
@@ -87,14 +84,13 @@ static bool display_init(char *config, char *welcome) {
|
|||||||
if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
|
||||||
|
|
||||||
|
|
||||||
if (width != -1 && height != -1) {
|
if (width != -1 && height != -1) {
|
||||||
SSD1306_I2CMasterInitDefault( i2c_system_port, -1, -1 ) ;
|
SSD1306_I2CMasterInitDefault( i2c_system_port, -1, -1 ) ;
|
||||||
SSD1306_I2CMasterAttachDisplayDefault( &Display, width, height, address, -1 );
|
SSD1306_I2CMasterAttachDisplayDefault( &Display, width, height, address, -1 );
|
||||||
SSD1306_SetHFlip( &Display, strcasestr(config, "HFlip") ? true : false);
|
SSD1306_SetHFlip( &Display, strcasestr(config, "HFlip") ? true : false);
|
||||||
SSD1306_SetVFlip( &Display, strcasestr(config, "VFlip") ? true : false);
|
SSD1306_SetVFlip( &Display, strcasestr(config, "VFlip") ? true : false);
|
||||||
SSD1306_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
SSD1306_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
||||||
print_message(welcome);
|
text(DISPLAY_CENTER, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
|
||||||
ESP_LOGI(TAG, "Initialized I2C display %dx%d", width, height);
|
ESP_LOGI(TAG, "Initialized I2C display %dx%d", width, height);
|
||||||
res = true;
|
res = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -110,147 +106,43 @@ static bool display_init(char *config, char *welcome) {
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void print_message(char *msg) {
|
static void text(enum display_pos_e pos, int attribute, char *text) {
|
||||||
if (!msg) return;
|
TextAnchor Anchor = TextAnchor_Center;
|
||||||
SSD1306_AddressMode Mode = AddressMode;
|
|
||||||
SSD1306_Clear( &Display, SSD_COLOR_BLACK );
|
|
||||||
SSD1306_SetDisplayAddressMode( &Display, AddressMode_Horizontal );
|
|
||||||
SSD1306_FontDrawAnchoredString( &Display, TextAnchor_Center, msg, SSD_COLOR_WHITE );
|
|
||||||
SSD1306_Update( &Display );
|
|
||||||
SSD1306_SetDisplayAddressMode( &Display, Mode );
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
if (attribute & DISPLAY_CLEAR) SSD1306_Clear( &Display, SSD_COLOR_BLACK );
|
||||||
* Change special LCD chars to something more printable on screen
|
|
||||||
*/
|
if (!text) return;
|
||||||
static void makeprintable(unsigned char * line) {
|
|
||||||
for (int n = 0; n < LINELEN; n++) {
|
switch(pos) {
|
||||||
switch (line[n]) {
|
case DISPLAY_TOP_LEFT:
|
||||||
case 11: /* block */
|
Anchor = TextAnchor_NorthWest;
|
||||||
line[n] = '#';
|
break;
|
||||||
break;;
|
case DISPLAY_MIDDLE_LEFT:
|
||||||
case 16: /* rightarrow */
|
break;
|
||||||
line[n] = '>';
|
case DISPLAY_BOTTOM_LEFT:
|
||||||
break;;
|
Anchor = TextAnchor_SouthWest;
|
||||||
case 22: /* circle */
|
break;
|
||||||
line[n] = '@';
|
case DISPLAY_CENTER:
|
||||||
break;;
|
Anchor = TextAnchor_Center;
|
||||||
case 145: /* note */
|
break;
|
||||||
line[n] = ' ';
|
|
||||||
break;;
|
|
||||||
case 152: /* bell */
|
|
||||||
line[n] = 'o';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
ESP_LOGD(TAG, "SSDD1306 displaying %s at %u with attribute %u", text, Anchor, attribute);
|
||||||
* Check if char is printable, or a valid symbol
|
|
||||||
*/
|
|
||||||
static bool charisok(unsigned char c) {
|
|
||||||
switch (c) {
|
|
||||||
case 11: /* block */
|
|
||||||
case 16: /* rightarrow */
|
|
||||||
case 22: /* circle */
|
|
||||||
case 145: /* note */
|
|
||||||
case 152: /* bell */
|
|
||||||
return true;
|
|
||||||
break;;
|
|
||||||
default:
|
|
||||||
return isprint(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
|
||||||
* Show the display (text mode)
|
|
||||||
*/
|
|
||||||
static void show_display_buffer(char *ddram) {
|
|
||||||
char line1[LINELEN+1];
|
|
||||||
char *line2;
|
|
||||||
|
|
||||||
memset(line1, 0, LINELEN+1);
|
|
||||||
strncpy(line1, ddram, LINELEN);
|
|
||||||
line2 = &(ddram[LINELEN]);
|
|
||||||
line2[LINELEN] = '\0';
|
|
||||||
|
|
||||||
/* Convert special LCD chars */
|
|
||||||
makeprintable((unsigned char *)line1);
|
|
||||||
makeprintable((unsigned char *)line2);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "\n\t%.40s\n\t%.40s", line1, line2);
|
|
||||||
|
|
||||||
SSD1306_Clear( &Display, SSD_COLOR_BLACK );
|
|
||||||
SSD1306_FontDrawAnchoredString( &Display, TextAnchor_NorthWest, line1, SSD_COLOR_WHITE );
|
|
||||||
SSD1306_FontDrawAnchoredString( &Display, TextAnchor_SouthWest, line2, SSD_COLOR_WHITE );
|
|
||||||
|
|
||||||
// check addressing mode by rows
|
|
||||||
if (AddressMode != AddressMode_Horizontal) {
|
if (AddressMode != AddressMode_Horizontal) {
|
||||||
AddressMode = AddressMode_Horizontal;
|
AddressMode = AddressMode_Horizontal;
|
||||||
SSD1306_SetDisplayAddressMode( &Display, AddressMode );
|
SSD1306_SetDisplayAddressMode( &Display, AddressMode );
|
||||||
}
|
}
|
||||||
|
SSD1306_FontDrawAnchoredString( &Display, Anchor, text, SSD_COLOR_WHITE );
|
||||||
SSD1306_Update( &Display );
|
if (attribute & DISPLAY_UPDATE) SSD1306_Update( &Display );
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************
|
|
||||||
* Process display data
|
|
||||||
*/
|
|
||||||
static void vfdc_handler( u8_t *_data, int bytes_read) {
|
|
||||||
unsigned short *data = (unsigned short*) _data, *display_data;
|
|
||||||
char ddram[(LINELEN + 1) * 2];
|
|
||||||
int n, addr = 0; /* counter */
|
|
||||||
|
|
||||||
bytes_read -= 4;
|
|
||||||
if (bytes_read % 2) bytes_read--; /* even number of bytes */
|
|
||||||
// if we use Noritake VFD codes, display data starts at 12
|
|
||||||
display_data = &(data[5]); /* display data starts at byte 10 */
|
|
||||||
|
|
||||||
memset(ddram, ' ', LINELEN * 2);
|
|
||||||
|
|
||||||
for (n = 0; n < (bytes_read/2); n++) {
|
|
||||||
unsigned short d; /* data element */
|
|
||||||
unsigned char t, c;
|
|
||||||
|
|
||||||
d = ntohs(display_data[n]);
|
|
||||||
t = (d & 0x00ff00) >> 8; /* type of display data */
|
|
||||||
c = (d & 0x0000ff); /* character/command */
|
|
||||||
switch (t) {
|
|
||||||
case 0x03: /* character */
|
|
||||||
if (!charisok(c)) c = ' ';
|
|
||||||
if (addr <= LINELEN * 2) {
|
|
||||||
ddram[addr++] = c;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x02: /* command */
|
|
||||||
switch (c) {
|
|
||||||
case 0x06: /* display clear */
|
|
||||||
memset(ddram, ' ', LINELEN * 2);
|
|
||||||
break;
|
|
||||||
case 0x02: /* cursor home */
|
|
||||||
addr = 0;
|
|
||||||
break;
|
|
||||||
case 0xc0: /* cursor home2 */
|
|
||||||
addr = LINELEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_display_buffer(ddram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Process graphic display data
|
* Process graphic display data
|
||||||
*/
|
*/
|
||||||
static void grfe_handler( u8_t *data, int len) {
|
static void v_draw( u8_t *data) {
|
||||||
data += 8;
|
|
||||||
len -= 8;
|
|
||||||
|
|
||||||
#ifndef FULL_REFRESH
|
#ifndef FULL_REFRESH
|
||||||
// force addressing mode by lines
|
// force addressing mode by rows
|
||||||
if (AddressMode != AddressMode_Horizontal) {
|
if (AddressMode != AddressMode_Horizontal) {
|
||||||
AddressMode = AddressMode_Horizontal;
|
AddressMode = AddressMode_Horizontal;
|
||||||
SSD1306_SetDisplayAddressMode( &Display, AddressMode );
|
SSD1306_SetDisplayAddressMode( &Display, AddressMode );
|
||||||
@@ -262,13 +154,14 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
uint8_t first = 0, last;
|
uint8_t first = 0, last;
|
||||||
uint8_t *optr = Display.Framebuffer + r*Display.Width, *iptr = data + r;
|
uint8_t *optr = Display.Framebuffer + r*Display.Width, *iptr = data + r;
|
||||||
|
|
||||||
// row/col swap, frame buffr comparison and bit-reversing
|
// row/col swap, frame buffer comparison and bit-reversing
|
||||||
for (int c = 0; c < Display.Width; c++) {
|
for (int c = 0; c < Display.Width; c++) {
|
||||||
|
*iptr = BitReverseTable256[*iptr];
|
||||||
if (*iptr != *optr) {
|
if (*iptr != *optr) {
|
||||||
if (first) last = c;
|
if (!first) first = c + 1;
|
||||||
else first = c + 1;
|
last = c ;
|
||||||
}
|
}
|
||||||
*optr++ = BitReverseTable256[*iptr];
|
*optr++ = *iptr;
|
||||||
iptr += rows;
|
iptr += rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,9 +173,12 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
int len = (Display.Width * Display.Height) / 8;
|
||||||
|
|
||||||
// to be verified, but this is as fast as using a pointer on data
|
// to be verified, but this is as fast as using a pointer on data
|
||||||
for (int i = len - 1; i >= 0; i--) data[i] = BitReverseTable256[data[i]];
|
for (int i = len - 1; i >= 0; i--) data[i] = BitReverseTable256[data[i]];
|
||||||
|
|
||||||
|
// 64 pixels display are not handled by LMS (bitmap is 32 pixels)
|
||||||
if (Display.Height > 32) SSD1306_SetPageAddress( &Display, 0, 32/8-1);
|
if (Display.Height > 32) SSD1306_SetPageAddress( &Display, 0, 32/8-1);
|
||||||
|
|
||||||
// force addressing mode by columns
|
// force addressing mode by columns
|
||||||
@@ -296,18 +192,26 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Process graphic display data
|
* Brightness
|
||||||
*/
|
*/
|
||||||
static void grfb_handler(u8_t *data, int len) {
|
static void brightness(u8_t level) {
|
||||||
s16_t brightness = htons(*(uint16_t*) (data + 4));
|
SSD1306_DisplayOn( &Display );
|
||||||
|
SSD1306_SetContrast( &Display, (uint8_t) level);
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "brightness %hx", brightness);
|
/****************************************************************************************
|
||||||
if (brightness < 0) {
|
* Display On/Off
|
||||||
SSD1306_DisplayOff( &Display );
|
*/
|
||||||
} else {
|
static void on(bool state) {
|
||||||
SSD1306_DisplayOn( &Display );
|
if (state) SSD1306_DisplayOn( &Display );
|
||||||
SSD1306_SetContrast( &Display, brightness * 256 / 4 - 1);
|
else SSD1306_DisplayOff( &Display );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Update
|
||||||
|
*/
|
||||||
|
static void update(void) {
|
||||||
|
SSD1306_Update( &Display );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ static void notify(in_addr_t ip, u16_t hport, u16_t cport) {
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Initialize controls - shall be called once from output_init_embedded
|
* Initialize controls - shall be called once from output_init_embedded
|
||||||
*/
|
*/
|
||||||
void cli_controls_init(void) {
|
void sb_controls_init(void) {
|
||||||
LOG_INFO("initializing CLI controls");
|
LOG_INFO("initializing CLI controls");
|
||||||
get_mac(mac);
|
get_mac(mac);
|
||||||
actrls_set_default(LMS_controls, NULL);
|
actrls_set_default(LMS_controls, NULL);
|
||||||
|
|||||||
289
components/squeezelite/display.c
Normal file
289
components/squeezelite/display.c
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* (c) 2004,2006 Richard Titmuss for SlimProtoLib
|
||||||
|
* (c) 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "squeezelite.h"
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
struct grfb_packet {
|
||||||
|
char opcode[4];
|
||||||
|
u16_t brightness;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct grfe_packet {
|
||||||
|
char opcode[4];
|
||||||
|
u16_t offset;
|
||||||
|
u8_t transition;
|
||||||
|
u8_t param;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct grfs_packet {
|
||||||
|
char opcode[4];
|
||||||
|
u8_t screen;
|
||||||
|
u8_t direction; // 1=left, 2=right
|
||||||
|
u32_t pause; // in ms
|
||||||
|
u32_t speed; // in ms
|
||||||
|
u16_t by; // # of pixel of scroll step
|
||||||
|
u16_t mode; // 0=continuous, 1=once and stop, 2=once and end
|
||||||
|
u16_t width; // total width of animation
|
||||||
|
u16_t offset; // offset if multiple packets are sent
|
||||||
|
};
|
||||||
|
|
||||||
|
struct grfg_packet {
|
||||||
|
char opcode[4];
|
||||||
|
u16_t screen;
|
||||||
|
u16_t width; // # of pixels of scrollable
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LINELEN 40
|
||||||
|
|
||||||
|
static log_level loglevel = lINFO;
|
||||||
|
|
||||||
|
static bool (*slimp_handler_chain)(u8_t *data, int len);
|
||||||
|
static void (*notify_chain)(in_addr_t ip, u16_t hport, u16_t cport);
|
||||||
|
|
||||||
|
static void server(in_addr_t ip, u16_t hport, u16_t cport);
|
||||||
|
static bool handler(u8_t *data, int len);
|
||||||
|
static void vfdc_handler( u8_t *_data, int bytes_read);
|
||||||
|
static void grfe_handler( u8_t *data, int len);
|
||||||
|
static void grfb_handler(u8_t *data, int len);
|
||||||
|
static void grfs_handler(u8_t *data, int len);
|
||||||
|
static void grfg_handler(u8_t *data, int len);
|
||||||
|
|
||||||
|
/* scrolling undocumented information
|
||||||
|
grfs
|
||||||
|
B: screen number
|
||||||
|
B:1 = left, 2 = right,
|
||||||
|
Q: scroll pause once done (ms)
|
||||||
|
Q: scroll speed (ms)
|
||||||
|
W: # of pixels to scroll each time
|
||||||
|
W: 0 = continue scrolling after pause, 1 = scroll to scrollend and then stop, 2 = scroll to scrollend and then end animation (causing new update)
|
||||||
|
W: width of total scroll area in pixels
|
||||||
|
|
||||||
|
grfd
|
||||||
|
W: screen number
|
||||||
|
W: width of scrollable area in pixels
|
||||||
|
|
||||||
|
ANIC flags
|
||||||
|
ANIM_TRANSITION 0x01 # A transition animation has finished
|
||||||
|
ANIM_SCROLL_ONCE 0x02 # A scrollonce has finished
|
||||||
|
ANIM_SCREEN_1 0x04 # For scrollonce only, screen 1 was scrolling
|
||||||
|
ANIM_SCREEN_2 0x08 # For scrollonce only, screen 2 was scrolling
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void sb_display_init(void) {
|
||||||
|
|
||||||
|
slimp_handler_chain = slimp_handler;
|
||||||
|
slimp_handler = handler;
|
||||||
|
|
||||||
|
notify_chain = server_notify;
|
||||||
|
server_notify = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void server(in_addr_t ip, u16_t hport, u16_t cport) {
|
||||||
|
char msg[32];
|
||||||
|
sprintf(msg, "%s:%hu", inet_ntoa(ip), hport);
|
||||||
|
display->text(DISPLAY_CENTER, DISPLAY_CLEAR | DISPLAY_UPDATE, msg);
|
||||||
|
if (notify_chain) (*notify_chain)(ip, hport, cport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Process graphic display data
|
||||||
|
*/
|
||||||
|
static bool handler(u8_t *data, int len){
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
if (!strncmp((char*) data, "vfdc", 4)) {
|
||||||
|
vfdc_handler(data, len);
|
||||||
|
} else if (!strncmp((char*) data, "grfe", 4)) {
|
||||||
|
grfe_handler(data, len);
|
||||||
|
} else if (!strncmp((char*) data, "grfb", 4)) {
|
||||||
|
grfb_handler(data, len);
|
||||||
|
} else if (!strncmp((char*) data, "grfs", 4)) {
|
||||||
|
grfs_handler(data, len);
|
||||||
|
} else if (!strncmp((char*) data, "grfg", 4)) {
|
||||||
|
grfg_handler(data, len);
|
||||||
|
} else {
|
||||||
|
res = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chain protocol handlers (bitwise or is fine)
|
||||||
|
if (*slimp_handler_chain) res |= (*slimp_handler_chain)(data, len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Change special LCD chars to something more printable on screen
|
||||||
|
*/
|
||||||
|
static void makeprintable(unsigned char * line) {
|
||||||
|
for (int n = 0; n < LINELEN; n++) {
|
||||||
|
switch (line[n]) {
|
||||||
|
case 11: /* block */
|
||||||
|
line[n] = '#';
|
||||||
|
break;;
|
||||||
|
case 16: /* rightarrow */
|
||||||
|
line[n] = '>';
|
||||||
|
break;;
|
||||||
|
case 22: /* circle */
|
||||||
|
line[n] = '@';
|
||||||
|
break;;
|
||||||
|
case 145: /* note */
|
||||||
|
line[n] = ' ';
|
||||||
|
break;;
|
||||||
|
case 152: /* bell */
|
||||||
|
line[n] = 'o';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Check if char is printable, or a valid symbol
|
||||||
|
*/
|
||||||
|
static bool charisok(unsigned char c) {
|
||||||
|
switch (c) {
|
||||||
|
case 11: /* block */
|
||||||
|
case 16: /* rightarrow */
|
||||||
|
case 22: /* circle */
|
||||||
|
case 145: /* note */
|
||||||
|
case 152: /* bell */
|
||||||
|
return true;
|
||||||
|
break;;
|
||||||
|
default:
|
||||||
|
return isprint(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Show the display (text mode)
|
||||||
|
*/
|
||||||
|
static void show_display_buffer(char *ddram) {
|
||||||
|
char line1[LINELEN+1];
|
||||||
|
char *line2;
|
||||||
|
|
||||||
|
memset(line1, 0, LINELEN+1);
|
||||||
|
strncpy(line1, ddram, LINELEN);
|
||||||
|
line2 = &(ddram[LINELEN]);
|
||||||
|
line2[LINELEN] = '\0';
|
||||||
|
|
||||||
|
/* Convert special LCD chars */
|
||||||
|
makeprintable((unsigned char *)line1);
|
||||||
|
makeprintable((unsigned char *)line2);
|
||||||
|
|
||||||
|
LOG_INFO("\n\t%.40s\n\t%.40s", line1, line2);
|
||||||
|
|
||||||
|
display->text(DISPLAY_TOP_LEFT, DISPLAY_CLEAR, line1);
|
||||||
|
display->text(DISPLAY_BOTTOM_LEFT, DISPLAY_UPDATE, line2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Process display data
|
||||||
|
*/
|
||||||
|
static void vfdc_handler( u8_t *_data, int bytes_read) {
|
||||||
|
unsigned short *data = (unsigned short*) _data, *display_data;
|
||||||
|
char ddram[(LINELEN + 1) * 2];
|
||||||
|
int n, addr = 0; /* counter */
|
||||||
|
|
||||||
|
bytes_read -= 4;
|
||||||
|
if (bytes_read % 2) bytes_read--; /* even number of bytes */
|
||||||
|
// if we use Noritake VFD codes, display data starts at 12
|
||||||
|
display_data = &(data[5]); /* display data starts at byte 10 */
|
||||||
|
|
||||||
|
memset(ddram, ' ', LINELEN * 2);
|
||||||
|
|
||||||
|
for (n = 0; n < (bytes_read/2); n++) {
|
||||||
|
unsigned short d; /* data element */
|
||||||
|
unsigned char t, c;
|
||||||
|
|
||||||
|
d = ntohs(display_data[n]);
|
||||||
|
t = (d & 0x00ff00) >> 8; /* type of display data */
|
||||||
|
c = (d & 0x0000ff); /* character/command */
|
||||||
|
switch (t) {
|
||||||
|
case 0x03: /* character */
|
||||||
|
if (!charisok(c)) c = ' ';
|
||||||
|
if (addr <= LINELEN * 2) {
|
||||||
|
ddram[addr++] = c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02: /* command */
|
||||||
|
switch (c) {
|
||||||
|
case 0x06: /* display clear */
|
||||||
|
memset(ddram, ' ', LINELEN * 2);
|
||||||
|
break;
|
||||||
|
case 0x02: /* cursor home */
|
||||||
|
addr = 0;
|
||||||
|
break;
|
||||||
|
case 0xc0: /* cursor home2 */
|
||||||
|
addr = LINELEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show_display_buffer(ddram);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Process graphic display data
|
||||||
|
*/
|
||||||
|
static void grfe_handler( u8_t *data, int len) {
|
||||||
|
display->v_draw(data + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Brightness
|
||||||
|
*/
|
||||||
|
static void grfb_handler(u8_t *data, int len) {
|
||||||
|
s16_t brightness = htons(*(uint16_t*) (data + 4));
|
||||||
|
|
||||||
|
LOG_INFO("brightness %hx", brightness);
|
||||||
|
if (brightness < 0) {
|
||||||
|
display->on(false);
|
||||||
|
} else {
|
||||||
|
display->on(true);
|
||||||
|
display->brightness(brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Scroll set
|
||||||
|
*/
|
||||||
|
static void grfs_handler(u8_t *data, int len) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Scroll go
|
||||||
|
*/
|
||||||
|
static void grfg_handler(u8_t *data, int len) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -49,8 +49,10 @@ uint32_t _gettime_ms_(void) {
|
|||||||
return (uint32_t) (esp_timer_get_time() / 1000);
|
return (uint32_t) (esp_timer_get_time() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void cli_controls_init(void);
|
extern void sb_controls_init(void);
|
||||||
|
extern void sb_display_init(void);
|
||||||
|
|
||||||
void embedded_init(void) {
|
void embedded_init(void) {
|
||||||
cli_controls_init();
|
sb_controls_init();
|
||||||
|
sb_display_init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ sub brightnessMap {
|
|||||||
return (65535, 10, 50, 100, 200);
|
return (65535, 10, 50, 100, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub hasScrolling {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
=comment
|
=comment
|
||||||
sub bytesPerColumn {
|
sub bytesPerColumn {
|
||||||
return 4;
|
return 4;
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use base qw(Slim::Display::Text);
|
|||||||
|
|
||||||
# we don't want the special Noritake codes
|
# we don't want the special Noritake codes
|
||||||
sub vfdmodel {
|
sub vfdmodel {
|
||||||
return 'squeezeslave'';
|
return 'squeezeslave';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
Reference in New Issue
Block a user