Start of 5.X work

This commit is contained in:
Sebastien L
2025-03-18 17:38:34 -04:00
parent c0ddf0a997
commit 73bd096f37
442 changed files with 227862 additions and 21075 deletions

View File

@@ -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
)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
/****************************************************************************************

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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=&top;
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 = &top;
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=&top;
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 = &top;
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");
}
}

View File

@@ -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),

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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);

View 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);
}
}

View File

@@ -0,0 +1,2 @@
#pragma once;
void system_time_init(void);