add IR and "raw" button mode - release

This commit is contained in:
Philippe G
2020-05-09 18:07:26 -07:00
parent be00683b66
commit 5b6ddf0b02
15 changed files with 662 additions and 163 deletions

View File

@@ -7,84 +7,225 @@
*/
#include "squeezelite.h"
#include "config.h"
#include "audio_controls.h"
static log_level loglevel = lINFO;
#define DOWN_OFS 0x10000
#define UP_OFS 0x20000
// numbers are simply 0..9
// arrow_right.down = 0001000e seems to be missing ...
enum { BUTN_POWER_FRONT = 0X0A, BUTN_ARROW_UP, BUTN_ARROW_DOWN, BUTN_ARROW_LEFT, BUTN_KNOB_PUSH, BUTN_SEARCH,
BUTN_REW, BUTN_FWD, BUTN_PLAY, BUTN_ADD, BUTN_BRIGHTNESS, BUTN_NOW_PLAYING,
BUTN_PAUSE = 0X17, BUTN_BROWSE, BUTN_VOLUP_FRONT, BUTN_VOLDOWN_FRONT, BUTN_SIZE, BUTN_VISUAL, BUTN_VOLUMEMODE,
BUTN_PRESET_1 = 0X23, BUTN_PRESET_2, BUTN_PRESET_3, BUTN_PRESET_4, BUTN_PRESET_5, BUTN_PRESET_6, BUTN_SNOOZE,
BUTN_KNOB_LEFT = 0X5A, BUTN_KNOB_RIGHT };
#define BUTN_ARROW_RIGHT BUTN_KNOB_PUSH
#pragma pack(push, 1)
struct BUTN_header {
char opcode[4];
u32_t length;
u32_t jiffies;
u32_t button;
};
struct IR_header {
char opcode[4];
u32_t length;
u32_t jiffies;
u8_t format; // unused
u8_t bits; // unused
u32_t code;
};
#pragma pack(pop)
static in_addr_t server_ip;
static u16_t server_hport;
static u16_t server_cport;
static u8_t mac[6];
static void (*chained_notify)(in_addr_t, u16_t, u16_t);
static bool raw_mode;
static void cli_send_cmd(char *cmd);
static void lms_volume_up(void) {
cli_send_cmd("button volup");
/****************************************************************************************
* Send BUTN
*/
static void sendBUTN(int code, bool pressed) {
struct BUTN_header pkt_header;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "BUTN", 4);
pkt_header.length = htonl(sizeof(pkt_header) - 8);
pkt_header.jiffies = htonl(gettime_ms());
pkt_header.button = htonl(code + (pressed ? DOWN_OFS : UP_OFS));
LOG_INFO("sending BUTN code %04x %s", code, pressed ? "down" : "up");
LOCK_P;
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
UNLOCK_P;
}
static void lms_volume_down(void) {
cli_send_cmd("button voldown");
/****************************************************************************************
* Send IR
*/
static void sendIR(u16_t addr, u16_t cmd) {
struct IR_header pkt_header;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "IR ", 4);
pkt_header.length = htonl(sizeof(pkt_header) - 8);
pkt_header.jiffies = htonl(gettime_ms());
pkt_header.format = pkt_header.bits = 0;
pkt_header.code = htonl((addr << 16) | cmd);
LOG_INFO("sending IR code %04x", (addr << 16) | cmd);
LOCK_P;
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
UNLOCK_P;
}
static void lms_toggle(void) {
cli_send_cmd("pause");
static void lms_volume_up(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_VOLUP_FRONT, pressed);
} else {
cli_send_cmd("button volup");
}
}
static void lms_pause(void) {
cli_send_cmd("pause 1");
static void lms_volume_down(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_VOLDOWN_FRONT, pressed);
} else {
cli_send_cmd("button voldown");
}
}
static void lms_play(void) {
cli_send_cmd("button play.single");
static void lms_toggle(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_PAUSE, pressed);
} else {
cli_send_cmd("pause");
}
}
static void lms_stop(void) {
static void lms_pause(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_PAUSE, pressed);
} else {
cli_send_cmd("pause 1");
}
}
static void lms_play(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_PLAY, pressed);
} else {
cli_send_cmd("button play.single");
}
}
static void lms_stop(bool pressed) {
cli_send_cmd("button stop");
}
static void lms_rew(void) {
cli_send_cmd("button rew.repeat");
static void lms_rew(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_REW, pressed);
} else {
cli_send_cmd("button rew.repeat");
}
}
static void lms_fwd(void) {
cli_send_cmd("button fwd.repeat");
static void lms_fwd(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_FWD, pressed);
} else {
cli_send_cmd("button fwd.repeat");
}
}
static void lms_prev(void) {
cli_send_cmd("button rew");
static void lms_prev(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_REW, pressed);
} else {
cli_send_cmd("button rew");
}
}
static void lms_next(void) {
cli_send_cmd("button fwd");
static void lms_next(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_FWD, pressed);
} else {
cli_send_cmd("button fwd");
}
}
static void lms_up(void) {
cli_send_cmd("button arrow_up");
static void lms_up(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_ARROW_UP, pressed);
} else {
cli_send_cmd("button arrow_up");
}
}
static void lms_down(void) {
cli_send_cmd("button arrow_down");
static void lms_down(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_ARROW_DOWN, pressed);
} else {
cli_send_cmd("button arrow_down");
}
}
static void lms_left(void) {
cli_send_cmd("button arrow_left");
static void lms_left(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_ARROW_LEFT, pressed);
} else {
cli_send_cmd("button arrow_left");
}
}
static void lms_right(void) {
cli_send_cmd("button arrow_right");
static void lms_right(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_ARROW_RIGHT, pressed);
} else {
cli_send_cmd("button arrow_right");
}
}
static void lms_knob_left(void) {
cli_send_cmd("button knob_left");
static void lms_knob_left(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_KNOB_LEFT, pressed);
} else {
cli_send_cmd("button knob_left");
}
}
static void lms_knob_right(void) {
cli_send_cmd("button knob_right");
static void lms_knob_right(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_KNOB_RIGHT, pressed);
} else {
cli_send_cmd("button knob_right");
}
}
static void lms_knob_push(void) {
cli_send_cmd("button knob_push");
static void lms_knob_push(bool pressed) {
if (raw_mode) {
sendBUTN(BUTN_KNOB_PUSH, pressed);
} else {
cli_send_cmd("button knob_push");
}
}
const actrls_t LMS_controls = {
@@ -137,13 +278,27 @@ static void notify(in_addr_t ip, u16_t hport, u16_t cport) {
if (chained_notify) (*chained_notify)(ip, hport, cport);
}
/****************************************************************************************
* IR handler
*/
static bool ir_handler(u16_t addr, u16_t cmd) {
sendIR(addr, cmd);
return true;
}
/****************************************************************************************
* Initialize controls - shall be called once from output_init_embedded
*/
void sb_controls_init(void) {
LOG_INFO("initializing CLI controls");
char *p = config_alloc_get_default(NVS_TYPE_STR, "lms_ctrls_raw", "n", 0);
raw_mode = p && (*p == '1' || *p == 'Y' || *p == 'y');
free(p);
LOG_INFO("initializing audio (buttons/rotary/ir) controls (raw:%u)", raw_mode);
get_mac(mac);
actrls_set_default(LMS_controls, NULL);
actrls_set_default(LMS_controls, raw_mode, NULL, ir_handler);
chained_notify = server_notify;
server_notify = notify;
}

View File

@@ -197,23 +197,20 @@ extern const uint8_t vu_bitmap[] asm("_binary_vu_data_start");
#define ANIM_SCREEN_1 0x04
#define ANIM_SCREEN_2 0x08
static u8_t ANIC_resp = ANIM_NONE;
static uint16_t SETD_width;
#define SCROLL_STACK_SIZE (3*1024)
#define LINELEN 40
static log_level loglevel = lINFO;
static bool (*slimp_handler_chain)(u8_t *data, int len);
static void (*slimp_loop_chain)(void);
static void (*notify_chain)(in_addr_t ip, u16_t hport, u16_t cport);
static bool (*display_bus_chain)(void *from, enum display_bus_cmd_e cmd);
#define max(a,b) (((a) > (b)) ? (a) : (b))
static void server(in_addr_t ip, u16_t hport, u16_t cport);
static void send_server(void);
static void sendSETD(u16_t width, u16_t height);
static void sendANIC(u8_t code);
static bool handler(u8_t *data, int len);
static bool display_bus_handler(void *from, enum display_bus_cmd_e cmd);
static void vfdc_handler( u8_t *_data, int bytes_read);
@@ -223,7 +220,6 @@ static void grfs_handler(u8_t *data, int len);
static void grfg_handler(u8_t *data, int len);
static void grfa_handler(u8_t *data, int len);
static void visu_handler(u8_t *data, int len);
static void displayer_task(void* arg);
/* scrolling undocumented information
@@ -293,11 +289,13 @@ bool sb_display_init(void) {
return false;
}
// inform LMS of our screen dimensions
sendSETD(GDS_GetWidth(display), GDS_GetHeight(display));
// need to force height to 32 maximum
displayer.width = GDS_GetWidth(display);
displayer.height = min(GDS_GetHeight(display), SB_HEIGHT);
SETD_width = displayer.width;
// create visu configuration
visu.bar_gap = 1;
visu.speed = 100;
@@ -319,9 +317,6 @@ bool sb_display_init(void) {
slimp_handler_chain = slimp_handler;
slimp_handler = handler;
slimp_loop_chain = slimp_loop;
slimp_loop = send_server;
notify_chain = server_notify;
server_notify = server;
@@ -358,52 +353,44 @@ static bool display_bus_handler(void *from, enum display_bus_cmd_e cmd) {
else return true;
}
/****************************************************************************************
* Send message to server (ANIC at that time)
* Send ANImation Complete
*/
static void send_server(void) {
/*
This complication is needed as we cannot send direclty to LMS, because
send_packet is not thread safe. So must subscribe to slimproto busy loop
end send from there
*/
if (ANIC_resp != ANIM_NONE) {
struct ANIC_header pkt_header;
static void sendANIC(u8_t code) {
struct ANIC_header pkt_header;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "ANIC", 4);
pkt_header.length = htonl(sizeof(pkt_header) - 8);
pkt_header.mode = ANIC_resp;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "ANIC", 4);
pkt_header.length = htonl(sizeof(pkt_header) - 8);
pkt_header.mode = code;
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
LOCK_P;
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
UNLOCK_P;
}
ANIC_resp = ANIM_NONE;
}
if (SETD_width) {
struct SETD_header pkt_header;
/****************************************************************************************
* Send SETD for width
*/
static void sendSETD(u16_t width, u16_t height) {
struct SETD_header pkt_header;
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "SETD", 4);
memset(&pkt_header, 0, sizeof(pkt_header));
memcpy(&pkt_header.opcode, "SETD", 4);
pkt_header.id = 0xfe; // id 0xfe is width S:P:Squeezebox2
pkt_header.length = htonl(sizeof(pkt_header) + 4 - 8);
pkt_header.id = 0xfe; // id 0xfe is width S:P:Squeezebox2
pkt_header.length = htonl(sizeof(pkt_header) + 4 - 8);
u16_t height = GDS_GetHeight(display);
LOG_INFO("sending dimension %ux%u", SETD_width, height);
LOG_INFO("sending dimension %ux%u", width, height);
SETD_width = htons(SETD_width);
height = htons(height);
width = htons(width);
height = htons(height);
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
send_packet((uint8_t *) &SETD_width, 2);
send_packet((uint8_t *) &height, 2);
SETD_width = 0;
}
if (slimp_loop_chain) (*slimp_loop_chain)();
LOCK_P;
send_packet((uint8_t *) &pkt_header, sizeof(pkt_header));
send_packet((uint8_t *) &width, 2);
send_packet((uint8_t *) &height, 2);
UNLOCK_P;
}
/****************************************************************************************
@@ -416,11 +403,13 @@ static void server(in_addr_t ip, u16_t hport, u16_t cport) {
sprintf(msg, "%s:%hu", inet_ntoa(ip), hport);
if (displayer.owned) GDS_TextPos(display, GDS_FONT_DEFAULT, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg);
SETD_width = displayer.width;
displayer.dirty = true;
xSemaphoreGive(displayer.mutex);
// inform new LMS server of our capabilities
sendSETD(displayer.width, GDS_GetHeight(display));
if (notify_chain) (*notify_chain)(ip, hport, cport);
}
@@ -1141,8 +1130,7 @@ static void displayer_task(void *args) {
// see if we need to pause or if we are done
if (scroller.mode) {
// can't call directly send_packet from slimproto as it's not re-entrant
ANIC_resp = ANIM_SCROLL_ONCE | ANIM_SCREEN_1;
sendANIC(ANIM_SCROLL_ONCE | ANIM_SCREEN_1);
LOG_INFO("scroll-once terminated");
} else {
scroller.wake = scroller.pause;

View File

@@ -15,6 +15,8 @@
#include "esp_timer.h"
#include "esp_wifi.h"
mutex_type slimp_mutex;
void get_mac(u8_t mac[]) {
esp_read_mac(mac, ESP_MAC_WIFI_STA);
}
@@ -46,6 +48,7 @@ extern bool sb_display_init(void);
u8_t custom_player_id = 12;
void embedded_init(void) {
mutex_create(slimp_mutex);
sb_controls_init();
if (sb_display_init()) custom_player_id = 100;
}

View File

@@ -58,6 +58,9 @@ void embedded_init(void);
void register_external(void);
void deregister_external(void);
void decode_restore(int external);
extern mutex_type slimp_mutex;
#define LOCK_P mutex_lock(slimp_mutex)
#define UNLOCK_P mutex_unlock(slimp_mutex)
// must provide or define as 0xffff
u16_t get_RSSI(void);
@@ -77,5 +80,5 @@ void output_visu_close(void);
bool (*slimp_handler)(u8_t *data, int len);
void (*slimp_loop)(void);
void (*server_notify)(in_addr_t ip, u16_t hport, u16_t cport);
#endif // EMBEDDED_H

View File

@@ -67,6 +67,10 @@ event_event wake_e;
#define UNLOCK_O mutex_unlock(outputbuf->mutex)
#define LOCK_D mutex_lock(decode.mutex)
#define UNLOCK_D mutex_unlock(decode.mutex)
#if !EMBEDDED
#define LOCK_P
#define UNLOCK_P
#endif
#if IR
#define LOCK_I mutex_lock(ir.mutex)
#define UNLOCK_I mutex_unlock(ir.mutex)
@@ -149,11 +153,12 @@ static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap,
LOG_INFO("mac: %02x:%02x:%02x:%02x:%02x:%02x", pkt.mac[0], pkt.mac[1], pkt.mac[2], pkt.mac[3], pkt.mac[4], pkt.mac[5]);
LOG_INFO("cap: %s%s%s", base_cap, fixed_cap, var_cap);
LOCK_P;
send_packet((u8_t *)&pkt, sizeof(pkt));
send_packet((u8_t *)base_cap, strlen(base_cap));
send_packet((u8_t *)fixed_cap, strlen(fixed_cap));
send_packet((u8_t *)var_cap, strlen(var_cap));
UNLOCK_P;
}
static void sendSTAT(const char *event, u32_t server_timestamp) {
@@ -205,7 +210,9 @@ static void sendSTAT(const char *event, u32_t server_timestamp) {
ms_played - now + status.stream_start, status.device_frames * 1000 / status.current_sample_rate, now - status.updated);
}
LOCK_P;
send_packet((u8_t *)&pkt, sizeof(pkt));
UNLOCK_P;
}
static void sendDSCO(disconnect_code disconnect) {
@@ -218,7 +225,9 @@ static void sendDSCO(disconnect_code disconnect) {
LOG_DEBUG("DSCO: %d", disconnect);
LOCK_P;
send_packet((u8_t *)&pkt, sizeof(pkt));
UNLOCK_P;
}
static void sendRESP(const char *header, size_t len) {
@@ -229,9 +238,11 @@ static void sendRESP(const char *header, size_t len) {
pkt_header.length = htonl(sizeof(pkt_header) + len - 8);
LOG_DEBUG("RESP");
LOCK_P;
send_packet((u8_t *)&pkt_header, sizeof(pkt_header));
send_packet((u8_t *)header, len);
UNLOCK_P;
}
static void sendMETA(const char *meta, size_t len) {
@@ -243,8 +254,10 @@ static void sendMETA(const char *meta, size_t len) {
LOG_DEBUG("META");
LOCK_P;
send_packet((u8_t *)&pkt_header, sizeof(pkt_header));
send_packet((u8_t *)meta, len);
UNLOCK_P;
}
static void sendSETDName(const char *name) {
@@ -258,8 +271,10 @@ static void sendSETDName(const char *name) {
LOG_DEBUG("set playername: %s", name);
LOCK_P;
send_packet((u8_t *)&pkt_header, sizeof(pkt_header));
send_packet((u8_t *)name, strlen(name) + 1);
UNLOCK_P;
}
#if IR
@@ -274,8 +289,9 @@ void sendIR(u32_t code, u32_t ts) {
pkt.ir_code = htonl(code);
LOG_DEBUG("IR: ir code: 0x%x ts: %u", code, ts);
LOCK_P;
send_packet((u8_t *)&pkt, sizeof(pkt));
UNLOCK_P;
}
#endif