mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 04:27:12 +03:00
knob-only navigation - release
This commit is contained in:
@@ -12,6 +12,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/timers.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
@@ -36,6 +38,7 @@ static esp_err_t actrls_process_action (const cJSON * member, actrls_config_t *c
|
|||||||
|
|
||||||
static esp_err_t actrls_init_json(const char *profile_name, bool create);
|
static esp_err_t actrls_init_json(const char *profile_name, bool create);
|
||||||
static void control_rotary_handler(void *client, rotary_event_e event, bool long_press);
|
static void control_rotary_handler(void *client, rotary_event_e event, bool long_press);
|
||||||
|
static void rotary_timer( TimerHandle_t xTimer );
|
||||||
|
|
||||||
static const actrls_config_map_t actrls_config_map[] =
|
static const actrls_config_map_t actrls_config_map[] =
|
||||||
{
|
{
|
||||||
@@ -71,6 +74,9 @@ static actrls_ir_handler_t *default_ir_handler, *current_ir_handler;
|
|||||||
static struct {
|
static struct {
|
||||||
bool long_state;
|
bool long_state;
|
||||||
bool volume_lock;
|
bool volume_lock;
|
||||||
|
TimerHandle_t timer;
|
||||||
|
bool click_pending;
|
||||||
|
int left_count;
|
||||||
} rotary;
|
} rotary;
|
||||||
|
|
||||||
static const struct ir_action_map_s{
|
static const struct ir_action_map_s{
|
||||||
@@ -133,8 +139,16 @@ esp_err_t actrls_init(const char *profile_name) {
|
|||||||
if ((p = strcasestr(config, "A")) != NULL) A = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "A")) != NULL) A = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "B")) != NULL) B = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "B")) != NULL) B = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "SW")) != NULL) SW = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "SW")) != NULL) SW = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true;
|
if ((p = strcasestr(config, "knobonly")) != NULL) {
|
||||||
if ((p = strcasestr(config, "longpress")) != NULL) longpress = 1000;
|
p = strchr(p, '=');
|
||||||
|
int double_press = p ? atoi(p + 1) : 350;
|
||||||
|
rotary.timer = xTimerCreate("knobTimer", double_press / portTICK_RATE_MS, pdFALSE, NULL, rotary_timer);
|
||||||
|
longpress = 500;
|
||||||
|
ESP_LOGI(TAG, "single knob navigation %d", double_press);
|
||||||
|
} else {
|
||||||
|
if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true;
|
||||||
|
if ((p = strcasestr(config, "longpress")) != NULL) longpress = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
// create rotary (no handling of long press)
|
// create rotary (no handling of long press)
|
||||||
err = create_rotary(NULL, A, B, SW, longpress, control_rotary_handler) ? ESP_OK : ESP_FAIL;
|
err = create_rotary(NULL, A, B, SW, longpress, control_rotary_handler) ? ESP_OK : ESP_FAIL;
|
||||||
@@ -223,17 +237,42 @@ static void control_rotary_handler(void *client, rotary_event_e event, bool long
|
|||||||
|
|
||||||
switch(event) {
|
switch(event) {
|
||||||
case ROTARY_LEFT:
|
case ROTARY_LEFT:
|
||||||
if (rotary.long_state) action = ACTRLS_PREV;
|
if (rotary.timer) {
|
||||||
|
if (rotary.left_count) {
|
||||||
|
action = KNOB_LEFT;
|
||||||
|
// need to add a left button the first time
|
||||||
|
if (rotary.left_count == 1) (*current_controls[KNOB_LEFT])(true);
|
||||||
|
}
|
||||||
|
xTimerStart(rotary.timer, 20 / portTICK_RATE_MS);
|
||||||
|
rotary.left_count++;
|
||||||
|
}
|
||||||
|
else if (rotary.long_state) action = ACTRLS_PREV;
|
||||||
else if (rotary.volume_lock) action = ACTRLS_VOLDOWN;
|
else if (rotary.volume_lock) action = ACTRLS_VOLDOWN;
|
||||||
else action = KNOB_LEFT;
|
else action = KNOB_LEFT;
|
||||||
break;
|
break;
|
||||||
case ROTARY_RIGHT:
|
case ROTARY_RIGHT:
|
||||||
if (rotary.long_state) action = ACTRLS_NEXT;
|
if (rotary.timer) {
|
||||||
|
if (rotary.left_count == 1) {
|
||||||
|
action = ACTRLS_PAUSE;
|
||||||
|
rotary.left_count = 0;
|
||||||
|
xTimerStop(rotary.timer, 0);
|
||||||
|
} else action = KNOB_RIGHT;
|
||||||
|
}
|
||||||
|
else if (rotary.long_state) action = ACTRLS_NEXT;
|
||||||
else if (rotary.volume_lock) action = ACTRLS_VOLUP;
|
else if (rotary.volume_lock) action = ACTRLS_VOLUP;
|
||||||
else action = KNOB_RIGHT;
|
else action = KNOB_RIGHT;
|
||||||
break;
|
break;
|
||||||
case ROTARY_PRESSED:
|
case ROTARY_PRESSED:
|
||||||
if (long_press) rotary.long_state = !rotary.long_state;
|
if (rotary.timer) {
|
||||||
|
if (long_press) action = ACTRLS_PLAY;
|
||||||
|
else if (rotary.click_pending) {
|
||||||
|
action = BCTRLS_LEFT;
|
||||||
|
xTimerStop(rotary.timer, 0);
|
||||||
|
}
|
||||||
|
else xTimerStart(rotary.timer, 20 / portTICK_RATE_MS);
|
||||||
|
rotary.click_pending = !rotary.click_pending;
|
||||||
|
}
|
||||||
|
else if (long_press) rotary.long_state = !rotary.long_state;
|
||||||
else if (rotary.volume_lock) action = ACTRLS_TOGGLE;
|
else if (rotary.volume_lock) action = ACTRLS_TOGGLE;
|
||||||
else action = KNOB_PUSH;
|
else action = KNOB_PUSH;
|
||||||
break;
|
break;
|
||||||
@@ -244,6 +283,19 @@ static void control_rotary_handler(void *client, rotary_event_e event, bool long
|
|||||||
if (action != ACTRLS_NONE) (*current_controls[action])(pressed);
|
if (action != ACTRLS_NONE) (*current_controls[action])(pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void rotary_timer( TimerHandle_t xTimer ) {
|
||||||
|
if (rotary.click_pending) {
|
||||||
|
(*current_controls[KNOB_PUSH])(true);
|
||||||
|
rotary.click_pending = false;
|
||||||
|
} else if (rotary.left_count) {
|
||||||
|
if (rotary.left_count == 1) (*current_controls[KNOB_LEFT])(true);
|
||||||
|
rotary.left_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct IR_header {
|
|||||||
static in_addr_t server_ip;
|
static in_addr_t server_ip;
|
||||||
static u16_t server_hport;
|
static u16_t server_hport;
|
||||||
static u16_t server_cport;
|
static u16_t server_cport;
|
||||||
|
static int cli_sock = -1;
|
||||||
static u8_t mac[6];
|
static u8_t mac[6];
|
||||||
static void (*chained_notify)(in_addr_t, u16_t, u16_t);
|
static void (*chained_notify)(in_addr_t, u16_t, u16_t);
|
||||||
static bool raw_mode;
|
static bool raw_mode;
|
||||||
@@ -243,38 +244,44 @@ const actrls_t LMS_controls = {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void cli_send_cmd(char *cmd) {
|
static void cli_send_cmd(char *cmd) {
|
||||||
char packet[64];
|
char packet[96];
|
||||||
struct sockaddr_in addr;
|
int len;
|
||||||
socklen_t addrlen = sizeof(addr);
|
|
||||||
int len, sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = server_ip;
|
|
||||||
addr.sin_port = htons(server_cport);
|
|
||||||
|
|
||||||
if (connect(sock, (struct sockaddr *) &addr, addrlen) < 0) {
|
|
||||||
LOG_ERROR("unable to connect to server %s:%hu with cli", inet_ntoa(server_ip), server_cport);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = sprintf(packet, "%02x:%02x:%02x:%02x:%02x:%02x %s\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], cmd);
|
len = sprintf(packet, "%02x:%02x:%02x:%02x:%02x:%02x %s\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], cmd);
|
||||||
LOG_DEBUG("sending command %s at %s:%hu", packet, inet_ntoa(server_ip), server_cport);
|
LOG_DEBUG("sending command %s at %s:%hu", packet, inet_ntoa(server_ip), server_cport);
|
||||||
|
|
||||||
if (send(sock, packet, len, 0) < 0) {
|
if (send(cli_sock, packet, len, MSG_DONTWAIT) < 0) {
|
||||||
LOG_WARN("cannot send CLI %s", packet);
|
LOG_WARN("cannot send CLI %s", packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
closesocket(sock);
|
// need to empty the RX buffer otherwise we'll lock the TCP/IP stack
|
||||||
|
len = recv(cli_sock, packet, 96, MSG_DONTWAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Notification when server changes
|
* Notification when server changes
|
||||||
*/
|
*/
|
||||||
static void notify(in_addr_t ip, u16_t hport, u16_t cport) {
|
static void notify(in_addr_t ip, u16_t hport, u16_t cport) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addrlen = sizeof(addr);
|
||||||
|
|
||||||
server_ip = ip;
|
server_ip = ip;
|
||||||
server_hport = hport;
|
server_hport = hport;
|
||||||
server_cport = cport;
|
server_cport = cport;
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = server_ip;
|
||||||
|
addr.sin_port = htons(server_cport);
|
||||||
|
|
||||||
|
// close existing CLI connection and open new one
|
||||||
|
if (cli_sock >= 0) closesocket(cli_sock);
|
||||||
|
cli_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (connect(cli_sock, (struct sockaddr *) &addr, addrlen) < 0) {
|
||||||
|
LOG_ERROR("unable to connect to server %s:%hu with cli", inet_ntoa(server_ip), server_cport);
|
||||||
|
cli_sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO("notified server %s hport %hu cport %hu", inet_ntoa(ip), hport, cport);
|
LOG_INFO("notified server %s hport %hu cport %hu", inet_ntoa(ip), hport, cport);
|
||||||
|
|
||||||
if (chained_notify) (*chained_notify)(ip, hport, cport);
|
if (chained_notify) (*chained_notify)(ip, hport, cport);
|
||||||
|
|||||||
Reference in New Issue
Block a user