mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-01-27 21:00:57 +03:00
Start of 5.X work
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES json tools platform_config display wifi-manager esp-tls platform_config
|
||||
REQUIRES json tools platform_config display wifi-manager esp-tls
|
||||
PRIV_REQUIRES soc esp32
|
||||
)
|
||||
|
||||
|
||||
@@ -5,15 +5,13 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_INFO
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/spi_master.h"
|
||||
// #include "Configurator.h"
|
||||
#pragma message("fixme: look for TODO below")
|
||||
#include "Config.h"
|
||||
#include "accessors.h"
|
||||
#include "globdefs.h"
|
||||
#include "display.h"
|
||||
@@ -94,12 +92,20 @@ bool is_dac_config_locked(){
|
||||
}
|
||||
|
||||
|
||||
|
||||
const sys_i2c_bus* get_i2c_bus(i2c_port_t port){
|
||||
if(platform->dev.has_i2c && port == platform->dev.i2c.port-sys_i2c_port_PORT0 && platform->dev.i2c.scl>=0){
|
||||
return &platform->dev.i2c;
|
||||
}
|
||||
if(platform->dev.has_dac && platform->dev.dac.has_i2c && platform->dev.dac.i2c.port == port && platform->dev.dac.i2c.scl>=0){
|
||||
return &platform->dev.dac.i2c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
const i2c_config_t * config_i2c_get(int * i2c_port) {
|
||||
sys_I2CBus * bus = NULL;
|
||||
const i2c_config_t * config_i2c_get(sys_i2c_bus * bus) {
|
||||
|
||||
static i2c_config_t i2c = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = -1,
|
||||
@@ -109,38 +115,30 @@ const i2c_config_t * config_i2c_get(int * i2c_port) {
|
||||
.master.clk_speed = 0,
|
||||
};
|
||||
|
||||
if(SYS_I2CBUS(bus)){
|
||||
if(bus->has_scl){
|
||||
i2c.scl_io_num = bus->scl.pin;
|
||||
if(bus && bus->scl >=0 && bus->sda >=0 ){
|
||||
if(bus->scl>=0){
|
||||
i2c.scl_io_num = bus->scl;
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG,"%s missing for i2c","SCL");
|
||||
}
|
||||
|
||||
if(bus->has_sda){
|
||||
i2c.sda_io_num= bus->sda.pin;
|
||||
if(bus->sda>=0){
|
||||
i2c.sda_io_num= bus->sda;
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG,"%s missing for i2c","SDA");
|
||||
}
|
||||
if(bus->speed>0){
|
||||
i2c.master.clk_speed = bus->speed;
|
||||
}
|
||||
if(bus->port != sys_I2CPortEnum_UNSPECIFIED_PORT){
|
||||
i2c_system_port = bus->port - sys_I2CPortEnum_I2CPort0;
|
||||
}
|
||||
// TODO: untangle i2c system port handling
|
||||
if(i2c_port) {
|
||||
*i2c_port=i2c_system_port;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return &i2c;
|
||||
}
|
||||
|
||||
|
||||
void config_set_gpio(int * pin, sys_GPIO * gpio,bool has_value, const char * name, bool mandatory){
|
||||
void config_set_gpio(int * pin, sys_gpio_config * gpio,bool has_value, const char * name, bool mandatory){
|
||||
if(has_value){
|
||||
ESP_LOGD(TAG, "Setting pin %d as %s", gpio->pin, name);
|
||||
if(pin) *pin= gpio->pin;
|
||||
@@ -166,14 +164,14 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
|
||||
.quadhd_io_num = -1
|
||||
};
|
||||
if(platform->has_dev && platform->dev.has_spi){
|
||||
ESP_LOGI(TAG,"SPI Configuration found");
|
||||
ASSIGN_GPIO(spi.mosi_io_num,platform->dev.spi,mosi,true);
|
||||
ASSIGN_GPIO(spi.miso_io_num,platform->dev.spi,miso,false);
|
||||
ASSIGN_GPIO(spi.sclk_io_num,platform->dev.spi,clk,true);
|
||||
ASSIGN_GPIO(spi_system_dc_gpio,platform->dev.spi,dc,true);
|
||||
ESP_LOGD(TAG,"SPI Configuration found");
|
||||
spi.mosi_io_num = platform->dev.spi.mosi;
|
||||
spi.miso_io_num = platform->dev.spi.miso;
|
||||
spi.sclk_io_num = platform->dev.spi.clk;
|
||||
spi_system_dc_gpio = platform->dev.spi.dc;
|
||||
// only VSPI (1) can be used as Flash and PSRAM run at 80MHz
|
||||
if(platform->dev.spi.host!=sys_HostEnum_UNSPECIFIED_HOST){
|
||||
spi_system_host = platform->dev.spi.host;
|
||||
if(platform->dev.spi.host!=sys_dev_common_hosts_NONE){
|
||||
spi_system_host = platform->dev.spi.host-sys_dev_common_hosts_Host0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "I2CBus.pb.h"
|
||||
#define ASSIGN_GPIO(pin, root, name, mandatory) config_set_gpio(&pin, &(root).name, (root).has_##name, #name, mandatory)
|
||||
|
||||
#define ASSIGN_COND_VAL_1LVL(name, targetval) \
|
||||
@@ -31,7 +32,9 @@
|
||||
#define SYS_NET(target) ASSIGN_COND_VAL_1LVL(net,target)
|
||||
#define SYS_DISPLAY(target) ASSIGN_COND_VAL_2LVL(dev,display,target)
|
||||
#define SYS_DEV_LEDSTRIP(target) ASSIGN_COND_VAL_2LVL(dev,led_strip,target)
|
||||
#define SYS_DEV(target) ASSIGN_COND_VAL_1LVL(dev,target)
|
||||
#define SYS_DEV_ROTARY(target) ASSIGN_COND_VAL_2LVL(dev,rotary,target)
|
||||
#define SYS_DEV_IR(target) ASSIGN_COND_VAL_2LVL(dev,ir,target)
|
||||
#define SYS_DISPLAY_COMMON(target) ASSIGN_COND_VAL_3LVL(dev,display,common,target)
|
||||
#define SYS_DISPLAY_SPI(target) ASSIGN_COND_VAL_3LVL(dev,display,spi,target)
|
||||
#define SYS_DISPLAY_I2C(target) ASSIGN_COND_VAL_3LVL(dev,display,i2c,target)
|
||||
@@ -40,25 +43,25 @@
|
||||
#define SYS_ETH_COMMON(target) ASSIGN_COND_VAL_3LVL(dev,eth,common,target)
|
||||
|
||||
|
||||
#define SYS_I2CBUS(target) ASSIGN_COND_VAL_2LVL(dev,i2c,target)
|
||||
#define sys_i2c_bus(target) ASSIGN_COND_VAL_2LVL(dev,i2c,target)
|
||||
#define SYS_GPIOS_NAME(name,target) ASSIGN_COND_VAL_2LVL(gpios,name,target)
|
||||
#define SYS_SERVICES(target) ASSIGN_COND_VAL_1LVL(services,target)
|
||||
#define SYS_SERVICES_SPOTIFY(target) ASSIGN_COND_VAL_2LVL(services,cspot,target)
|
||||
#define SYS_SERVICES_METADATA(target) ASSIGN_COND_VAL_2LVL(services,metadata,target)
|
||||
#define SYS_SERVICES_AIRPLAY(target) ASSIGN_COND_VAL_2LVL(services,airplay,target)
|
||||
#define SYS_SERVICES_SLEEP(target) ASSIGN_COND_VAL_2LVL(services,sleep,target)
|
||||
#define SYS_SERVICES_EQUALIZER(target) ASSIGN_COND_VAL_2LVL(services,equalizer,target)
|
||||
#define sys_services_config(target) ASSIGN_COND_VAL_1LVL(services,target)
|
||||
#define sys_services_config_SPOTIFY(target) ASSIGN_COND_VAL_2LVL(services,cspot,target)
|
||||
#define sys_services_config_METADATA(target) ASSIGN_COND_VAL_2LVL(services,metadata,target)
|
||||
#define sys_services_config_AIRPLAY(target) ASSIGN_COND_VAL_2LVL(services,airplay,target)
|
||||
#define sys_services_config_SLEEP(target) ASSIGN_COND_VAL_2LVL(services,sleep,target)
|
||||
#define sys_services_config_EQUALIZER(target) ASSIGN_COND_VAL_2LVL(services,equalizer,target)
|
||||
|
||||
#define SYS_SERVICES_TELNET(target) ASSIGN_COND_VAL_2LVL(services,telnet,target)
|
||||
#define SYS_SERVICES_BTSINK(target) ASSIGN_COND_VAL_2LVL(services,bt_sink,target)
|
||||
#define SYS_SERVICES_SQUEEZELITE(target) ASSIGN_COND_VAL_2LVL(services,squeezelite,target)
|
||||
#define sys_services_config_TELNET(target) ASSIGN_COND_VAL_2LVL(services,telnet,target)
|
||||
#define sys_services_config_BTSINK(target) ASSIGN_COND_VAL_2LVL(services,bt_sink,target)
|
||||
|
||||
|
||||
#define SYS_DEV_BATTERY(target) ASSIGN_COND_VAL_2LVL(dev,battery,target)
|
||||
|
||||
const i2c_config_t * config_i2c_get(int * i2c_port);
|
||||
const i2c_config_t * config_i2c_get(sys_i2c_bus * bus);
|
||||
const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host);
|
||||
const gpio_exp_config_t * config_gpio_exp_get(int index);
|
||||
const sys_i2c_bus* get_i2c_bus(i2c_port_t port);
|
||||
|
||||
bool is_dac_config_locked();
|
||||
bool are_statistics_enabled();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,27 +9,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "buttons.h"
|
||||
#include "Buttons.pb.h"
|
||||
|
||||
// BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
|
||||
typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
|
||||
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
|
||||
BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9,
|
||||
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
|
||||
ACTRLS_SLEEP,
|
||||
ACTRLS_REMAP, ACTRLS_MAX
|
||||
} actrls_action_e;
|
||||
// typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
|
||||
// ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
|
||||
// BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
|
||||
// BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9,
|
||||
// KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
|
||||
// ACTRLS_SLEEP,
|
||||
// ACTRLS_REMAP, ACTRLS_MAX
|
||||
// } actrls_action_e;
|
||||
|
||||
typedef void (*actrls_handler)(bool pressed);
|
||||
typedef actrls_handler actrls_t[ACTRLS_MAX - ACTRLS_NONE - 1];
|
||||
typedef bool actrls_hook_t(int gpio, actrls_action_e action, button_event_e event, button_press_e press, bool long_press);
|
||||
typedef actrls_handler actrls_t[sys_btns_actions_MAX- sys_btns_actions_A_NONE - 1];
|
||||
typedef bool actrls_hook_t(int gpio, sys_btns_action *action, button_event_e event, button_press_e press, bool long_press);
|
||||
typedef bool actrls_ir_handler_t(uint16_t addr, uint16_t cmd);
|
||||
|
||||
// BEWARE any change to struct below must be mapped to actrls_config_map
|
||||
typedef struct {
|
||||
actrls_action_e action;
|
||||
const char * name;
|
||||
} actrls_action_detail_t;
|
||||
// typedef struct {
|
||||
// actrls_action_e action;
|
||||
// const char * name;
|
||||
// } actrls_action_detail_t;
|
||||
typedef struct actrl_config_s {
|
||||
int gpio;
|
||||
int type;
|
||||
@@ -37,7 +38,7 @@ typedef struct actrl_config_s {
|
||||
int debounce;
|
||||
int long_press;
|
||||
int shifter_gpio;
|
||||
actrls_action_detail_t normal[2], longpress[2], shifted[2], longshifted[2]; // [0] keypressed, [1] keyreleased
|
||||
sys_btns_press normal, longpress, shifted, longshifted; // [0] keypressed, [1] keyreleased
|
||||
} actrls_config_t;
|
||||
|
||||
esp_err_t actrls_init(const char *profile_name);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "driver/adc.h"
|
||||
#include "battery.h"
|
||||
#include "Configurator.h"
|
||||
#include "Config.h"
|
||||
|
||||
/*
|
||||
There is a bug in esp32 which causes a spurious interrupt on gpio 36/39 when
|
||||
@@ -32,11 +32,11 @@ static const char *TAG = "battery";
|
||||
static struct {
|
||||
float sum, avg, scale;
|
||||
int count;
|
||||
sys_Battery * battery_config;
|
||||
sys_battery_config * battery_config;
|
||||
TimerHandle_t timer;
|
||||
} battery;
|
||||
#define BATTERY_CHANNEL(b) (b.battery_config?b.battery_config->channel - sys_BatteryChannelEnum_CH0:-1)
|
||||
#define ATTENUATION(b) (b.battery_config?b.battery_config->atten - sys_BatteryAttenEnum_ATT_0:-1)
|
||||
#define BATTERY_CHANNEL(b) (b.battery_config?b.battery_config->channel - sys_battery_channels_CH0:-1)
|
||||
#define ATTENUATION(b) (b.battery_config?b.battery_config->atten - sys_battery_atten_ATT_0:-1)
|
||||
void (*battery_handler_svc)(float value, int cells);
|
||||
|
||||
/****************************************************************************************
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* a crude button press/long-press/shift management based on GPIO
|
||||
*
|
||||
* (c) Philippe G. 2019, philippe_44@outlook.com
|
||||
@@ -7,448 +7,458 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_task.h"
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
#include "buttons.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "buttons.h"
|
||||
#include "services.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_task.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "globdefs.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "services.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char * TAG = "buttons";
|
||||
static const char* TAG = "buttons";
|
||||
|
||||
static EXT_RAM_ATTR int n_buttons;
|
||||
static EXT_RAM_ATTR uint32_t buttons_idle_since;
|
||||
|
||||
#define BUTTON_STACK_SIZE 4096
|
||||
#define MAX_BUTTONS 32
|
||||
#define DEBOUNCE 50
|
||||
#define BUTTON_QUEUE_LEN 10
|
||||
#define BUTTON_STACK_SIZE 4096
|
||||
#define MAX_BUTTONS 32
|
||||
#define DEBOUNCE 50
|
||||
#define BUTTON_QUEUE_LEN 10
|
||||
|
||||
static EXT_RAM_ATTR struct button_s {
|
||||
void *client;
|
||||
int gpio;
|
||||
int debounce;
|
||||
button_handler handler;
|
||||
struct button_s *self, *shifter;
|
||||
int shifter_gpio; // this one is just for post-creation
|
||||
int long_press;
|
||||
bool long_timer, shifted, shifting;
|
||||
int type, level;
|
||||
TimerHandle_t timer;
|
||||
void* client;
|
||||
int gpio;
|
||||
int debounce;
|
||||
button_handler handler;
|
||||
struct button_s *self, *shifter;
|
||||
int shifter_gpio; // this one is just for post-creation
|
||||
int long_press;
|
||||
bool long_timer, shifted, shifting;
|
||||
int type, level;
|
||||
TimerHandle_t timer;
|
||||
} buttons[MAX_BUTTONS];
|
||||
|
||||
// can't use EXT_RAM_ATTR for initialized structure
|
||||
static struct {
|
||||
int gpio, level;
|
||||
struct button_s *button;
|
||||
} polled_gpio[] = { {36, -1, NULL}, {39, -1, NULL}, {-1, -1, NULL} };
|
||||
int gpio, level;
|
||||
struct button_s* button;
|
||||
} polled_gpio[] = {{36, -1, NULL}, {39, -1, NULL}, {-1, -1, NULL}};
|
||||
|
||||
static TimerHandle_t polled_timer;
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
QueueHandle_t queue;
|
||||
void *client;
|
||||
rotary_encoder_info_t info;
|
||||
int A, B, SW;
|
||||
rotary_handler handler;
|
||||
QueueHandle_t queue;
|
||||
void* client;
|
||||
rotary_encoder_info_t info;
|
||||
int A, B, SW;
|
||||
rotary_handler handler;
|
||||
} rotary;
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
RingbufHandle_t rb;
|
||||
infrared_handler handler;
|
||||
RingbufHandle_t rb;
|
||||
infrared_handler handler;
|
||||
} infrared;
|
||||
|
||||
static EXT_RAM_ATTR QueueHandle_t button_queue;
|
||||
static EXT_RAM_ATTR QueueSetHandle_t common_queue_set;
|
||||
|
||||
static void buttons_task(void* arg);
|
||||
static void buttons_handler(struct button_s *button, int level);
|
||||
static void buttons_handler(struct button_s* button, int level);
|
||||
|
||||
/****************************************************************************************
|
||||
* Start task needed by button,s rotaty and infrared
|
||||
*/
|
||||
static void common_task_init(void) {
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[BUTTON_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
|
||||
if (!common_queue_set) {
|
||||
common_queue_set = xQueueCreateSet(BUTTON_QUEUE_LEN + 1);
|
||||
xTaskCreateStatic( (TaskFunction_t) buttons_task, "buttons", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
|
||||
}
|
||||
}
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__((aligned(4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[BUTTON_STACK_SIZE] __attribute__((aligned(4)));
|
||||
|
||||
if (!common_queue_set) {
|
||||
ESP_LOGD(TAG,"Creating buttons task with a queue set length of %d",BUTTON_QUEUE_LEN+1);
|
||||
common_queue_set = xQueueCreateSet(BUTTON_QUEUE_LEN + 1);
|
||||
xTaskCreateStatic((TaskFunction_t)buttons_task, "buttons", BUTTON_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 2, xStack, &xTaskBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* GPIO low-level ISR handler
|
||||
*/
|
||||
static void IRAM_ATTR gpio_isr_handler(void* arg)
|
||||
{
|
||||
struct button_s *button = (struct button_s*) arg;
|
||||
BaseType_t woken = pdFALSE;
|
||||
static void IRAM_ATTR gpio_isr_handler(void* arg) {
|
||||
struct button_s* button = (struct button_s*)arg;
|
||||
BaseType_t woken = pdFALSE;
|
||||
|
||||
if (xTimerGetPeriod(button->timer) > pdMS_TO_TICKS(button->debounce)) {
|
||||
if (button->gpio < GPIO_NUM_MAX) xTimerChangePeriodFromISR(button->timer, pdMS_TO_TICKS(button->debounce), &woken);
|
||||
else xTimerChangePeriod(button->timer, pdMS_TO_TICKS(button->debounce), pdMS_TO_TICKS(10));
|
||||
} else {
|
||||
if (button->gpio < GPIO_NUM_MAX) xTimerResetFromISR(button->timer, &woken);
|
||||
else xTimerReset(button->timer, portMAX_DELAY);
|
||||
}
|
||||
if (xTimerGetPeriod(button->timer) > pdMS_TO_TICKS(button->debounce)) {
|
||||
if (button->gpio < GPIO_NUM_MAX)
|
||||
xTimerChangePeriodFromISR(button->timer, pdMS_TO_TICKS(button->debounce), &woken);
|
||||
else
|
||||
xTimerChangePeriod(button->timer, pdMS_TO_TICKS(button->debounce), pdMS_TO_TICKS(10));
|
||||
} else {
|
||||
if (button->gpio < GPIO_NUM_MAX)
|
||||
xTimerResetFromISR(button->timer, &woken);
|
||||
else
|
||||
xTimerReset(button->timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
if (woken) portYIELD_FROM_ISR();
|
||||
if (woken) portYIELD_FROM_ISR();
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "INT gpio %u level %u", button->gpio, button->level);
|
||||
ESP_EARLY_LOGD(TAG, "INT gpio %u level %u", button->gpio, button->level);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons debounce/longpress timer
|
||||
*/
|
||||
static void buttons_timer_handler( TimerHandle_t xTimer ) {
|
||||
struct button_s *button = (struct button_s*) pvTimerGetTimerID (xTimer);
|
||||
// if this is an expanded GPIO, must give cache a chance
|
||||
buttons_handler(button, gpio_exp_get_level(button->gpio, (button->debounce * 3) / 2, NULL));
|
||||
static void buttons_timer_handler(TimerHandle_t xTimer) {
|
||||
struct button_s* button = (struct button_s*)pvTimerGetTimerID(xTimer);
|
||||
// if this is an expanded GPIO, must give cache a chance
|
||||
buttons_handler(button, gpio_exp_get_level(button->gpio, (button->debounce * 3) / 2, NULL));
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons polling timer
|
||||
*/
|
||||
static void buttons_polling( TimerHandle_t xTimer ) {
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++) {
|
||||
if (!polled_gpio[i].button) continue;
|
||||
|
||||
int level = gpio_get_level(polled_gpio[i].gpio);
|
||||
|
||||
if (level != polled_gpio[i].level) {
|
||||
polled_gpio[i].level = level;
|
||||
buttons_handler(polled_gpio[i].button, level);
|
||||
}
|
||||
}
|
||||
static void buttons_polling(TimerHandle_t xTimer) {
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++) {
|
||||
if (!polled_gpio[i].button) continue;
|
||||
|
||||
int level = gpio_get_level(polled_gpio[i].gpio);
|
||||
|
||||
if (level != polled_gpio[i].level) {
|
||||
polled_gpio[i].level = level;
|
||||
buttons_handler(polled_gpio[i].button, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Buttons timer handler for press/longpress
|
||||
*/
|
||||
static void buttons_handler(struct button_s *button, int level) {
|
||||
button->level = level;
|
||||
static void buttons_handler(struct button_s* button, int level) {
|
||||
button->level = level;
|
||||
|
||||
if (button->shifter && button->shifter->type == button->shifter->level) button->shifter->shifting = true;
|
||||
if (button->shifter && button->shifter->type == button->shifter->level) button->shifter->shifting = true;
|
||||
|
||||
if (button->long_press && !button->long_timer && button->level == button->type) {
|
||||
// detect a long press, so hold event generation
|
||||
ESP_LOGD(TAG, "setting long timer gpio:%u level:%u", button->gpio, button->level);
|
||||
xTimerChangePeriod(button->timer, button->long_press / portTICK_RATE_MS, 0);
|
||||
button->long_timer = true;
|
||||
} else {
|
||||
// send a button pressed/released event (content is copied in queue)
|
||||
ESP_LOGD(TAG, "sending event for gpio:%u level:%u", button->gpio, button->level);
|
||||
// queue will have a copy of button's context
|
||||
xQueueSend(button_queue, button, 0);
|
||||
button->long_timer = false;
|
||||
}
|
||||
if (button->long_press && !button->long_timer && button->level == button->type) {
|
||||
// detect a long press, so hold event generation
|
||||
ESP_LOGD(TAG, "setting long timer gpio:%u level:%u", button->gpio, button->level);
|
||||
xTimerChangePeriod(button->timer, button->long_press / portTICK_RATE_MS, 0);
|
||||
button->long_timer = true;
|
||||
} else {
|
||||
// send a button pressed/released event (content is copied in queue)
|
||||
ESP_LOGD(TAG, "sending event for gpio:%u level:%u", button->gpio, button->level);
|
||||
// queue will have a copy of button's context
|
||||
xQueueSend(button_queue, button, 0);
|
||||
button->long_timer = false;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get inactivity callback
|
||||
*/
|
||||
static uint32_t buttons_idle_callback(void) {
|
||||
return pdTICKS_TO_MS(xTaskGetTickCount()) - buttons_idle_since;
|
||||
}
|
||||
static uint32_t buttons_idle_callback(void) { return pdTICKS_TO_MS(xTaskGetTickCount()) - buttons_idle_since; }
|
||||
|
||||
/****************************************************************************************
|
||||
* Tasks that calls the appropriate functions when buttons are pressed
|
||||
*/
|
||||
static void buttons_task(void* arg) {
|
||||
ESP_LOGI(TAG, "starting button tasks");
|
||||
|
||||
buttons_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
ESP_LOGI(TAG, "starting button tasks");
|
||||
|
||||
buttons_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
services_sleep_setsleeper(buttons_idle_callback);
|
||||
|
||||
|
||||
while (1) {
|
||||
QueueSetMemberHandle_t xActivatedMember;
|
||||
QueueSetMemberHandle_t xActivatedMember;
|
||||
bool active = true;
|
||||
|
||||
// wait on button, rotary and infrared queues
|
||||
if ((xActivatedMember = xQueueSelectFromSet( common_queue_set, portMAX_DELAY )) == NULL) continue;
|
||||
|
||||
if (xActivatedMember == button_queue) {
|
||||
struct button_s button;
|
||||
button_event_e event;
|
||||
button_press_e press;
|
||||
|
||||
// received a button event
|
||||
xQueueReceive(button_queue, &button, 0);
|
||||
// wait on button, rotary and infrared queues
|
||||
if ((xActivatedMember = xQueueSelectFromSet(common_queue_set, portMAX_DELAY)) == NULL) continue;
|
||||
|
||||
event = (button.level == button.type) ? BUTTON_PRESSED : BUTTON_RELEASED;
|
||||
if (xActivatedMember == button_queue) {
|
||||
struct button_s button;
|
||||
button_event_e event;
|
||||
button_press_e press;
|
||||
|
||||
ESP_LOGD(TAG, "received event:%u from gpio:%u level:%u (timer %u shifting %u)", event, button.gpio, button.level, button.long_timer, button.shifting);
|
||||
// received a button event
|
||||
xQueueReceive(button_queue, &button, 0);
|
||||
|
||||
// find if shifting is activated
|
||||
if (button.shifter && button.shifter->type == button.shifter->level) press = BUTTON_SHIFTED;
|
||||
else press = BUTTON_NORMAL;
|
||||
|
||||
/*
|
||||
long_timer will be set either because we truly have a long press
|
||||
or we have a release before the long press timer elapsed, so two
|
||||
events shall be sent
|
||||
*/
|
||||
if (button.long_timer) {
|
||||
if (event == BUTTON_RELEASED) {
|
||||
// early release of a long-press button, send press/release
|
||||
if (!button.shifting) {
|
||||
button.handler(button.client, BUTTON_PRESSED, press, false);
|
||||
button.handler(button.client, BUTTON_RELEASED, press, false);
|
||||
}
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
} else if (!button.shifting) {
|
||||
// normal long press and not shifting so don't discard
|
||||
button.handler(button.client, BUTTON_PRESSED, press, true);
|
||||
}
|
||||
} else {
|
||||
// normal press/release of a button or release of a long-press button
|
||||
if (!button.shifting) button.handler(button.client, event, press, button.long_press);
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
}
|
||||
} else if (xActivatedMember == rotary.queue) {
|
||||
rotary_encoder_event_t event = { 0 };
|
||||
|
||||
// received a rotary event
|
||||
xQueueReceive(rotary.queue, &event, 0);
|
||||
event = (button.level == button.type) ? BUTTON_PRESSED : BUTTON_RELEASED;
|
||||
|
||||
ESP_LOGD(TAG, "received event:%u from gpio:%u level:%u (timer %u shifting %u)", event, button.gpio, button.level, button.long_timer,
|
||||
button.shifting);
|
||||
|
||||
// find if shifting is activated
|
||||
if (button.shifter && button.shifter->type == button.shifter->level)
|
||||
press = BUTTON_SHIFTED;
|
||||
else
|
||||
press = BUTTON_NORMAL;
|
||||
|
||||
/*
|
||||
long_timer will be set either because we truly have a long press
|
||||
or we have a release before the long press timer elapsed, so two
|
||||
events shall be sent
|
||||
*/
|
||||
if (button.long_timer) {
|
||||
if (event == BUTTON_RELEASED) {
|
||||
// early release of a long-press button, send press/release
|
||||
if (!button.shifting) {
|
||||
button.handler(button.client, BUTTON_PRESSED, press, false);
|
||||
button.handler(button.client, BUTTON_RELEASED, press, false);
|
||||
}
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
} else if (!button.shifting) {
|
||||
// normal long press and not shifting so don't discard
|
||||
button.handler(button.client, BUTTON_PRESSED, press, true);
|
||||
}
|
||||
} else {
|
||||
// normal press/release of a button or release of a long-press button
|
||||
if (!button.shifting) button.handler(button.client, event, press, button.long_press);
|
||||
// button is a copy, so need to go to real context
|
||||
button.self->shifting = false;
|
||||
}
|
||||
} else if (xActivatedMember == rotary.queue) {
|
||||
rotary_encoder_event_t event = {0};
|
||||
|
||||
// received a rotary event
|
||||
xQueueReceive(rotary.queue, &event, 0);
|
||||
|
||||
ESP_LOGD(TAG, "Event: position %d, direction %s", event.state.position,
|
||||
event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
|
||||
|
||||
rotary.handler(rotary.client, event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? ROTARY_RIGHT : ROTARY_LEFT, false);
|
||||
} else {
|
||||
// this is IR
|
||||
active = infrared_receive(infrared.rb, infrared.handler);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Event: position %d, direction %s", event.state.position,
|
||||
event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
|
||||
|
||||
rotary.handler(rotary.client, event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ?
|
||||
ROTARY_RIGHT : ROTARY_LEFT, false);
|
||||
} else {
|
||||
// this is IR
|
||||
active = infrared_receive(infrared.rb, infrared.handler);
|
||||
}
|
||||
|
||||
// mark the last activity
|
||||
if (active) buttons_idle_since = pdTICKS_TO_MS(xTaskGetTickCount());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* dummy button handler
|
||||
*/
|
||||
void dummy_handler(void *id, button_event_e event, button_press_e press) {
|
||||
ESP_LOGW(TAG, "should not be here");
|
||||
}
|
||||
*/
|
||||
void dummy_handler(void* id, button_event_e event, button_press_e press) { ESP_LOGW(TAG, "should not be here"); }
|
||||
|
||||
/****************************************************************************************
|
||||
* Create buttons
|
||||
* Create buttons
|
||||
*/
|
||||
void button_create(void *client, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio) {
|
||||
if (n_buttons >= MAX_BUTTONS) return;
|
||||
void button_create(void* client, int gpio, int type, bool pull, int debounce, button_handler handler, int long_press, int shifter_gpio) {
|
||||
if (n_buttons >= MAX_BUTTONS) return;
|
||||
|
||||
ESP_LOGI(TAG, "Creating button using GPIO %u, type %u, pull-up/down %u, long press %u shifter %d", gpio, type, pull, long_press, shifter_gpio);
|
||||
ESP_LOGI(TAG, "Creating button using GPIO %u, type %s, %s pull-up/down, long press %u shifter %d", gpio,
|
||||
sys_gpio_lvl_name(type == 0 ? sys_gpio_lvl_LOW : sys_gpio_lvl_HIGH), pull?"with":"without", long_press, shifter_gpio);
|
||||
|
||||
if (!n_buttons) {
|
||||
button_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(struct button_s));
|
||||
common_task_init();
|
||||
xQueueAddToSet( button_queue, common_queue_set );
|
||||
}
|
||||
|
||||
// just in case this structure is allocated in a future release
|
||||
memset(buttons + n_buttons, 0, sizeof(struct button_s));
|
||||
if (!n_buttons) {
|
||||
ESP_LOGD(TAG,"Creating new buttton message queue with a length of %d entries",BUTTON_QUEUE_LEN);
|
||||
button_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(struct button_s));
|
||||
common_task_init();
|
||||
xQueueAddToSet(button_queue, common_queue_set);
|
||||
}
|
||||
|
||||
// set mandatory parameters
|
||||
buttons[n_buttons].client = client;
|
||||
buttons[n_buttons].gpio = gpio;
|
||||
buttons[n_buttons].debounce = debounce ? debounce: DEBOUNCE;
|
||||
buttons[n_buttons].handler = handler;
|
||||
buttons[n_buttons].long_press = long_press;
|
||||
buttons[n_buttons].shifter_gpio = shifter_gpio;
|
||||
buttons[n_buttons].type = type;
|
||||
buttons[n_buttons].timer = xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer_handler);
|
||||
buttons[n_buttons].self = buttons + n_buttons;
|
||||
// just in case this structure is allocated in a future release
|
||||
memset(buttons + n_buttons, 0, sizeof(struct button_s));
|
||||
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
// first try to find our shifter
|
||||
if (buttons[i].gpio == shifter_gpio) {
|
||||
buttons[n_buttons].shifter = buttons + i;
|
||||
// a shifter must have a long-press handler
|
||||
if (!buttons[i].long_press) buttons[i].long_press = -1;
|
||||
}
|
||||
// then try to see if we are a non-assigned shifter
|
||||
if (buttons[i].shifter_gpio == gpio) {
|
||||
buttons[i].shifter = buttons + n_buttons;
|
||||
ESP_LOGI(TAG, "post-assigned shifter gpio %u", buttons[i].gpio);
|
||||
}
|
||||
}
|
||||
// set mandatory parameters
|
||||
buttons[n_buttons].client = client;
|
||||
buttons[n_buttons].gpio = gpio;
|
||||
buttons[n_buttons].debounce = debounce ? debounce : DEBOUNCE;
|
||||
buttons[n_buttons].handler = handler;
|
||||
buttons[n_buttons].long_press = long_press;
|
||||
buttons[n_buttons].shifter_gpio = shifter_gpio;
|
||||
buttons[n_buttons].type = type;
|
||||
buttons[n_buttons].timer =
|
||||
xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void*)&buttons[n_buttons], buttons_timer_handler);
|
||||
buttons[n_buttons].self = buttons + n_buttons;
|
||||
|
||||
gpio_pad_select_gpio_x(gpio);
|
||||
gpio_set_direction_x(gpio, GPIO_MODE_INPUT);
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
// first try to find our shifter
|
||||
if (buttons[i].gpio == shifter_gpio) {
|
||||
buttons[n_buttons].shifter = buttons + i;
|
||||
// a shifter must have a long-press handler
|
||||
if (!buttons[i].long_press) buttons[i].long_press = -1;
|
||||
}
|
||||
// then try to see if we are a non-assigned shifter
|
||||
if (buttons[i].shifter_gpio == gpio) {
|
||||
buttons[i].shifter = buttons + n_buttons;
|
||||
ESP_LOGI(TAG, "post-assigned shifter gpio %u", buttons[i].gpio);
|
||||
}
|
||||
}
|
||||
|
||||
// do we need pullup or pulldown
|
||||
if (pull) {
|
||||
if (GPIO_IS_VALID_OUTPUT_GPIO(gpio) || gpio >= GPIO_NUM_MAX) {
|
||||
if (type == BUTTON_LOW) gpio_set_pull_mode_x(gpio, GPIO_PULLUP_ONLY);
|
||||
else gpio_set_pull_mode_x(gpio, GPIO_PULLDOWN_ONLY);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "cannot set pull up/down for gpio %u", gpio);
|
||||
}
|
||||
}
|
||||
|
||||
// and initialize level ...
|
||||
buttons[n_buttons].level = gpio_get_level_x(gpio);
|
||||
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++) if (polled_gpio[i].gpio == gpio) {
|
||||
if (!polled_timer) {
|
||||
polled_timer = xTimerCreate("buttonsPolling", 100 / portTICK_RATE_MS, pdTRUE, polled_gpio, buttons_polling);
|
||||
xTimerStart(polled_timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
polled_gpio[i].button = buttons + n_buttons;
|
||||
polled_gpio[i].level = gpio_get_level(gpio);
|
||||
ESP_LOGW(TAG, "creating polled gpio %u, level %u", gpio, polled_gpio[i].level);
|
||||
|
||||
gpio = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// only create ISR if this is not a polled gpio
|
||||
if (gpio != -1) {
|
||||
// we need any edge detection
|
||||
gpio_set_intr_type_x(gpio, GPIO_INTR_ANYEDGE);
|
||||
gpio_isr_handler_add_x(gpio, gpio_isr_handler, buttons + n_buttons);
|
||||
gpio_intr_enable_x(gpio);
|
||||
}
|
||||
gpio_pad_select_gpio_x(gpio);
|
||||
gpio_set_direction_x(gpio, GPIO_MODE_INPUT);
|
||||
|
||||
n_buttons++;
|
||||
}
|
||||
// do we need pullup or pulldown
|
||||
if (pull) {
|
||||
if (GPIO_IS_VALID_OUTPUT_GPIO(gpio) || gpio >= GPIO_NUM_MAX) {
|
||||
if (type == BUTTON_LOW)
|
||||
gpio_set_pull_mode_x(gpio, GPIO_PULLUP_ONLY);
|
||||
else
|
||||
gpio_set_pull_mode_x(gpio, GPIO_PULLDOWN_ONLY);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "cannot set pull up/down for gpio %u", gpio);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get stored id
|
||||
*/
|
||||
void *button_get_client(int gpio) {
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == gpio) return buttons[i].client;
|
||||
}
|
||||
return NULL;
|
||||
// and initialize level ...
|
||||
buttons[n_buttons].level = gpio_get_level_x(gpio);
|
||||
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
for (int i = 0; polled_gpio[i].gpio != -1; i++)
|
||||
if (polled_gpio[i].gpio == gpio) {
|
||||
if (!polled_timer) {
|
||||
polled_timer = xTimerCreate("buttonsPolling", 100 / portTICK_RATE_MS, pdTRUE, polled_gpio, buttons_polling);
|
||||
xTimerStart(polled_timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
polled_gpio[i].button = buttons + n_buttons;
|
||||
polled_gpio[i].level = gpio_get_level(gpio);
|
||||
ESP_LOGW(TAG, "creating polled gpio %u, level %u", gpio, polled_gpio[i].level);
|
||||
|
||||
gpio = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// only create ISR if this is not a polled gpio
|
||||
if (gpio != -1) {
|
||||
// we need any edge detection
|
||||
gpio_set_intr_type_x(gpio, GPIO_INTR_ANYEDGE);
|
||||
gpio_isr_handler_add_x(gpio, gpio_isr_handler, buttons + n_buttons);
|
||||
gpio_intr_enable_x(gpio);
|
||||
}
|
||||
|
||||
n_buttons++;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Get stored id
|
||||
*/
|
||||
bool button_is_pressed(int gpio, void *client) {
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
if (gpio != -1 && buttons[i].gpio == gpio) return buttons[i].level == buttons[i].type;
|
||||
else if (client && buttons[i].client == client) return buttons[i].level == buttons[i].type;
|
||||
}
|
||||
return false;
|
||||
void* button_get_client(int gpio) {
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == gpio) return buttons[i].client;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Update buttons
|
||||
* Get stored id
|
||||
*/
|
||||
void *button_remap(void *client, int gpio, button_handler handler, int long_press, int shifter_gpio) {
|
||||
int i;
|
||||
struct button_s *button = NULL;
|
||||
void *prev_client;
|
||||
|
||||
ESP_LOGI(TAG, "remapping GPIO %u, long press %u shifter %u", gpio, long_press, shifter_gpio);
|
||||
bool button_is_pressed(int gpio, void* client) {
|
||||
for (int i = 0; i < n_buttons; i++) {
|
||||
if (gpio != -1 && buttons[i].gpio == gpio)
|
||||
return buttons[i].level == buttons[i].type;
|
||||
else if (client && buttons[i].client == client)
|
||||
return buttons[i].level == buttons[i].type;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// find button
|
||||
for (i = 0; i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == gpio) {
|
||||
button = buttons + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't know what we are doing here
|
||||
if (!button) return NULL;
|
||||
|
||||
prev_client = button->client;
|
||||
button->client = client;
|
||||
button->handler = handler;
|
||||
button->long_press = long_press;
|
||||
button->shifter_gpio = shifter_gpio;
|
||||
/****************************************************************************************
|
||||
* Update buttons
|
||||
*/
|
||||
void* button_remap(void* client, int gpio, button_handler handler, int long_press, int shifter_gpio) {
|
||||
int i;
|
||||
struct button_s* button = NULL;
|
||||
void* prev_client;
|
||||
|
||||
// find our shifter (if any)
|
||||
for (i = 0; shifter_gpio != -1 && i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == shifter_gpio) {
|
||||
button->shifter = buttons + i;
|
||||
// a shifter must have a long-press handler
|
||||
if (!buttons[i].long_press) buttons[i].long_press = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prev_client;
|
||||
ESP_LOGI(TAG, "remapping GPIO %u, long press %u shifter %u", gpio, long_press, shifter_gpio);
|
||||
|
||||
// find button
|
||||
for (i = 0; i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == gpio) {
|
||||
button = buttons + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't know what we are doing here
|
||||
if (!button) return NULL;
|
||||
|
||||
prev_client = button->client;
|
||||
button->client = client;
|
||||
button->handler = handler;
|
||||
button->long_press = long_press;
|
||||
button->shifter_gpio = shifter_gpio;
|
||||
|
||||
// find our shifter (if any)
|
||||
for (i = 0; shifter_gpio != -1 && i < n_buttons; i++) {
|
||||
if (buttons[i].gpio == shifter_gpio) {
|
||||
button->shifter = buttons + i;
|
||||
// a shifter must have a long-press handler
|
||||
if (!buttons[i].long_press) buttons[i].long_press = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prev_client;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Rotary encoder handler
|
||||
*/
|
||||
static void rotary_button_handler(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
ESP_LOGI(TAG, "Rotary push-button %d", event);
|
||||
rotary.handler(id, event == BUTTON_PRESSED ? ROTARY_PRESSED : ROTARY_RELEASED, long_press);
|
||||
static void rotary_button_handler(void* id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
ESP_LOGI(TAG, "Rotary push-button %d", event);
|
||||
rotary.handler(id, event == BUTTON_PRESSED ? ROTARY_PRESSED : ROTARY_RELEASED, long_press);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Create rotary encoder
|
||||
*/
|
||||
bool create_rotary(void *id, int A, int B, int SW, int long_press, rotary_handler handler) {
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
if (A == -1 || B == -1 || A == 36 || A == 39 || B == 36 || B == 39) {
|
||||
ESP_LOGI(TAG, "Cannot create rotary %d %d", A, B);
|
||||
return false;
|
||||
}
|
||||
bool create_rotary(void* id, int A, int B, int SW, int long_press, rotary_handler handler) {
|
||||
// nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated
|
||||
if (A == -1 || B == -1 || A == 36 || A == 39 || B == 36 || B == 39) {
|
||||
ESP_LOGI(TAG, "Cannot create rotary %d %d", A, B);
|
||||
return false;
|
||||
}
|
||||
|
||||
rotary.A = A;
|
||||
rotary.B = B;
|
||||
rotary.SW = SW;
|
||||
rotary.client = id;
|
||||
rotary.handler = handler;
|
||||
|
||||
rotary.A = A;
|
||||
rotary.B = B;
|
||||
rotary.SW = SW;
|
||||
rotary.client = id;
|
||||
rotary.handler = handler;
|
||||
|
||||
// Initialise the rotary encoder device with the GPIOs for A and B signals
|
||||
rotary_encoder_init(&rotary.info, A, B);
|
||||
|
||||
|
||||
// Create a queue for events from the rotary encoder driver.
|
||||
rotary.queue = rotary_encoder_create_queue();
|
||||
rotary_encoder_set_queue(&rotary.info, rotary.queue);
|
||||
|
||||
common_task_init();
|
||||
xQueueAddToSet( rotary.queue, common_queue_set );
|
||||
|
||||
// create companion button if rotary has a switch
|
||||
if (SW != -1) button_create(id, SW, BUTTON_LOW, true, 0, rotary_button_handler, long_press, -1);
|
||||
|
||||
ESP_LOGI(TAG, "Created rotary encoder A:%d B:%d, SW:%d", A, B, SW);
|
||||
|
||||
return true;
|
||||
}
|
||||
common_task_init();
|
||||
xQueueAddToSet(rotary.queue, common_queue_set);
|
||||
|
||||
// create companion button if rotary has a switch
|
||||
if (SW != -1) button_create(id, SW, BUTTON_LOW, true, 0, rotary_button_handler, long_press, -1);
|
||||
|
||||
ESP_LOGI(TAG, "Created rotary encoder A:%d B:%d, SW:%d", A, B, SW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Create Infrared
|
||||
*/
|
||||
bool create_infrared(int gpio, infrared_handler handler, infrared_mode_t mode) {
|
||||
// initialize IR infrastructure
|
||||
infrared_init(&infrared.rb, gpio, mode);
|
||||
infrared.handler = handler;
|
||||
|
||||
// join the queue set
|
||||
common_task_init();
|
||||
xRingbufferAddToQueueSetRead(infrared.rb, common_queue_set);
|
||||
|
||||
ESP_LOGI(TAG, "Created infrared receiver using GPIO %u", gpio);
|
||||
|
||||
return (infrared.rb != NULL);
|
||||
}
|
||||
// initialize IR infrastructure
|
||||
infrared_init(&infrared.rb, gpio, mode);
|
||||
infrared.handler = handler;
|
||||
|
||||
// join the queue set
|
||||
common_task_init();
|
||||
xRingbufferAddToQueueSetRead(infrared.rb, common_queue_set);
|
||||
|
||||
ESP_LOGI(TAG, "Created infrared receiver using GPIO %u", gpio);
|
||||
|
||||
return (infrared.rb != NULL);
|
||||
}
|
||||
|
||||
@@ -10,14 +10,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define I2C_SYSTEM_PORT 1
|
||||
#define SPI_SYSTEM_HOST SPI2_HOST
|
||||
|
||||
#define RMT_NEXT_TX_CHANNEL() rmt_system_base_tx_channel++;
|
||||
#define RMT_NEXT_RX_CHANNEL() rmt_system_base_rx_channel--;
|
||||
|
||||
extern int i2c_system_port;
|
||||
extern int i2c_system_speed;
|
||||
extern int spi_system_host;
|
||||
extern int spi_system_dc_gpio;
|
||||
extern int rmt_system_base_tx_channel;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "gpio_exp.h"
|
||||
|
||||
#include "GPIO.pb.h"
|
||||
#define GPIO_EXP_INTR 0x100
|
||||
#define GPIO_EXP_WRITE 0x200
|
||||
|
||||
@@ -181,7 +181,6 @@ gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) {
|
||||
ESP_LOGE(TAG, "Cannot create GPIO expander %s, check i2c/spi configuration", config->model);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_expanders++;
|
||||
expander->first = config->base;
|
||||
expander->last = config->base + config->count - 1;
|
||||
@@ -197,6 +196,12 @@ gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) {
|
||||
message_queue = xQueueCreate(4, sizeof(queue_request_t));
|
||||
service_task = xTaskCreateStatic(service_handler, "gpio_expander", sizeof(xStack), NULL, ESP_TASK_PRIO_MIN + 1, xStack, xTaskBuffer);
|
||||
}
|
||||
if(config->phy.ena_pin>=0){
|
||||
ESP_LOGD(TAG,"Enabling expander with pin %d level %d",config->phy.ena_pin,config->phy.ena_lvl);
|
||||
gpio_pad_select_gpio(config->phy.ena_pin);
|
||||
gpio_set_direction(config->phy.ena_pin, GPIO_MODE_DEF_OUTPUT);
|
||||
gpio_set_level(config->phy.ena_pin, config->phy.ena_lvl);
|
||||
}
|
||||
|
||||
// set interrupt if possible
|
||||
if (config->intr >= 0) {
|
||||
@@ -222,7 +227,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 intr %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, enable pin: %d:%d", config->model, config->base, config->intr, config->phy.addr, config->phy.port, config->phy.host,config->phy.ena_pin,config->phy.ena_lvl);
|
||||
return expander;
|
||||
}
|
||||
|
||||
@@ -377,6 +382,13 @@ esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, gpio_exp_t *ex
|
||||
/******************************************************************************
|
||||
* Wrapper function
|
||||
*/
|
||||
|
||||
void esp_rom_gpio_pad_select_gpio_x(uint32_t gpio){
|
||||
if (gpio < GPIO_NUM_MAX) {
|
||||
esp_rom_gpio_pad_select_gpio(gpio);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t gpio_set_pull_mode_x(int gpio, gpio_pull_mode_t mode) {
|
||||
if (gpio < GPIO_NUM_MAX) return gpio_set_pull_mode(gpio, mode);
|
||||
return gpio_exp_set_pull_mode(gpio, mode, NULL);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <stdint.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
struct gpio_exp_s;
|
||||
|
||||
@@ -29,6 +30,8 @@ typedef struct {
|
||||
uint8_t host;
|
||||
uint8_t cs_pin;
|
||||
};
|
||||
int8_t ena_pin; // enable pin
|
||||
int8_t ena_lvl; // enable level
|
||||
} phy;
|
||||
} gpio_exp_config_t;
|
||||
|
||||
@@ -42,6 +45,7 @@ struct gpio_exp_s* gpio_exp_get_expander(int gpio);
|
||||
For all functions below when <expander> is provided, GPIO's can be numbered from 0. If <expander>
|
||||
is NULL, then GPIO must start from base OR be on-chip
|
||||
*/
|
||||
void esp_rom_gpio_pad_select_gpio_x(uint32_t iopad_num);
|
||||
esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *expander);
|
||||
esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, struct gpio_exp_s *expander);
|
||||
int gpio_exp_get_level(int gpio, int age, struct gpio_exp_s *expander);
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_INFO
|
||||
#include "led.h"
|
||||
#include "Config.h"
|
||||
#include "accessors.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/rmt.h"
|
||||
@@ -14,17 +17,14 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "globdefs.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "services.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "Configurator.h"
|
||||
#include "accessors.h"
|
||||
#include "globdefs.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "led.h"
|
||||
#include "services.h"
|
||||
|
||||
#define MAX_LED 8
|
||||
#define BLOCKTIME 10 // up to portMAX_DELAY
|
||||
@@ -43,7 +43,7 @@ static int8_t led_rmt_channel = -1;
|
||||
static uint32_t scale24(uint32_t bright, uint8_t);
|
||||
|
||||
static const struct rmt_led_param_s {
|
||||
sys_LedTypesEnum type;
|
||||
sys_led_types type;
|
||||
uint8_t bits;
|
||||
// number of ticks in nanoseconds converted in RMT_CLK ticks
|
||||
rmt_item32_t bit_0;
|
||||
@@ -51,7 +51,7 @@ static const struct rmt_led_param_s {
|
||||
uint32_t green, red;
|
||||
uint32_t (*scale)(uint32_t, uint8_t);
|
||||
} rmt_led_param[] = {
|
||||
{sys_LedTypesEnum_LED_TYPE_WS2812, 24, {{{350 / RMT_CLK, 1, 1000 / RMT_CLK, 0}}},
|
||||
{sys_led_types_WS2812, 24, {{{350 / RMT_CLK, 1, 1000 / RMT_CLK, 0}}},
|
||||
{{{1000 / RMT_CLK, 1, 350 / RMT_CLK, 0}}}, 0xff0000, 0x00ff00, scale24},
|
||||
{.type = -1}};
|
||||
|
||||
@@ -73,15 +73,9 @@ static struct led_config_s {
|
||||
int gpio;
|
||||
int color;
|
||||
int bright;
|
||||
sys_LedTypesEnum type;
|
||||
} green = {.gpio = CONFIG_LED_GREEN_GPIO,
|
||||
.color = 0,
|
||||
.bright = -1,
|
||||
.type = sys_LedTypesEnum_LED_TYPE_GPIO},
|
||||
red = {.gpio = CONFIG_LED_RED_GPIO,
|
||||
.color = 0,
|
||||
.bright = -1,
|
||||
.type = sys_LedTypesEnum_LED_TYPE_GPIO};
|
||||
sys_led_types type;
|
||||
} green = {.gpio = -1, .color = 0, .bright = -1, .type = sys_led_types_GPIO},
|
||||
red = {.gpio = -1, .color = 0, .bright = -1, .type = sys_led_types_GPIO};
|
||||
|
||||
static int led_max = 2;
|
||||
|
||||
@@ -127,7 +121,7 @@ static void vCallbackFunction(TimerHandle_t xTimer) {
|
||||
if (!led->timer) return;
|
||||
|
||||
led->on = !led->on;
|
||||
ESP_EARLY_LOGD(TAG, "led vCallbackFunction setting gpio %d level %d (bright:%d)", led->gpio,
|
||||
ESP_EARLY_LOGV(TAG, "led vCallbackFunction setting gpio %d level %d (bright:%d)", led->gpio,
|
||||
led->on, led->bright);
|
||||
set_level(led, led->on);
|
||||
|
||||
@@ -231,12 +225,13 @@ int led_allocate(void) {
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
bool led_config(int idx, sys_LED* led_config) {
|
||||
bool led_config(int idx, sys_led_config* led_config) {
|
||||
if (!led_config->has_gpio) {
|
||||
ESP_LOGD(TAG,"No GPIO configured for %s LED",idx == LED_GREEN ? "GREEN" : "RED");
|
||||
return false;
|
||||
}
|
||||
if (led_config->gpio.pin < 0) {
|
||||
ESP_LOGW(TAG, "LED GPIO -1 ignored");
|
||||
ESP_LOGD(TAG,"GPIO -1 ignored for %s LED",idx == LED_GREEN ? "GREEN" : "RED");
|
||||
return false;
|
||||
}
|
||||
if (idx >= MAX_LED) return false;
|
||||
@@ -247,7 +242,7 @@ bool led_config(int idx, sys_LED* led_config) {
|
||||
leds[idx].rmt = NULL;
|
||||
leds[idx].bright = -1;
|
||||
|
||||
if (led_config->led_type != sys_LedTypesEnum_LED_TYPE_GPIO) {
|
||||
if (led_config->led_type != sys_led_types_GPIO) {
|
||||
// first make sure we have a known addressable led
|
||||
for (const struct rmt_led_param_s* p = rmt_led_param; !leds[idx].rmt && p->type >= 0; p++)
|
||||
if (p->type == led_config->led_type) leds[idx].rmt = p;
|
||||
@@ -285,7 +280,7 @@ bool led_config(int idx, sys_LED* led_config) {
|
||||
|
||||
set_level(leds + idx, false);
|
||||
ESP_LOGI(TAG, "Configuring LED %s %d (on:%d rmt:%s %d%% )", idx == LED_GREEN ? "GREEN" : "RED",
|
||||
led_config->gpio.pin, led_config->gpio.level, sys_LedTypesEnum_name(led_config->led_type),
|
||||
led_config->gpio.pin, led_config->gpio.level, sys_led_types_name(led_config->led_type),
|
||||
led_config->brightness);
|
||||
return true;
|
||||
}
|
||||
@@ -294,6 +289,7 @@ bool led_config(int idx, sys_LED* led_config) {
|
||||
*
|
||||
*/
|
||||
static void led_suspend(void) {
|
||||
ESP_LOGD(TAG,"led_suspend: turning off leds");
|
||||
led_off(LED_GREEN);
|
||||
led_off(LED_RED);
|
||||
}
|
||||
@@ -316,12 +312,12 @@ void set_led_gpio(int gpio, char* value) {
|
||||
while ((p = strchr(p, ':')) != NULL) {
|
||||
p++;
|
||||
if ((strcasestr(p, "ws2812")) != NULL)
|
||||
config->type = sys_LedTypesEnum_LED_TYPE_WS2812;
|
||||
config->type = sys_led_types_WS2812;
|
||||
else
|
||||
config->color = atoi(p);
|
||||
}
|
||||
|
||||
if (config->type != sys_LedTypesEnum_LED_TYPE_GPIO) {
|
||||
if (config->type != sys_led_types_GPIO) {
|
||||
for (const struct rmt_led_param_s* p = rmt_led_param; p->type >= 0; p++) {
|
||||
if (p->type == config->type) {
|
||||
if (config == &green)
|
||||
@@ -335,18 +331,25 @@ void set_led_gpio(int gpio, char* value) {
|
||||
}
|
||||
|
||||
void led_svc_init(void) {
|
||||
sys_Gpios* gpios = NULL;
|
||||
sys_gpios_config* gpios = NULL;
|
||||
bool found = false;
|
||||
|
||||
if (!platform->has_gpios) {
|
||||
ESP_LOGI(TAG, "No LED configured");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG,"Setting up leds");
|
||||
gpios = &platform->gpios;
|
||||
if (gpios->has_greenLED) {
|
||||
led_config(LED_GREEN, &gpios->greenLED);
|
||||
found = found | led_config(LED_GREEN, &gpios->greenLED);
|
||||
}
|
||||
if (gpios->has_redLED) {
|
||||
led_config(LED_RED, &gpios->redLED);
|
||||
found = found | led_config(LED_RED, &gpios->redLED);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG,"Done setting up leds");
|
||||
// make sure we switch off all leds (useful for gpio expanders)
|
||||
services_sleep_setsuspend(led_suspend);
|
||||
if (found) {
|
||||
ESP_LOGD(TAG,"Switching leds off");
|
||||
services_sleep_setsuspend(led_suspend);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef LED_H
|
||||
#define LED_H
|
||||
#include "driver/gpio.h"
|
||||
#include "Configurator.h"
|
||||
#include "Config.h"
|
||||
|
||||
enum { LED_GREEN = 0, LED_RED };
|
||||
#define led_on(idx) led_blink_core(idx, 1, 0, false)
|
||||
@@ -21,7 +21,7 @@ enum { LED_GREEN = 0, LED_RED };
|
||||
#define led_blink_pushed(idx, on, off) led_blink_core(idx, on, off, true)
|
||||
|
||||
// if type is LED_GPIO then color set the GPIO logic value for "on"
|
||||
bool led_config(int idx, sys_LED * led_config);
|
||||
bool led_config(int idx, sys_led_config * led_config);
|
||||
bool led_brightness(int idx, int percent);
|
||||
bool led_blink_core(int idx, int ontime, int offtime, bool push);
|
||||
bool led_unpush(int idx);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/**
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h> // Required for libtelnet.h
|
||||
#include <esp_log.h>
|
||||
#include "stdbool.h"
|
||||
#include <lwip/def.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_attr.h"
|
||||
#include "config.h"
|
||||
#include "stdbool.h"
|
||||
#include <errno.h>
|
||||
#include <esp_log.h>
|
||||
#include <lwip/def.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <stdlib.h> // Required for libtelnet.h
|
||||
#include <string.h>
|
||||
// #include "nvs_utilities.h"
|
||||
|
||||
#include "platform_esp32.h"
|
||||
#include "messaging.h"
|
||||
#include "platform_esp32.h"
|
||||
#include "tools.h"
|
||||
/************************************
|
||||
* Globals
|
||||
@@ -22,290 +22,293 @@
|
||||
|
||||
const static char tag[] = "messaging";
|
||||
typedef struct {
|
||||
struct messaging_list_t * next;
|
||||
char * subscriber_name;
|
||||
size_t max_count;
|
||||
RingbufHandle_t buf_handle;
|
||||
struct messaging_list_t* next;
|
||||
char* subscriber_name;
|
||||
size_t max_count;
|
||||
RingbufHandle_t buf_handle;
|
||||
} messaging_list_t;
|
||||
static messaging_list_t top;
|
||||
#define MSG_LENGTH_AVG 1024
|
||||
|
||||
messaging_list_t * get_struct_ptr(messaging_handle_t handle){
|
||||
return (messaging_list_t *)handle;
|
||||
}
|
||||
messaging_handle_t get_handle_ptr(messaging_list_t * handle){
|
||||
return (messaging_handle_t )handle;
|
||||
}
|
||||
messaging_list_t* get_struct_ptr(messaging_handle_t handle) { return (messaging_list_t*)handle; }
|
||||
messaging_handle_t get_handle_ptr(messaging_list_t* handle) { return (messaging_handle_t)handle; }
|
||||
|
||||
RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){
|
||||
RingbufHandle_t buf_handle = NULL;
|
||||
StaticRingbuffer_t *buffer_struct = malloc_init_external(sizeof(StaticRingbuffer_t));
|
||||
if (buffer_struct != NULL) {
|
||||
size_t buf_size = (size_t )(sizeof(single_message_t)+8+MSG_LENGTH_AVG)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes
|
||||
buf_size = buf_size - (buf_size % 4);
|
||||
uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_32BIT);
|
||||
if (buffer_storage== NULL) {
|
||||
ESP_LOGE(tag,"buff alloc failed");
|
||||
}
|
||||
else {
|
||||
buf_handle = xRingbufferCreateStatic(buf_size, RINGBUF_TYPE_NOSPLIT, buffer_storage, buffer_struct);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(tag,"ringbuf alloc failed");
|
||||
}
|
||||
return buf_handle;
|
||||
RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count) {
|
||||
RingbufHandle_t buf_handle = NULL;
|
||||
StaticRingbuffer_t* buffer_struct = malloc_init_external(sizeof(StaticRingbuffer_t));
|
||||
if (buffer_struct != NULL) {
|
||||
size_t buf_size =
|
||||
(size_t)(sizeof(single_message_t) + 8 + MSG_LENGTH_AVG) *
|
||||
(size_t)(max_count > 0 ? max_count
|
||||
: 5); // no-split buffer requires an additional 8 bytes
|
||||
buf_size = buf_size - (buf_size % 4);
|
||||
uint8_t* buffer_storage =
|
||||
(uint8_t*)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_32BIT);
|
||||
if (buffer_storage == NULL) {
|
||||
ESP_LOGE(tag, "buff alloc failed");
|
||||
} else {
|
||||
buf_handle = xRingbufferCreateStatic(
|
||||
buf_size, RINGBUF_TYPE_NOSPLIT, buffer_storage, buffer_struct);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(tag, "ringbuf alloc failed");
|
||||
}
|
||||
return buf_handle;
|
||||
}
|
||||
void messaging_fill_messages(messaging_list_t * target_subscriber){
|
||||
single_message_t * message=NULL;
|
||||
void messaging_fill_messages(messaging_list_t* target_subscriber) {
|
||||
single_message_t* message = NULL;
|
||||
UBaseType_t uxItemsWaiting;
|
||||
|
||||
if (!top.buf_handle) {
|
||||
ESP_LOGE(tag, "Queue initialization error!");
|
||||
return;
|
||||
}
|
||||
vRingbufferGetInfo(top.buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
for(size_t i=0;i<uxItemsWaiting;i++){
|
||||
message= messaging_retrieve_message(top.buf_handle);
|
||||
if(message){
|
||||
//re-post to original queue so it is available to future subscribers
|
||||
messaging_post_to_queue(get_handle_ptr(&top), message, message->msg_size);
|
||||
// post to new subscriber
|
||||
messaging_post_to_queue(get_handle_ptr(target_subscriber) , message, message->msg_size);
|
||||
FREE_AND_NULL(message);
|
||||
}
|
||||
for (size_t i = 0; i < uxItemsWaiting; i++) {
|
||||
message = messaging_retrieve_message(top.buf_handle);
|
||||
if (message) {
|
||||
// re-post to original queue so it is available to future subscribers
|
||||
messaging_post_to_queue(get_handle_ptr(&top), message, message->msg_size);
|
||||
// post to new subscriber
|
||||
messaging_post_to_queue(get_handle_ptr(target_subscriber), message, message->msg_size);
|
||||
FREE_AND_NULL(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
messaging_handle_t messaging_register_subscriber(uint8_t max_count, char * name){
|
||||
messaging_list_t * cur=⊤
|
||||
while(cur->next){
|
||||
cur = get_struct_ptr(cur->next);
|
||||
}
|
||||
cur->next=malloc_init_external(sizeof(messaging_list_t));
|
||||
if(!cur->next){
|
||||
ESP_LOGE(tag,"subscriber alloc failed");
|
||||
return NULL;
|
||||
}
|
||||
memset(cur->next,0x00,sizeof(messaging_list_t));
|
||||
cur = get_struct_ptr(cur->next);
|
||||
cur->max_count=max_count;
|
||||
cur->subscriber_name=strdup_psram(name);
|
||||
cur->buf_handle = messaging_create_ring_buffer(max_count);
|
||||
if(cur->buf_handle){
|
||||
messaging_fill_messages(cur);
|
||||
}
|
||||
return cur->buf_handle;
|
||||
messaging_handle_t messaging_register_subscriber(uint8_t max_count, char* name) {
|
||||
messaging_list_t* cur = ⊤
|
||||
while (cur->next) {
|
||||
cur = get_struct_ptr(cur->next);
|
||||
}
|
||||
cur->next = malloc_init_external(sizeof(messaging_list_t));
|
||||
if (!cur->next) {
|
||||
ESP_LOGE(tag, "subscriber alloc failed");
|
||||
return NULL;
|
||||
}
|
||||
memset(cur->next, 0x00, sizeof(messaging_list_t));
|
||||
cur = get_struct_ptr(cur->next);
|
||||
cur->max_count = max_count;
|
||||
cur->subscriber_name = strdup_psram(name);
|
||||
cur->buf_handle = messaging_create_ring_buffer(max_count);
|
||||
if (cur->buf_handle) {
|
||||
messaging_fill_messages(cur);
|
||||
}
|
||||
return cur->buf_handle;
|
||||
}
|
||||
void messaging_service_init(){
|
||||
size_t max_count=15;
|
||||
top.buf_handle = messaging_create_ring_buffer(max_count);
|
||||
if(!top.buf_handle){
|
||||
ESP_LOGE(tag, "messaging service init failed.");
|
||||
}
|
||||
else {
|
||||
top.max_count = max_count;
|
||||
top.subscriber_name = strdup_psram("messaging");
|
||||
}
|
||||
return;
|
||||
void messaging_service_init() {
|
||||
size_t max_count = 15;
|
||||
ESP_LOGI(tag, "Setting up messaging");
|
||||
top.buf_handle = messaging_create_ring_buffer(max_count);
|
||||
if (!top.buf_handle) {
|
||||
ESP_LOGE(tag, "messaging service init failed.");
|
||||
} else {
|
||||
top.max_count = max_count;
|
||||
top.subscriber_name = strdup_psram("messaging");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const char * messaging_get_type_desc(messaging_types msg_type){
|
||||
switch (msg_type) {
|
||||
CASE_TO_STR(MESSAGING_INFO);
|
||||
CASE_TO_STR(MESSAGING_WARNING);
|
||||
CASE_TO_STR(MESSAGING_ERROR);
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
const char* messaging_get_type_desc(messaging_types msg_type) {
|
||||
switch (msg_type) {
|
||||
CASE_TO_STR(MESSAGING_INFO);
|
||||
CASE_TO_STR(MESSAGING_WARNING);
|
||||
CASE_TO_STR(MESSAGING_ERROR);
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char * messaging_get_class_desc(messaging_classes msg_class){
|
||||
switch (msg_class) {
|
||||
CASE_TO_STR(MESSAGING_CLASS_OTA);
|
||||
CASE_TO_STR(MESSAGING_CLASS_SYSTEM);
|
||||
CASE_TO_STR(MESSAGING_CLASS_STATS);
|
||||
CASE_TO_STR(MESSAGING_CLASS_CFGCMD);
|
||||
CASE_TO_STR(MESSAGING_CLASS_BT);
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
const char* messaging_get_class_desc(messaging_classes msg_class) {
|
||||
switch (msg_class) {
|
||||
CASE_TO_STR(MESSAGING_CLASS_OTA);
|
||||
CASE_TO_STR(MESSAGING_CLASS_SYSTEM);
|
||||
CASE_TO_STR(MESSAGING_CLASS_STATS);
|
||||
CASE_TO_STR(MESSAGING_CLASS_CFGCMD);
|
||||
CASE_TO_STR(MESSAGING_CLASS_BT);
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){
|
||||
single_message_t * message=NULL;
|
||||
cJSON * json_messages=cJSON_CreateArray();
|
||||
cJSON * json_message=NULL;
|
||||
size_t item_size;
|
||||
cJSON* messaging_retrieve_messages(RingbufHandle_t buf_handle) {
|
||||
single_message_t* message = NULL;
|
||||
cJSON* json_messages = cJSON_CreateArray();
|
||||
cJSON* json_message = NULL;
|
||||
size_t item_size;
|
||||
UBaseType_t uxItemsWaiting;
|
||||
vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
for(int i = 0;i<uxItemsWaiting;i++){
|
||||
message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
//Check received data
|
||||
if (message== NULL) {
|
||||
ESP_LOGE(tag,"received null ptr");
|
||||
}
|
||||
else {
|
||||
json_message = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(json_message, "message", message->message);
|
||||
cJSON_AddStringToObject(json_message, "type", messaging_get_type_desc(message->type));
|
||||
cJSON_AddStringToObject(json_message, "class", messaging_get_class_desc(message->msg_class));
|
||||
cJSON_AddNumberToObject(json_message,"sent_time",message->sent_time);
|
||||
cJSON_AddNumberToObject(json_message,"current_time",esp_timer_get_time() / 1000);
|
||||
cJSON_AddItemToArray(json_messages,json_message);
|
||||
vRingbufferReturnItem(buf_handle, (void *)message);
|
||||
}
|
||||
}
|
||||
return json_messages;
|
||||
for (int i = 0; i < uxItemsWaiting; i++) {
|
||||
message = (single_message_t*)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
// Check received data
|
||||
if (message == NULL) {
|
||||
ESP_LOGE(tag, "received null ptr");
|
||||
} else {
|
||||
json_message = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(json_message, "message", message->message);
|
||||
cJSON_AddStringToObject(json_message, "type", messaging_get_type_desc(message->type));
|
||||
cJSON_AddStringToObject(
|
||||
json_message, "class", messaging_get_class_desc(message->msg_class));
|
||||
cJSON_AddNumberToObject(json_message, "sent_time", message->sent_time);
|
||||
cJSON_AddNumberToObject(json_message, "current_time", esp_timer_get_time() / 1000);
|
||||
cJSON_AddItemToArray(json_messages, json_message);
|
||||
vRingbufferReturnItem(buf_handle, (void*)message);
|
||||
}
|
||||
}
|
||||
return json_messages;
|
||||
}
|
||||
single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle){
|
||||
single_message_t * message=NULL;
|
||||
single_message_t * message_copy=NULL;
|
||||
size_t item_size;
|
||||
single_message_t* messaging_retrieve_message(RingbufHandle_t buf_handle) {
|
||||
single_message_t* message = NULL;
|
||||
single_message_t* message_copy = NULL;
|
||||
size_t item_size;
|
||||
UBaseType_t uxItemsWaiting;
|
||||
vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
if(uxItemsWaiting>0){
|
||||
message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
message_copy = clone_obj_psram(message,item_size);
|
||||
vRingbufferReturnItem(buf_handle, (void *)message);
|
||||
}
|
||||
return message_copy;
|
||||
if (uxItemsWaiting > 0) {
|
||||
message = (single_message_t*)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
message_copy = clone_obj_psram(message, item_size);
|
||||
vRingbufferReturnItem(buf_handle, (void*)message);
|
||||
}
|
||||
return message_copy;
|
||||
}
|
||||
|
||||
esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_message_t * message, size_t message_size){
|
||||
size_t item_size=0;
|
||||
messaging_list_t * subscriber=get_struct_ptr(subscriber_handle);
|
||||
if(!subscriber->buf_handle){
|
||||
ESP_LOGE(tag,"post failed: null buffer for %s", str_or_unknown(subscriber->subscriber_name));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
void * pItem=NULL;
|
||||
UBaseType_t res=pdFALSE;
|
||||
while(1){
|
||||
ESP_LOGD(tag,"Attempting to reserve %d bytes for %s",message_size, str_or_unknown(subscriber->subscriber_name));
|
||||
res = xRingbufferSendAcquire(subscriber->buf_handle, &pItem, message_size, pdMS_TO_TICKS(50));
|
||||
if(res == pdTRUE && pItem){
|
||||
ESP_LOGD(tag,"Reserving complete for %s", str_or_unknown(subscriber->subscriber_name));
|
||||
memcpy(pItem,message,message_size);
|
||||
xRingbufferSendComplete(subscriber->buf_handle, pItem);
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(tag,"Dropping for %s",str_or_unknown(subscriber->subscriber_name));
|
||||
single_message_t * dummy = (single_message_t *)xRingbufferReceive(subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
if (dummy== NULL) {
|
||||
ESP_LOGE(tag,"Dropping message failed");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(tag,"Dropping message of %d bytes for %s",item_size, str_or_unknown(subscriber->subscriber_name));
|
||||
vRingbufferReturnItem(subscriber->buf_handle, (void *)dummy);
|
||||
}
|
||||
}
|
||||
if (res != pdTRUE) {
|
||||
ESP_LOGE(tag,"post to %s failed",str_or_unknown(subscriber->subscriber_name));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
esp_err_t messaging_post_to_queue(
|
||||
messaging_handle_t subscriber_handle, single_message_t* message, size_t message_size) {
|
||||
size_t item_size = 0;
|
||||
messaging_list_t* subscriber = get_struct_ptr(subscriber_handle);
|
||||
if (!subscriber->buf_handle) {
|
||||
ESP_LOGE(
|
||||
tag, "post failed: null buffer for %s", str_or_unknown(subscriber->subscriber_name));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
void* pItem = NULL;
|
||||
UBaseType_t res = pdFALSE;
|
||||
while (1) {
|
||||
ESP_LOGD(tag, "Attempting to reserve %d bytes for %s", message_size,
|
||||
str_or_unknown(subscriber->subscriber_name));
|
||||
res =
|
||||
xRingbufferSendAcquire(subscriber->buf_handle, &pItem, message_size, pdMS_TO_TICKS(50));
|
||||
if (res == pdTRUE && pItem) {
|
||||
ESP_LOGD(tag, "Reserving complete for %s", str_or_unknown(subscriber->subscriber_name));
|
||||
memcpy(pItem, message, message_size);
|
||||
xRingbufferSendComplete(subscriber->buf_handle, pItem);
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(tag, "Dropping for %s", str_or_unknown(subscriber->subscriber_name));
|
||||
single_message_t* dummy = (single_message_t*)xRingbufferReceive(
|
||||
subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50));
|
||||
if (dummy == NULL) {
|
||||
ESP_LOGE(tag, "Dropping message failed");
|
||||
break;
|
||||
} else {
|
||||
ESP_LOGD(tag, "Dropping message of %d bytes for %s", item_size,
|
||||
str_or_unknown(subscriber->subscriber_name));
|
||||
vRingbufferReturnItem(subscriber->buf_handle, (void*)dummy);
|
||||
}
|
||||
}
|
||||
if (res != pdTRUE) {
|
||||
ESP_LOGE(tag, "post to %s failed", str_or_unknown(subscriber->subscriber_name));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
esp_err_t messaging_type_to_err_type(messaging_types type){
|
||||
switch (type) {
|
||||
case MESSAGING_INFO:
|
||||
return ESP_LOG_INFO;
|
||||
break;
|
||||
case MESSAGING_ERROR:
|
||||
return ESP_LOG_ERROR;
|
||||
break;
|
||||
case MESSAGING_WARNING:
|
||||
return ESP_LOG_WARN;
|
||||
break;
|
||||
default:
|
||||
return ESP_LOG_DEBUG;
|
||||
break;
|
||||
}
|
||||
return ESP_LOG_DEBUG;
|
||||
}
|
||||
|
||||
void messaging_post_message(messaging_types type,messaging_classes msg_class, const char *fmt, ...){
|
||||
esp_err_t messaging_type_to_err_type(messaging_types type) {
|
||||
switch (type) {
|
||||
case MESSAGING_INFO:
|
||||
return ESP_LOG_INFO;
|
||||
break;
|
||||
case MESSAGING_ERROR:
|
||||
return ESP_LOG_ERROR;
|
||||
break;
|
||||
case MESSAGING_WARNING:
|
||||
return ESP_LOG_WARN;
|
||||
break;
|
||||
default:
|
||||
return ESP_LOG_DEBUG;
|
||||
break;
|
||||
}
|
||||
return ESP_LOG_DEBUG;
|
||||
}
|
||||
|
||||
void messaging_post_message(
|
||||
messaging_types type, messaging_classes msg_class, const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
va_start(va, fmt);
|
||||
vmessaging_post_message(type, msg_class, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void vmessaging_post_message(messaging_types type,messaging_classes msg_class, const char *fmt, va_list va){
|
||||
single_message_t * message=NULL;
|
||||
size_t msg_size=0;
|
||||
size_t ln =0;
|
||||
messaging_list_t * cur=⊤
|
||||
ln = vsnprintf(NULL, 0, fmt, va)+1;
|
||||
msg_size = sizeof(single_message_t)+ln;
|
||||
message = (single_message_t *)malloc_init_external(msg_size);
|
||||
vsprintf(message->message, fmt, va);
|
||||
message->msg_size = msg_size;
|
||||
message->type = type;
|
||||
message->msg_class = msg_class;
|
||||
message->sent_time = esp_timer_get_time() / 1000;
|
||||
if(type==MESSAGING_WARNING) {
|
||||
ESP_LOGW(tag,"%s",message->message);
|
||||
}
|
||||
else if(type==MESSAGING_ERROR) {
|
||||
ESP_LOGE(tag,"%s",message->message);
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(tag,"Post: %s",message->message);
|
||||
}
|
||||
|
||||
while(cur){
|
||||
messaging_post_to_queue(get_handle_ptr(cur), message, msg_size);
|
||||
cur = get_struct_ptr(cur->next);
|
||||
}
|
||||
FREE_AND_NULL(message);
|
||||
return;
|
||||
void vmessaging_post_message(
|
||||
messaging_types type, messaging_classes msg_class, const char* fmt, va_list va) {
|
||||
single_message_t* message = NULL;
|
||||
size_t msg_size = 0;
|
||||
size_t ln = 0;
|
||||
messaging_list_t* cur = ⊤
|
||||
ln = vsnprintf(NULL, 0, fmt, va) + 1;
|
||||
msg_size = sizeof(single_message_t) + ln;
|
||||
message = (single_message_t*)malloc_init_external(msg_size);
|
||||
vsprintf(message->message, fmt, va);
|
||||
message->msg_size = msg_size;
|
||||
message->type = type;
|
||||
message->msg_class = msg_class;
|
||||
message->sent_time = esp_timer_get_time() / 1000;
|
||||
if (type == MESSAGING_WARNING) {
|
||||
ESP_LOGW(tag, "%s", message->message);
|
||||
} else if (type == MESSAGING_ERROR) {
|
||||
ESP_LOGE(tag, "%s", message->message);
|
||||
} else {
|
||||
ESP_LOGD(tag, "Post: %s", message->message);
|
||||
}
|
||||
|
||||
while (cur) {
|
||||
messaging_post_to_queue(get_handle_ptr(cur), message, msg_size);
|
||||
cur = get_struct_ptr(cur->next);
|
||||
}
|
||||
FREE_AND_NULL(message);
|
||||
return;
|
||||
}
|
||||
char * messaging_alloc_format_string(const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
|
||||
char * message_txt = malloc_init_external(ln);
|
||||
if(message_txt){
|
||||
vsprintf(message_txt, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
else{
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
return message_txt;
|
||||
char* messaging_alloc_format_string(const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va) + 1;
|
||||
char* message_txt = malloc_init_external(ln);
|
||||
if (message_txt) {
|
||||
vsprintf(message_txt, fmt, va);
|
||||
va_end(va);
|
||||
} else {
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
return message_txt;
|
||||
}
|
||||
void log_send_messaging(messaging_types msgtype,const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
|
||||
char * message_txt = malloc_init_external(ln);
|
||||
if(message_txt){
|
||||
vsprintf(message_txt, fmt, va);
|
||||
va_end(va);
|
||||
ESP_LOG_LEVEL_LOCAL(messaging_type_to_err_type(msgtype),tag, "%s",message_txt);
|
||||
messaging_post_message(msgtype, MESSAGING_CLASS_SYSTEM, message_txt );
|
||||
free(message_txt);
|
||||
}
|
||||
else{
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
void log_send_messaging(messaging_types msgtype, const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va) + 1;
|
||||
char* message_txt = malloc_init_external(ln);
|
||||
if (message_txt) {
|
||||
vsprintf(message_txt, fmt, va);
|
||||
va_end(va);
|
||||
ESP_LOG_LEVEL_LOCAL(messaging_type_to_err_type(msgtype), tag, "%s", message_txt);
|
||||
messaging_post_message(msgtype, MESSAGING_CLASS_SYSTEM, message_txt);
|
||||
free(message_txt);
|
||||
} else {
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_send_messaging(const char * cmdname,messaging_types msgtype, const char *fmt, ...){
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t cmd_len = strlen(cmdname)+1;
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va)+1;
|
||||
char * message_txt = malloc_init_external(ln+cmd_len);
|
||||
if(message_txt){
|
||||
strcpy(message_txt,cmdname);
|
||||
strcat(message_txt,"\n");
|
||||
vsprintf((message_txt+cmd_len), fmt, va);
|
||||
va_end(va);
|
||||
ESP_LOG_LEVEL_LOCAL(messaging_type_to_err_type(msgtype),tag, "%s",message_txt);
|
||||
messaging_post_message(msgtype, MESSAGING_CLASS_CFGCMD, message_txt );
|
||||
free(message_txt);
|
||||
}
|
||||
else{
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
void cmd_send_messaging(const char* cmdname, messaging_types msgtype, const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
size_t cmd_len = strlen(cmdname) + 1;
|
||||
size_t ln = vsnprintf(NULL, 0, fmt, va) + 1;
|
||||
char* message_txt = malloc_init_external(ln + cmd_len);
|
||||
if (message_txt) {
|
||||
strcpy(message_txt, cmdname);
|
||||
strcat(message_txt, "\n");
|
||||
vsprintf((message_txt + cmd_len), fmt, va);
|
||||
va_end(va);
|
||||
ESP_LOG_LEVEL_LOCAL(messaging_type_to_err_type(msgtype), tag, "%s", message_txt);
|
||||
messaging_post_message(msgtype, MESSAGING_CLASS_CFGCMD, message_txt);
|
||||
free(message_txt);
|
||||
} else {
|
||||
ESP_LOGE(tag, "Memory allocation failed while sending message");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_INFO
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "buttons.h"
|
||||
#include "led.h"
|
||||
#include "globdefs.h"
|
||||
// #include "Configurator.h"
|
||||
// TODO: Add support for the commented code: search for TODO in the code below")
|
||||
#include "accessors.h"
|
||||
#include "messaging.h"
|
||||
#include "cJSON.h"
|
||||
@@ -163,7 +161,7 @@ static void jack_handler_default(void *id, button_event_e event, button_press_e
|
||||
*
|
||||
*/
|
||||
bool jack_inserted_svc (void) {
|
||||
sys_GPIO * jack=NULL;
|
||||
sys_gpio_config * jack=NULL;
|
||||
if(SYS_GPIOS_NAME(jack,jack)){
|
||||
return button_is_pressed(jack->pin, NULL);
|
||||
}
|
||||
@@ -184,7 +182,7 @@ static void spkfault_handler_default(void *id, button_event_e event, button_pres
|
||||
*
|
||||
*/
|
||||
bool spkfault_svc (void) {
|
||||
sys_GPIO * spkfault=NULL;
|
||||
sys_gpio_config * spkfault=NULL;
|
||||
if(SYS_GPIOS_NAME(spkfault,spkfault)){
|
||||
return button_is_pressed(spkfault->pin, NULL);
|
||||
}
|
||||
@@ -209,10 +207,10 @@ static void pseudo_idle(void *arg) {
|
||||
*/
|
||||
void monitor_svc_init(void) {
|
||||
ESP_LOGI(TAG, "Initializing monitoring");
|
||||
sys_Services * services = NULL;
|
||||
sys_GPIO * gpio=NULL;
|
||||
sys_services_config * services = NULL;
|
||||
sys_gpio_config * gpio=NULL;
|
||||
if(SYS_GPIOS_NAME(jack,gpio) && gpio->pin>=0){
|
||||
ESP_LOGI(TAG,"Adding jack (%s) detection GPIO %d", gpio->level ? "high" : "low", gpio->pin);
|
||||
ESP_LOGI(TAG,"Adding jack (%s) detection GPIO %d", sys_gpio_lvl_name(gpio->level), gpio->pin);
|
||||
button_create(NULL, gpio->pin, gpio->level ? BUTTON_HIGH : BUTTON_LOW, false, 250, jack_handler_default, 0, -1);
|
||||
}
|
||||
if(SYS_GPIOS_NAME(spkfault,gpio) && gpio->pin>=0){
|
||||
@@ -220,7 +218,7 @@ void monitor_svc_init(void) {
|
||||
button_create(NULL, gpio->pin, gpio->level ? BUTTON_HIGH : BUTTON_LOW, false, 0, spkfault_handler_default, 0, -1);
|
||||
}
|
||||
// do we want stats
|
||||
monitor_stats = SYS_SERVICES(services) && services->statistics;
|
||||
monitor_stats = sys_services_config(services) && services->statistics;
|
||||
|
||||
ESP_LOGI(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
|
||||
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Squeezelite for esp32
|
||||
*
|
||||
* (c) Philippe G. 2019, philippe_44@outlook.com
|
||||
@@ -7,8 +7,11 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void (*pseudo_idle_svc)(uint32_t now);
|
||||
|
||||
extern void (*jack_handler_svc)(bool inserted);
|
||||
@@ -20,3 +23,6 @@ extern bool spkfault_svc(void);
|
||||
extern void (*battery_handler_svc)(float value, int cells);
|
||||
extern float battery_value_svc(void);
|
||||
extern uint16_t battery_level_svc(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -5,44 +5,46 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#include <stdio.h>
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
#include "Config.h"
|
||||
#include "accessors.h"
|
||||
#include "battery.h"
|
||||
#include "buttons.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "Configurator.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "battery.h"
|
||||
#include "led.h"
|
||||
#include "monitor.h"
|
||||
#include "globdefs.h"
|
||||
#include "accessors.h"
|
||||
#include "gpio_exp.h"
|
||||
#include "led.h"
|
||||
#include "messaging.h"
|
||||
#include "buttons.h"
|
||||
#include "monitor.h"
|
||||
#include "services.h"
|
||||
#include "tools.h"
|
||||
|
||||
extern void battery_svc_init(void);
|
||||
extern void monitor_svc_init(void);
|
||||
extern void led_svc_init(void);
|
||||
|
||||
int i2c_system_port = I2C_SYSTEM_PORT;
|
||||
int i2c_system_speed = 400000;
|
||||
int spi_system_host = SPI_SYSTEM_HOST;
|
||||
int spi_system_dc_gpio = -1;
|
||||
int rmt_system_base_tx_channel = RMT_CHANNEL_0;
|
||||
int rmt_system_base_rx_channel = RMT_CHANNEL_MAX-1;
|
||||
int rmt_system_base_rx_channel = RMT_CHANNEL_MAX - 1;
|
||||
|
||||
pwm_system_t pwm_system = {
|
||||
.timer = LEDC_TIMER_0,
|
||||
.base_channel = LEDC_CHANNEL_0,
|
||||
.max = (1 << LEDC_TIMER_13_BIT),
|
||||
.timer = LEDC_TIMER_0,
|
||||
.base_channel = LEDC_CHANNEL_0,
|
||||
.max = (1 << LEDC_TIMER_13_BIT),
|
||||
};
|
||||
static sys_SleepService * sleep_config;
|
||||
static sys_sleep_config* sleep_config;
|
||||
static EXT_RAM_ATTR uint8_t gpio_exp_count = 0;
|
||||
static EXT_RAM_ATTR bool spi_configured = false;
|
||||
static EXT_RAM_ATTR bool i2c_configured = false;
|
||||
static EXT_RAM_ATTR struct {
|
||||
uint64_t wake_gpio, wake_level;
|
||||
uint64_t rtc_gpio, rtc_level;
|
||||
@@ -55,31 +57,93 @@ static EXT_RAM_ATTR struct {
|
||||
uint32_t (*sleeper[10])(void);
|
||||
} sleep_context;
|
||||
|
||||
static const char *TAG = "services";
|
||||
static const char* TAG = "services";
|
||||
|
||||
void set_gpio_level(sys_GPIO*gpio,const char * name, gpio_mode_t mode){
|
||||
bool are_GPIOExp_equal(const sys_exp_config* exp1, const sys_exp_config* exp2) {
|
||||
if (exp1 == NULL || exp2 == NULL) {
|
||||
return false; // Safeguard against NULL pointers
|
||||
}
|
||||
|
||||
// Check if model, address, and base are the same
|
||||
if (exp1->model != exp2->model || exp1->addr != exp2->addr || exp1->base != exp2->base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if intr structure (pin and level) are the same
|
||||
if (exp1->intr != exp2->intr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sys_dev_config_callback(pb_istream_t* istream, pb_ostream_t* ostream, const pb_field_iter_t* field) {
|
||||
ESP_LOGV(TAG, "Decoding/Encoding Devices, tag: %d", field->tag);
|
||||
sys_exp_config** pExp = (sys_exp_config**)field->pData;
|
||||
sys_exp_config* exp = NULL;
|
||||
|
||||
if (istream != NULL && field->tag == sys_dev_config_gpio_exp_tag) {
|
||||
ESP_LOGD(TAG, "Decoding GPIO Expander #%d", gpio_exp_count + 1);
|
||||
sys_exp_config entry = sys_exp_config_init_default;
|
||||
if (!pb_decode(istream, &sys_exp_config_msg, &entry)) {
|
||||
return false;
|
||||
}
|
||||
if (entry.model == sys_exp_models_UNSPECIFIED_EXP) {
|
||||
ESP_LOGD(TAG, "Skipping GPIO Expander model %s", sys_exp_models_name(entry.model));
|
||||
return true;
|
||||
}
|
||||
// Don't add the expander if it was already decoded. This could
|
||||
// happen if both the configuration and the platform configuration
|
||||
// contain the definition.
|
||||
for (int i = 0; i < gpio_exp_count; i++) {
|
||||
if (are_GPIOExp_equal(&(*pExp)[i], &entry)) {
|
||||
ESP_LOGW(TAG, "GPIO Expander entry already exists, skipping addition.");
|
||||
return true; // Skip adding as it already exists
|
||||
}
|
||||
}
|
||||
|
||||
gpio_exp_count++;
|
||||
|
||||
*pExp = heap_caps_realloc(*pExp, sizeof(sys_exp_config) * gpio_exp_count, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
|
||||
// Assert after realloc to ensure memory allocation was successful
|
||||
assert(*pExp != NULL);
|
||||
exp = (*pExp) + gpio_exp_count - 1; // Simplified pointer arithmetic
|
||||
memcpy(exp, &entry, sizeof(entry));
|
||||
ESP_LOGD(TAG, "GPIO Expander #%d model %s", gpio_exp_count, sys_exp_models_name(entry.model));
|
||||
|
||||
} else if (ostream != NULL && field->tag == sys_dev_config_gpio_exp_tag) {
|
||||
ESP_LOGV(TAG, "Encoding %d GPIO Expanders", gpio_exp_count);
|
||||
|
||||
for (int i = 0; i < gpio_exp_count; i++) {
|
||||
if (!pb_encode_tag_for_field(ostream, field)) {
|
||||
return false;
|
||||
}
|
||||
if (!pb_encode_submessage(ostream, &sys_exp_config_msg, &(*pExp)[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "GPIO Expander encoding completed");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_gpio_level(sys_gpio_config* gpio, const char* name, gpio_mode_t mode) {
|
||||
ESP_LOGI(TAG, "set GPIO %u to %s, level %d", gpio->pin, name, gpio->level);
|
||||
if (gpio->pin < 0) {
|
||||
ESP_LOGW(TAG, "Invalid gpio %d for %s", gpio->pin, name);
|
||||
return;
|
||||
}
|
||||
gpio_pad_select_gpio(gpio->pin);
|
||||
gpio_set_direction(gpio->pin, mode);
|
||||
gpio_set_level(gpio->pin, gpio->level);
|
||||
ESP_LOGI(TAG, "set GPIO %u to %s, level %d", gpio->pin,name, gpio->level);
|
||||
}
|
||||
void set_chip_power_gpio(sys_Gpios*gpios) {
|
||||
|
||||
if(gpios->has_power){
|
||||
gpios->power.level = 1;
|
||||
set_gpio_level(&gpios->power,"vcc", GPIO_MODE_OUTPUT);
|
||||
}
|
||||
if(gpios->has_GND){
|
||||
gpios->GND.level = 0;
|
||||
set_gpio_level(&gpios->GND,"gnd", GPIO_MODE_OUTPUT);
|
||||
}
|
||||
|
||||
gpio_set_level(gpio->pin, gpio->level);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void sleep_gpio_handler(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
static void sleep_gpio_handler(void* id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
if (event == BUTTON_PRESSED) services_sleep_activate(SLEEP_ONGPIO);
|
||||
}
|
||||
|
||||
@@ -96,7 +160,7 @@ static void sleep_timer(uint32_t now) {
|
||||
if (!first) first = now;
|
||||
|
||||
// only query callbacks every 30s if we have at least one sleeper
|
||||
if (!*sleep_context.sleeper || now < last + 30*1000) return;
|
||||
if (!*sleep_context.sleeper || now < last + 30 * 1000) return;
|
||||
last = now;
|
||||
|
||||
// time to evaluate if we had spurious wake-up
|
||||
@@ -151,12 +215,13 @@ static void sleep_battery(float level, int cells) {
|
||||
*
|
||||
*/
|
||||
void services_sleep_init(void) {
|
||||
ESP_LOGD(TAG,"Initializing sleep services");
|
||||
if(!SYS_SERVICES_SLEEP(sleep_config)){
|
||||
ESP_LOGD(TAG,"No sleep service configured") ;
|
||||
ESP_LOGD(TAG, "Initializing sleep services");
|
||||
if (!sys_services_config_SLEEP(sleep_config)) {
|
||||
ESP_LOGD(TAG, "No sleep service configured");
|
||||
return;
|
||||
}
|
||||
// get the wake criteria
|
||||
for(int i=0;i<sleep_config->wake_count;i++){
|
||||
for (int i = 0; i < sleep_config->wake_count; i++) {
|
||||
if (!rtc_gpio_is_valid_gpio(sleep_config->wake[i].pin)) {
|
||||
ESP_LOGE(TAG, "invalid wake GPIO %d (not in RTC domain)", sleep_config->wake[i].pin);
|
||||
} else {
|
||||
@@ -165,7 +230,8 @@ void services_sleep_init(void) {
|
||||
sleep_context.wake_level |= sleep_config->wake[i].level << sleep_config->wake[i].pin;
|
||||
}
|
||||
}
|
||||
// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can be done
|
||||
// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can
|
||||
// be done
|
||||
if (sleep_context.wake_gpio) {
|
||||
ESP_LOGI(TAG, "Sleep wake-up gpio bitmap 0x%llx (active 0x%llx)", sleep_context.wake_gpio, sleep_context.wake_level);
|
||||
}
|
||||
@@ -177,7 +243,7 @@ void services_sleep_init(void) {
|
||||
battery_handler_svc = sleep_battery;
|
||||
ESP_LOGI(TAG, "Sleep on battery level of %.2f", sleep_context.battery_level);
|
||||
}
|
||||
for(int i = 0;i<sleep_config->rtc_count;i++){
|
||||
for (int i = 0; i < sleep_config->rtc_count; i++) {
|
||||
if (!rtc_gpio_is_valid_gpio(sleep_config->rtc[i].pin)) {
|
||||
ESP_LOGE(TAG, "invalid rtc GPIO %d", sleep_config->rtc[i].pin);
|
||||
} else {
|
||||
@@ -185,20 +251,21 @@ void services_sleep_init(void) {
|
||||
sleep_context.rtc_level |= sleep_config->rtc[i].level << sleep_config->rtc[i].pin;
|
||||
}
|
||||
}
|
||||
// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can be done
|
||||
// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can
|
||||
// be done
|
||||
if (sleep_context.rtc_gpio) {
|
||||
ESP_LOGI(TAG, "RTC forced gpio bitmap 0x%llx (active 0x%llx)", sleep_context.rtc_gpio, sleep_context.rtc_level);
|
||||
}
|
||||
|
||||
// get the GPIOs that activate sleep (we could check that we have a valid wake)
|
||||
if(sleep_config->has_sleep && sleep_config->sleep.pin >=0 ){
|
||||
ESP_LOGI(TAG, "Sleep activation gpio %d (active %d)", sleep_config->sleep.pin, sleep_config->sleep.level);
|
||||
if (sleep_config->has_sleep && sleep_config->sleep.pin >= 0) {
|
||||
ESP_LOGI(TAG, "Sleep activation gpio %d (active %d)", sleep_config->sleep.pin, sleep_config->sleep.level);
|
||||
button_create(NULL, sleep_config->sleep.pin, sleep_config->sleep.level ? BUTTON_HIGH : BUTTON_LOW, true, 0, sleep_gpio_handler, 0, -1);
|
||||
}
|
||||
|
||||
// do we want delay sleep
|
||||
|
||||
sleep_context.delay = sleep_config->delay*60*1000;
|
||||
|
||||
sleep_context.delay = sleep_config->delay * 60 * 1000;
|
||||
|
||||
// now check why we woke-up
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
@@ -207,17 +274,19 @@ void services_sleep_init(void) {
|
||||
|
||||
// find the type of wake-up
|
||||
uint64_t wake_gpio;
|
||||
if (cause == ESP_SLEEP_WAKEUP_EXT0) wake_gpio = sleep_context.wake_gpio;
|
||||
else wake_gpio = esp_sleep_get_ext1_wakeup_status();
|
||||
if (cause == ESP_SLEEP_WAKEUP_EXT0)
|
||||
wake_gpio = sleep_context.wake_gpio;
|
||||
else
|
||||
wake_gpio = esp_sleep_get_ext1_wakeup_status();
|
||||
|
||||
// we might be woken up by infrared in which case we want a short sleep
|
||||
if (infrared_gpio() >= 0 && ((1LL << infrared_gpio()) & wake_gpio)) {
|
||||
sleep_context.spurious = 1;
|
||||
if(sleep_config->spurious>0){
|
||||
if (sleep_config->spurious > 0) {
|
||||
sleep_context.spurious = sleep_config->spurious;
|
||||
}
|
||||
sleep_context.spurious *= 60*1000;
|
||||
|
||||
sleep_context.spurious *= 60 * 1000;
|
||||
|
||||
ESP_LOGI(TAG, "spurious wake-up detection during %d sec", sleep_context.spurious / 1000);
|
||||
}
|
||||
}
|
||||
@@ -226,7 +295,7 @@ void services_sleep_init(void) {
|
||||
if (sleep_context.delay || sleep_context.spurious) {
|
||||
sleep_context.idle_chain = pseudo_idle_svc;
|
||||
pseudo_idle_svc = sleep_timer;
|
||||
if (sleep_context.delay) ESP_LOGI(TAG, "inactivity timer of %d minute(s)", sleep_context.delay / (60*1000));
|
||||
if (sleep_context.delay) ESP_LOGI(TAG, "inactivity timer of %d minute(s)", sleep_context.delay / (60 * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +304,8 @@ void services_sleep_init(void) {
|
||||
*/
|
||||
void services_sleep_activate(sleep_cause_e cause) {
|
||||
// call all sleep hooks that might want to do something
|
||||
for (void (**suspend)(void) = sleep_context.suspend; *suspend; suspend++) (*suspend)();
|
||||
for (void (**suspend)(void) = sleep_context.suspend; *suspend; suspend++)
|
||||
(*suspend)();
|
||||
|
||||
// isolate all possible GPIOs, except the wake-up and RTC-maintaines ones
|
||||
esp_sleep_config_gpio_isolate();
|
||||
@@ -249,9 +319,11 @@ void services_sleep_activate(sleep_cause_e cause) {
|
||||
|
||||
// do we need to maintain a pull-up or down of that GPIO
|
||||
if ((1LL << i) & sleep_context.rtc_gpio) {
|
||||
if ((sleep_context.rtc_level >> i) & 0x01) rtc_gpio_pullup_en(i);
|
||||
else rtc_gpio_pulldown_en(i);
|
||||
// or is this not wake-up GPIO, just isolate it
|
||||
if ((sleep_context.rtc_level >> i) & 0x01)
|
||||
rtc_gpio_pullup_en(i);
|
||||
else
|
||||
rtc_gpio_pulldown_en(i);
|
||||
// or is this not wake-up GPIO, just isolate it
|
||||
} else if (!((1LL << i) & sleep_context.wake_gpio)) {
|
||||
rtc_gpio_isolate(i);
|
||||
}
|
||||
@@ -261,10 +333,11 @@ void services_sleep_activate(sleep_cause_e cause) {
|
||||
if (sleep_context.wake_gpio & (sleep_context.wake_gpio - 1)) {
|
||||
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on multiple GPIO, any '1' wakes up 0x%llx", cause, sleep_context.wake_gpio);
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
|
||||
if (!sleep_context.wake_level) esp_sleep_enable_ext1_wakeup(sleep_context.wake_gpio, ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
if (!sleep_context.wake_level)
|
||||
esp_sleep_enable_ext1_wakeup(sleep_context.wake_gpio, ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
else
|
||||
#endif
|
||||
esp_sleep_enable_ext1_wakeup(sleep_context.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
esp_sleep_enable_ext1_wakeup(sleep_context.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
} else if (sleep_context.wake_gpio) {
|
||||
int gpio = __builtin_ctzll(sleep_context.wake_gpio);
|
||||
int level = (sleep_context.wake_level >> gpio) & 0x01;
|
||||
@@ -274,136 +347,186 @@ void services_sleep_activate(sleep_cause_e cause) {
|
||||
ESP_LOGW(TAG, "going to sleep cause %d, no wake-up option", cause);
|
||||
}
|
||||
|
||||
// we need to use a timer in case the same button is used for sleep and wake-up and it's "pressed" vs "released" selected
|
||||
if (cause == SLEEP_ONKEY) xTimerStart(xTimerCreate("sleepTimer", pdMS_TO_TICKS(1000), pdFALSE, NULL, (void (*)(void*)) esp_deep_sleep_start), 0);
|
||||
else esp_deep_sleep_start();
|
||||
// we need to use a timer in case the same button is used for sleep and wake-up and it's
|
||||
// "pressed" vs "released" selected
|
||||
if (cause == SLEEP_ONKEY)
|
||||
xTimerStart(xTimerCreate("sleepTimer", pdMS_TO_TICKS(1000), pdFALSE, NULL, (void (*)(void*))esp_deep_sleep_start), 0);
|
||||
else
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
static void register_method(void **store, size_t size, void *method) {
|
||||
for (int i = 0; i < size; i++, *store++) if (!*store) {
|
||||
*store = method;
|
||||
return;
|
||||
}
|
||||
static void register_method(void** store, size_t size, void* method) {
|
||||
for (int i = 0; i < size; i++, *store++)
|
||||
if (!*store) {
|
||||
*store = method;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void services_sleep_setsuspend(void (*hook)(void)) {
|
||||
register_method((void**) sleep_context.suspend, sizeof(sleep_context.suspend)/sizeof(*sleep_context.suspend), (void*) hook);
|
||||
register_method((void**)sleep_context.suspend, sizeof(sleep_context.suspend) / sizeof(*sleep_context.suspend), (void*)hook);
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void services_sleep_setsleeper(uint32_t (*sleeper)(void)) {
|
||||
register_method((void**) sleep_context.sleeper, sizeof(sleep_context.sleeper)/sizeof(*sleep_context.sleeper), (void*) sleeper);
|
||||
register_method((void**)sleep_context.sleeper, sizeof(sleep_context.sleeper) / sizeof(*sleep_context.sleeper), (void*)sleeper);
|
||||
}
|
||||
void services_ports_init(void) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing ports");
|
||||
gpio_install_isr_service(0);
|
||||
ESP_LOGD(TAG, "Checking i2c port usage");
|
||||
if (platform->dev.dac.has_i2c && platform->dev.has_i2c && platform->dev.dac.i2c.port != sys_i2c_port_UNSPECIFIED &&
|
||||
platform->dev.dac.i2c.port == platform->dev.i2c.port) {
|
||||
ESP_LOGE(TAG, "Port %s is used for internal DAC use. Switching to ", sys_i2c_port_name(platform->dev.dac.i2c.port));
|
||||
platform->dev.i2c.port = platform->dev.i2c.port == sys_i2c_port_PORT0 ? sys_i2c_port_PORT1 : sys_i2c_port_PORT0;
|
||||
config_raise_changed(false);
|
||||
}
|
||||
|
||||
// shared I2C bus
|
||||
ESP_LOGD(TAG, "Configuring I2C");
|
||||
const i2c_config_t* i2c_config = config_i2c_get(&platform->dev.i2c);
|
||||
ESP_LOGD(TAG, "Stored I2C configuration [sda:%d scl:%d port:%s speed:%u]", i2c_config->sda_io_num, i2c_config->scl_io_num,
|
||||
sys_i2c_port_name(platform->dev.i2c.port), i2c_config->master.clk_speed);
|
||||
if (i2c_config->sda_io_num != -1 && i2c_config->scl_io_num != -1) {
|
||||
ESP_LOGI(TAG, "Configuring I2C sda:%d scl:%d port:%s speed:%u", i2c_config->sda_io_num, i2c_config->scl_io_num,
|
||||
sys_i2c_port_name(platform->dev.i2c.port), i2c_config->master.clk_speed);
|
||||
i2c_param_config(platform->dev.i2c.port - sys_i2c_port_PORT0, i2c_config);
|
||||
if ((err = i2c_driver_install(platform->dev.i2c.port - sys_i2c_port_PORT0, i2c_config->mode, 0, 0, 0)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error setting up i2c: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
i2c_configured = true;
|
||||
}
|
||||
} else {
|
||||
if (platform->dev.has_display && platform->dev.display.has_common && platform->dev.display.which_dispType == sys_display_config_i2c_tag) {
|
||||
ESP_LOGE(TAG, "I2C configuration missing for display %s", sys_display_drivers_name(platform->dev.display.common.driver));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Shared I2C not configured");
|
||||
}
|
||||
}
|
||||
|
||||
const spi_bus_config_t* spi_config = config_spi_get((spi_host_device_t*)&spi_system_host);
|
||||
ESP_LOGD(TAG, "Stored SPI configuration[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) {
|
||||
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 ((err = spi_bus_initialize(spi_system_host, spi_config, SPI_DMA_CH_AUTO)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error setting up SPI bus: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
spi_configured = true;
|
||||
}
|
||||
if (spi_system_dc_gpio != -1) {
|
||||
gpio_reset_pin(spi_system_dc_gpio);
|
||||
gpio_set_direction(spi_system_dc_gpio, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(spi_system_dc_gpio, 0);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "No DC GPIO set, SPI display will not work");
|
||||
}
|
||||
} else {
|
||||
spi_system_host = -1;
|
||||
if (platform->dev.has_display && platform->dev.display.has_common &&
|
||||
platform->dev.display.common.driver != sys_display_drivers_UNSPECIFIED &&
|
||||
platform->dev.display.which_dispType == sys_display_config_spi_tag) {
|
||||
ESP_LOGE(TAG, "SPI bus configuration missing for display %s", sys_display_drivers_name(platform->dev.display.common.driver));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "SPI bus not configured");
|
||||
}
|
||||
}
|
||||
}
|
||||
void services_gpio_init(void) {
|
||||
ESP_LOGI(TAG, "Initializing GPIOs");
|
||||
// set potential power GPIO on chip first in case expanders are power using these
|
||||
sys_gpio_config* gpio = NULL;
|
||||
if (SYS_GPIOS_NAME(power, gpio) && gpio->pin >= 0) {
|
||||
ESP_LOGD(TAG, "Handling power gpio");
|
||||
gpio->level = sys_gpio_lvl_HIGH;
|
||||
set_gpio_level(gpio, "power", GPIO_MODE_OUTPUT);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "No power GPIO defined");
|
||||
}
|
||||
|
||||
if (SYS_GPIOS_NAME(GND, gpio) && gpio->pin >= 0) {
|
||||
ESP_LOGD(TAG, "Handling GND gpio");
|
||||
gpio->level = sys_gpio_lvl_LOW;
|
||||
set_gpio_level(gpio, "GND", GPIO_MODE_OUTPUT);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "No GND gpio defined");
|
||||
}
|
||||
|
||||
// create GPIO expanders
|
||||
gpio_exp_config_t gpio_exp_config;
|
||||
if (platform->has_dev && gpio_exp_count > 0 && platform->dev.gpio_exp[0].model != sys_exp_models_UNSPECIFIED_EXP) {
|
||||
ESP_LOGI(TAG, "Initializing %d GPIO Expander(s)", gpio_exp_count);
|
||||
for (int count = 0; count < gpio_exp_count; count++) {
|
||||
sys_exp_config* exp = &platform->dev.gpio_exp[count];
|
||||
if (exp->model == sys_exp_models_UNSPECIFIED_EXP) {
|
||||
ESP_LOGD(TAG, "Skipping unknown model");
|
||||
continue;
|
||||
}
|
||||
gpio_exp_config.phy.ena_pin = -1;
|
||||
gpio_exp_config.base = exp->base;
|
||||
gpio_exp_config.count = exp->count;
|
||||
gpio_exp_config.phy.addr = exp->addr;
|
||||
gpio_exp_config.intr = exp->intr;
|
||||
if (exp->has_ena && exp->ena.pin >= 0) {
|
||||
gpio_exp_config.phy.ena_pin = exp->ena.pin;
|
||||
gpio_exp_config.phy.ena_lvl = exp->ena.level;
|
||||
}
|
||||
if (exp->which_ExpType == sys_exp_config_spi_tag) {
|
||||
if (!spi_configured) {
|
||||
ESP_LOGE(TAG, "SPI bus not configured for GPIO Expander index %d (%s)", count, sys_exp_models_name(exp->model));
|
||||
continue;
|
||||
}
|
||||
gpio_exp_config.phy.cs_pin = exp->ExpType.spi.cs;
|
||||
gpio_exp_config.phy.host =
|
||||
(!platform->dev.has_spi || (platform->dev.has_spi && platform->dev.spi.host == sys_dev_common_hosts_NONE) ? sys_dev_common_hosts_Host0 : platform->dev.spi.host) - sys_dev_common_hosts_Host0;
|
||||
gpio_exp_config.phy.speed = exp->ExpType.spi.speed > 0 ? exp->ExpType.spi.speed : 0;
|
||||
} else {
|
||||
if (!i2c_configured) {
|
||||
ESP_LOGE(TAG, "I2C bus not configured for GPIO Expander index %d (%s)", count, sys_exp_models_name(exp->model));
|
||||
continue;
|
||||
}
|
||||
gpio_exp_config.phy.port =
|
||||
((!platform->dev.has_i2c || (platform->dev.has_i2c && platform->dev.i2c.port == sys_i2c_port_UNSPECIFIED) )? sys_dev_common_ports_SYSTEM : platform->dev.i2c.port) - sys_dev_common_ports_SYSTEM ;
|
||||
}
|
||||
strncpy(gpio_exp_config.model, sys_exp_models_name(exp->model), sizeof(gpio_exp_config.model) - 1);
|
||||
gpio_exp_create(&gpio_exp_config);
|
||||
}
|
||||
} else if (gpio_exp_count > 0) {
|
||||
ESP_LOGW(TAG, "GPIO Expander count %d but none is valid", gpio_exp_count);
|
||||
}
|
||||
}
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
void services_init(void) {
|
||||
messaging_service_init();
|
||||
gpio_install_isr_service(0);
|
||||
// todo: untangle i2c stuff
|
||||
#ifdef CONFIG_I2C_LOCKED
|
||||
if (i2c_system_port == 0) {
|
||||
i2c_system_port = 1;
|
||||
ESP_LOGE(TAG, "Port 0 is reserved for internal DAC use");
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Initializing services");
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// set potential power GPIO on chip first in case expanders are power using these
|
||||
set_chip_power_gpio(&platform->gpios);
|
||||
|
||||
// shared I2C bus
|
||||
const i2c_config_t * i2c_config = config_i2c_get(&i2c_system_port);
|
||||
ESP_LOGI(TAG,"Configuring I2C sda:%d scl:%d port:%u speed:%u", i2c_config->sda_io_num, i2c_config->scl_io_num, i2c_system_port, i2c_config->master.clk_speed);
|
||||
|
||||
if (i2c_config->sda_io_num != -1 && i2c_config->scl_io_num != -1) {
|
||||
i2c_param_config(i2c_system_port, i2c_config);
|
||||
i2c_driver_install(i2c_system_port, i2c_config->mode, 0, 0, 0 );
|
||||
} else {
|
||||
i2c_system_port = -1;
|
||||
ESP_LOGW(TAG, "no I2C configured");
|
||||
}
|
||||
|
||||
const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host);
|
||||
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, SPI_DMA_CH_AUTO );
|
||||
if (spi_system_dc_gpio != -1) {
|
||||
gpio_reset_pin(spi_system_dc_gpio);
|
||||
gpio_set_direction( spi_system_dc_gpio, GPIO_MODE_OUTPUT );
|
||||
gpio_set_level( spi_system_dc_gpio, 0 );
|
||||
} else {
|
||||
ESP_LOGW(TAG, "No DC GPIO set, SPI display will not work");
|
||||
}
|
||||
} else {
|
||||
spi_system_host = -1;
|
||||
ESP_LOGW(TAG, "no SPI configured");
|
||||
}
|
||||
|
||||
// create GPIO expanders
|
||||
gpio_exp_config_t gpio_exp_config;
|
||||
if(platform->has_dev && platform->dev.gpio_exp_count>0){
|
||||
for(int count = 0;count<platform->dev.gpio_exp_count;count++){
|
||||
sys_GPIOExp * exp = &platform->dev.gpio_exp[count];
|
||||
gpio_exp_config.base = exp->base;
|
||||
gpio_exp_config.count = exp->count;
|
||||
gpio_exp_config.phy.addr = exp->addr;
|
||||
if(exp->has_intr){
|
||||
gpio_exp_config.intr = exp->intr.pin;
|
||||
}
|
||||
else {
|
||||
ESP_LOGW(TAG,"Expander doesn't have intr pin");
|
||||
}
|
||||
if(exp->which_ExpType == sys_GPIOExp_spi_tag){
|
||||
gpio_exp_config.phy.cs_pin= exp->ExpType.spi.cs.pin;
|
||||
gpio_exp_config.phy.host = exp->ExpType.spi.host == sys_HostEnum_UNSPECIFIED_HOST ?sys_HostEnum_Host0:exp->ExpType.spi.host -1;
|
||||
gpio_exp_config.phy.speed = exp->ExpType.spi.speed>0?exp->ExpType.spi.speed:0;
|
||||
}
|
||||
else {
|
||||
gpio_exp_config.phy.port = exp->ExpType.i2c.port == sys_PortEnum_UNSPECIFIED_SYSTPORT?sys_PortEnum_SYSTEM:exp->ExpType.i2c.port -1;
|
||||
}
|
||||
strncpy(gpio_exp_config.model,sys_GPIOExpModelEnum_name(exp->model),sizeof(gpio_exp_config.model)-1);
|
||||
gpio_exp_create(&gpio_exp_config);
|
||||
}
|
||||
}
|
||||
if(platform->has_gpios ){
|
||||
// if(platform->gpios.has_GND){
|
||||
// platform->gpios.GND.level = 0;
|
||||
// set_gpio_level(&platform->gpios.GND,"GND", GPIO_MODE_OUTPUT);
|
||||
// }
|
||||
// if(platform->gpios.has_Vcc){
|
||||
// platform->gpios.Vcc.level = 1;
|
||||
// set_gpio_level(&platform->gpios.Vcc,"VCC", GPIO_MODE_OUTPUT);
|
||||
// }
|
||||
set_chip_power_gpio(&platform->gpios);
|
||||
}
|
||||
|
||||
|
||||
// system-wide PWM timer configuration
|
||||
ledc_timer_config_t pwm_timer = {
|
||||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.freq_hz = 5000,
|
||||
// system-wide PWM timer configuration
|
||||
ledc_timer_config_t pwm_timer = {
|
||||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.freq_hz = 5000,
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
#else
|
||||
.speed_mode = LEDC_HIGH_SPEED_MODE,
|
||||
.speed_mode = LEDC_HIGH_SPEED_MODE,
|
||||
#endif
|
||||
.timer_num = pwm_system.timer,
|
||||
};
|
||||
.timer_num = pwm_system.timer,
|
||||
};
|
||||
|
||||
ledc_timer_config(&pwm_timer);
|
||||
|
||||
led_svc_init();
|
||||
battery_svc_init();
|
||||
monitor_svc_init();
|
||||
ledc_timer_config(&pwm_timer);
|
||||
led_svc_init();
|
||||
battery_svc_init();
|
||||
monitor_svc_init();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
#include "Configurator.h"
|
||||
#include "Config.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#pragma once
|
||||
@@ -17,4 +17,4 @@ void services_sleep_activate(sleep_cause_e cause);
|
||||
void services_sleep_setsuspend(void (*hook)(void));
|
||||
void services_sleep_setsleeper(uint32_t (*sleeper)(void));
|
||||
void services_sleep_init(void);
|
||||
void set_gpio_level(sys_GPIO*gpio,const char * name, gpio_mode_t mode);
|
||||
void set_gpio_level(sys_gpio_config*gpio,const char * name, gpio_mode_t mode);
|
||||
|
||||
44
components/services/system_time.c
Normal file
44
components/services/system_time.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/* LwIP SNTP example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include "Config.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_sntp.h"
|
||||
#include "esp_system.h"
|
||||
#include "tools.h"
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
static const char* TAG = "system_time";
|
||||
|
||||
void system_time_init(void) {
|
||||
char strftime_buf[64];
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
const char* timezone =
|
||||
platform->has_services && platform->services.timezone && strlen(platform->services.timezone) > 0 ? platform->services.timezone : "EST5EDT,M3.2.0/2,M11.1.0";
|
||||
setenv("TZ", timezone, 1);
|
||||
tzset();
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
// Is time set? If not, tm_year will be (1970 - 1900).
|
||||
if (timeinfo.tm_year < (2016 - 1900)) {
|
||||
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
|
||||
sntp_servermode_dhcp(2);
|
||||
esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
|
||||
esp_sntp_setservername(0, "pool.ntp.org");
|
||||
esp_sntp_init();
|
||||
|
||||
} else {
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
ESP_LOGI(TAG, "Current date/time is: %s for time zone %s", strftime_buf, timezone);
|
||||
}
|
||||
}
|
||||
2
components/services/system_time.h
Normal file
2
components/services/system_time.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once;
|
||||
void system_time_init(void);
|
||||
Reference in New Issue
Block a user