diff --git a/components/display/component.mk b/components/display/component.mk new file mode 100644 index 00000000..e0e9f4c1 --- /dev/null +++ b/components/display/component.mk @@ -0,0 +1,10 @@ +# +# Component Makefile +# +# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, +# this will take the sources in the src/ directory, compile them and link them into +# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, +# please read the SDK documents if you need to do this. +# + +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/components/display/text.c b/components/display/text.c new file mode 100644 index 00000000..cfb5810a --- /dev/null +++ b/components/display/text.c @@ -0,0 +1,128 @@ +/* + * (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 . + * + */ + +#include +#include +#include + +#include "esp_log.h" + +#define LINELEN 60 +#define TAG "display" + +//Change special LCD chars to something more printable on screen +unsigned char printable(unsigned char c) { + switch (c) { + case 11: /* block */ + return '#'; + break;; + case 16: /* rightarrow */ + return '>'; + break;; + case 22: /* circle */ + return '@'; + break;; + case 145: /* note */ + return ' '; + break;; + case 152: /* bell */ + return 'o'; + break;; + default: + return c; + } +} + +// Replace unprintable symbols in line +void makeprintable(unsigned char * line) { + for (int n=0; n < LINELEN; n++) line[n] = printable(line[n]); +} + +// Show the display +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); +} + +// Check if char is printable, or a valid symbol +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); + } +} + +// Process display data +void vfd_data( unsigned short *data, int bytes_read) { + unsigned short *display_data; + char ddram[LINELEN * 2]; + int n; + int addr = 0; /* counter */ + + if (bytes_read % 2) bytes_read--; /* even number of bytes */ + display_data = &(data[6]); /* display data starts at byte 12 */ + + 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); +} diff --git a/components/services/audio_controls.h b/components/services/audio_controls.h index 6db3d890..dfba2358 100644 --- a/components/services/audio_controls.h +++ b/components/services/audio_controls.h @@ -23,6 +23,7 @@ // BEWARE: this is the index of the array of action below typedef enum { ACTRLS_NONE = -1, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, + BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, ACTRLS_MAX } actrls_action_e; typedef void (*actrls_handler)(void); diff --git a/components/squeezelite/controls.c b/components/squeezelite/controls.c index c257d6ed..0a8c815a 100644 --- a/components/squeezelite/controls.c +++ b/components/squeezelite/controls.c @@ -69,12 +69,35 @@ static void lms_next(void) { cli_send_cmd("button fwd"); } +static void lms_up(void) { + cli_send_cmd("button arrow_up"); +} + +static void lms_down(void) { + cli_send_cmd("button arrow_down"); +} + +static void lms_left(void) { + cli_send_cmd("button arrow_left"); +} + +static void lms_right(void) { + cli_send_cmd("button arrow_right"); +} + +static void lms_push(void) { + cli_send_cmd("button knob_push"); +} + const actrls_t LMS_controls = { lms_volume_up, lms_volume_down, // volume up, volume down lms_toggle, lms_play, // toggle, play lms_pause, lms_stop, // pause, stop lms_rew, lms_fwd, // rew, fwd lms_prev, lms_next, // prev, next + lms_push, + lms_up, lms_down, + lms_left, lms_right, }; /**************************************************************************************** diff --git a/components/squeezelite/embedded.h b/components/squeezelite/embedded.h index ecc526eb..e604fdfa 100644 --- a/components/squeezelite/embedded.h +++ b/components/squeezelite/embedded.h @@ -25,7 +25,7 @@ #define OUTPUT_THREAD_STACK_SIZE 6 * 1024 #define IR_THREAD_STACK_SIZE 6 * 1024 -//#define BASE_CAP "Model=squeezelite,AccuratePlayPoints=0,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION +#define BASE_CAP "Model=squeezeesp32,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION #define EXT_BSS __attribute__((section(".ext_ram.bss"))) typedef int16_t s16_t; @@ -47,6 +47,7 @@ void embedded_init(void); void register_external(void); void deregister_external(void); void decode_resume(int external); +void vfd_data(u8_t *data, int len); void (*server_notify)(in_addr_t ip, u16_t hport, u16_t cport); diff --git a/components/squeezelite/slimproto.c b/components/squeezelite/slimproto.c index c4384a0c..f4ca0e40 100644 --- a/components/squeezelite/slimproto.c +++ b/components/squeezelite/slimproto.c @@ -45,6 +45,7 @@ static sockfd sock = -1; static in_addr_t slimproto_ip = 0; static u16_t slimproto_hport = 9000; static u16_t slimproto_cport = 9090; +static u8_t player_id = 100; // squeezeesp32 extern struct buffer *streambuf; extern struct buffer *outputbuf; @@ -136,7 +137,7 @@ static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, memset(&pkt, 0, sizeof(pkt)); memcpy(&pkt.opcode, "HELO", 4); pkt.length = htonl(sizeof(struct HELO_packet) - 8 + strlen(base_cap) + strlen(fixed_cap) + strlen(var_cap)); - pkt.deviceid = 12; // squeezeplay + pkt.deviceid = player_id; pkt.revision = 0; packn(&pkt.wlan_channellist, reconnect ? 0x4000 : 0x0000); packN(&pkt.bytes_received_H, (u64_t)status.stream_bytes >> 32); @@ -444,6 +445,16 @@ static void process_audg(u8_t *pkt, int len) { set_volume(audg->adjust ? audg->gainL : FIXED_ONE, audg->adjust ? audg->gainR : FIXED_ONE); } +static void process_dsco(u8_t *pkt, int len) { + LOG_INFO("got DSCO, switching from id %u to 12", (int) player_id); + player_id = 12; +} + +static void process_vfdc(u8_t *pkt, int len) { + LOG_DEBUG("VFDC %u", len); + vfd_data( pkt + 4, len - 4); +} + static void process_setd(u8_t *pkt, int len) { struct setd_packet *setd = (struct setd_packet *)pkt; @@ -519,6 +530,8 @@ static struct handler handlers[] = { { "audg", process_audg }, { "setd", process_setd }, { "serv", process_serv }, + { "dsco", process_dsco }, + { "vfdc", process_vfdc }, { "", NULL }, }; diff --git a/main/component.mk b/main/component.mk index 1b631af2..599b74aa 100644 --- a/main/component.mk +++ b/main/component.mk @@ -7,7 +7,7 @@ # please read the SDK documents if you need to do this. # #CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DMODEL_NAME=SqueezeESP32 COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools/ LDFLAGS += -s diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 0578964b..b09188bb 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -81,7 +81,7 @@ extern void services_init(void); static const actrls_config_t board_1[] = { // normal long shifted long shifted { 4, BUTTON_LOW, true, 1000, -1, {ACTRLS_VOLUP, ACTRLS_NONE}, {ACTRLS_PREV, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE}, {ACTRLS_NONE, ACTRLS_NONE} }, - { 5, BUTTON_LOW, true, 1000, 4, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_TOGGLE, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE} }, + { 5, BUTTON_LOW, true, 1000, 4, {ACTRLS_VOLDOWN, ACTRLS_NONE}, {ACTRLS_NEXT, ACTRLS_NONE}, {ACTRLS_TOGGLE, ACTRLS_NONE}, {BCTRLS_DOWN, ACTRLS_NONE} }, }; static const actrls_config_t board_2[] = {