mirror of
https://github.com/esphome/esphome.git
synced 2024-11-24 07:58:09 +01:00
Merge branch 'dev' into radon_eye_rd200-v2-add
This commit is contained in:
commit
02845e7169
12 changed files with 146 additions and 74 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
@ -315,7 +315,9 @@ jobs:
|
||||||
key: platformio-${{ matrix.pio_cache_key }}
|
key: platformio-${{ matrix.pio_cache_key }}
|
||||||
|
|
||||||
- name: Install clang-tidy
|
- name: Install clang-tidy
|
||||||
run: sudo apt-get install clang-tidy-14
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install clang-tidy-14
|
||||||
|
|
||||||
- name: Register problem matchers
|
- name: Register problem matchers
|
||||||
run: |
|
run: |
|
||||||
|
@ -397,7 +399,9 @@ jobs:
|
||||||
file: ${{ fromJson(needs.list-components.outputs.components) }}
|
file: ${{ fromJson(needs.list-components.outputs.components) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install libsdl2-dev
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install libsdl2-dev
|
||||||
|
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.1.7
|
||||||
|
@ -451,7 +455,9 @@ jobs:
|
||||||
run: echo ${{ matrix.components }}
|
run: echo ${{ matrix.components }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install libsdl2-dev
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install libsdl2-dev
|
||||||
|
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
|
@ -22,7 +22,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||||
|
|
||||||
size_t buffer_size = this->get_buffer_size_();
|
size_t buffer_size = this->get_buffer_size_();
|
||||||
|
|
||||||
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
RAMAllocator<uint8_t> allocator(this->use_psram_ ? 0 : RAMAllocator<uint8_t>::ALLOC_INTERNAL);
|
||||||
this->buf_ = allocator.allocate(buffer_size);
|
this->buf_ = allocator.allocate(buffer_size);
|
||||||
if (this->buf_ == nullptr) {
|
if (this->buf_ == nullptr) {
|
||||||
ESP_LOGE(TAG, "Cannot allocate LED buffer!");
|
ESP_LOGE(TAG, "Cannot allocate LED buffer!");
|
||||||
|
@ -37,7 +37,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalRAMAllocator<rmt_item32_t> rmt_allocator(ExternalRAMAllocator<rmt_item32_t>::ALLOW_FAILURE);
|
RAMAllocator<rmt_item32_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_item32_t>::ALLOC_INTERNAL);
|
||||||
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 +
|
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 +
|
||||||
1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset
|
1); // 8 bits per byte, 1 rmt_item32_t per bit + 1 rmt_item32_t for reset
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||||
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
|
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
|
||||||
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
|
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
|
||||||
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
|
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
|
||||||
|
void set_use_psram(bool use_psram) { this->use_psram_ = use_psram; }
|
||||||
|
|
||||||
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
||||||
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
||||||
|
@ -75,6 +76,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||||
uint16_t num_leds_;
|
uint16_t num_leds_;
|
||||||
bool is_rgbw_;
|
bool is_rgbw_;
|
||||||
bool is_wrgb_;
|
bool is_wrgb_;
|
||||||
|
bool use_psram_;
|
||||||
|
|
||||||
rmt_item32_t bit0_, bit1_, reset_;
|
rmt_item32_t bit0_, bit1_, reset_;
|
||||||
RGBOrder rgb_order_;
|
RGBOrder rgb_order_;
|
||||||
|
|
|
@ -55,7 +55,7 @@ CHIPSETS = {
|
||||||
"SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0),
|
"SM16703": LEDStripTimings(300, 900, 900, 300, 0, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONF_USE_PSRAM = "use_psram"
|
||||||
CONF_IS_WRGB = "is_wrgb"
|
CONF_IS_WRGB = "is_wrgb"
|
||||||
CONF_BIT0_HIGH = "bit0_high"
|
CONF_BIT0_HIGH = "bit0_high"
|
||||||
CONF_BIT0_LOW = "bit0_low"
|
CONF_BIT0_LOW = "bit0_low"
|
||||||
|
@ -77,6 +77,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
|
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
|
||||||
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
|
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
|
||||||
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
|
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_USE_PSRAM, default=True): cv.boolean,
|
||||||
cv.Inclusive(
|
cv.Inclusive(
|
||||||
CONF_BIT0_HIGH,
|
CONF_BIT0_HIGH,
|
||||||
"custom",
|
"custom",
|
||||||
|
@ -145,6 +146,7 @@ async def to_code(config):
|
||||||
cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
|
cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
|
||||||
cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
|
cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
|
||||||
cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))
|
cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))
|
||||||
|
cg.add(var.set_use_psram(config[CONF_USE_PSRAM]))
|
||||||
|
|
||||||
cg.add(
|
cg.add(
|
||||||
var.set_rmt_channel(
|
var.set_rmt_channel(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import mqtt
|
from esphome.components import mqtt, web_server
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DEVICE_CLASS,
|
CONF_DEVICE_CLASS,
|
||||||
|
@ -11,6 +11,7 @@ from esphome.const import (
|
||||||
CONF_MQTT_ID,
|
CONF_MQTT_ID,
|
||||||
CONF_ON_EVENT,
|
CONF_ON_EVENT,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
|
CONF_WEB_SERVER,
|
||||||
DEVICE_CLASS_BUTTON,
|
DEVICE_CLASS_BUTTON,
|
||||||
DEVICE_CLASS_DOORBELL,
|
DEVICE_CLASS_DOORBELL,
|
||||||
DEVICE_CLASS_EMPTY,
|
DEVICE_CLASS_EMPTY,
|
||||||
|
@ -40,17 +41,21 @@ EventTrigger = event_ns.class_("EventTrigger", automation.Trigger.template())
|
||||||
|
|
||||||
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
||||||
|
|
||||||
EVENT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
|
EVENT_SCHEMA = (
|
||||||
{
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent),
|
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
||||||
cv.GenerateID(): cv.declare_id(Event),
|
.extend(
|
||||||
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
|
{
|
||||||
cv.Optional(CONF_ON_EVENT): automation.validate_automation(
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTEventComponent),
|
||||||
{
|
cv.GenerateID(): cv.declare_id(Event),
|
||||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger),
|
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
|
||||||
}
|
cv.Optional(CONF_ON_EVENT): automation.validate_automation(
|
||||||
),
|
{
|
||||||
}
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(EventTrigger),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
_UNDEF = object()
|
_UNDEF = object()
|
||||||
|
@ -97,6 +102,9 @@ async def setup_event_core_(var, config, *, event_types: list[str]):
|
||||||
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||||
await mqtt.register_mqtt_component(mqtt_, config)
|
await mqtt.register_mqtt_component(mqtt_, config)
|
||||||
|
|
||||||
|
if web_server_config := config.get(CONF_WEB_SERVER):
|
||||||
|
await web_server.add_entity_config(var, web_server_config)
|
||||||
|
|
||||||
|
|
||||||
async def register_event(var, config, *, event_types: list[str]):
|
async def register_event(var, config, *, event_types: list[str]):
|
||||||
if not CORE.has_id(config[CONF_ID]):
|
if not CORE.has_id(config[CONF_ID]):
|
||||||
|
|
|
@ -64,46 +64,46 @@ uint16_t shelly_dimmer_checksum(const uint8_t *buf, int len) {
|
||||||
return std::accumulate<decltype(buf), uint16_t>(buf, buf + len, 0);
|
return std::accumulate<decltype(buf), uint16_t>(buf, buf + len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShellyDimmer::is_running_configured_version() const {
|
||||||
|
return this->version_major_ == USE_SHD_FIRMWARE_MAJOR_VERSION &&
|
||||||
|
this->version_minor_ == USE_SHD_FIRMWARE_MINOR_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShellyDimmer::handle_firmware() {
|
||||||
|
// Reset the STM32 and check the firmware version.
|
||||||
|
this->reset_normal_boot_();
|
||||||
|
this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0);
|
||||||
|
ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_,
|
||||||
|
this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION);
|
||||||
|
|
||||||
|
if (!is_running_configured_version()) {
|
||||||
|
#ifdef USE_SHD_FIRMWARE_DATA
|
||||||
|
if (!this->upgrade_firmware_()) {
|
||||||
|
ESP_LOGW(TAG, "Failed to upgrade firmware");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->reset_normal_boot_();
|
||||||
|
this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0);
|
||||||
|
if (!is_running_configured_version()) {
|
||||||
|
ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ShellyDimmer::setup() {
|
void ShellyDimmer::setup() {
|
||||||
this->pin_nrst_->setup();
|
this->pin_nrst_->setup();
|
||||||
this->pin_boot0_->setup();
|
this->pin_boot0_->setup();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Initializing Shelly Dimmer...");
|
ESP_LOGI(TAG, "Initializing Shelly Dimmer...");
|
||||||
|
|
||||||
// Reset the STM32 and check the firmware version.
|
this->handle_firmware();
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
this->reset_normal_boot_();
|
|
||||||
this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0);
|
|
||||||
ESP_LOGI(TAG, "STM32 current firmware version: %d.%d, desired version: %d.%d", this->version_major_,
|
|
||||||
this->version_minor_, USE_SHD_FIRMWARE_MAJOR_VERSION, USE_SHD_FIRMWARE_MINOR_VERSION);
|
|
||||||
if (this->version_major_ != USE_SHD_FIRMWARE_MAJOR_VERSION ||
|
|
||||||
this->version_minor_ != USE_SHD_FIRMWARE_MINOR_VERSION) {
|
|
||||||
#ifdef USE_SHD_FIRMWARE_DATA
|
|
||||||
// Update firmware if needed.
|
|
||||||
ESP_LOGW(TAG, "Unsupported STM32 firmware version, flashing");
|
|
||||||
if (i > 0) {
|
|
||||||
// Upgrade was already performed but the reported version is still not right.
|
|
||||||
ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect");
|
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->upgrade_firmware_()) {
|
|
||||||
ESP_LOGW(TAG, "Failed to upgrade firmware");
|
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firmware upgrade completed, do the checks again.
|
|
||||||
continue;
|
|
||||||
#else
|
|
||||||
ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update.");
|
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->send_settings_();
|
this->send_settings_();
|
||||||
// Do an immediate poll to refresh current state.
|
// Do an immediate poll to refresh current state.
|
||||||
|
|
|
@ -20,6 +20,8 @@ class ShellyDimmer : public PollingComponent, public light::LightOutput, public
|
||||||
public:
|
public:
|
||||||
float get_setup_priority() const override { return setup_priority::LATE; }
|
float get_setup_priority() const override { return setup_priority::LATE; }
|
||||||
|
|
||||||
|
bool is_running_configured_version() const;
|
||||||
|
void handle_firmware();
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
|
@ -18,8 +18,8 @@ void Touchscreen::attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::Int
|
||||||
|
|
||||||
void Touchscreen::call_setup() {
|
void Touchscreen::call_setup() {
|
||||||
if (this->display_ != nullptr) {
|
if (this->display_ != nullptr) {
|
||||||
this->display_width_ = this->display_->get_native_width();
|
this->display_width_ = this->display_->get_width();
|
||||||
this->display_height_ = this->display_->get_native_height();
|
this->display_height_ = this->display_->get_height();
|
||||||
}
|
}
|
||||||
PollingComponent::call_setup();
|
PollingComponent::call_setup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1441,9 +1441,26 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro
|
||||||
void WebServer::on_event(event::Event *obj, const std::string &event_type) {
|
void WebServer::on_event(event::Event *obj, const std::string &event_type) {
|
||||||
this->events_.send(this->event_json(obj, event_type, DETAIL_STATE).c_str(), "state");
|
this->events_.send(this->event_json(obj, event_type, DETAIL_STATE).c_str(), "state");
|
||||||
}
|
}
|
||||||
|
void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||||
|
for (event::Event *obj : App.get_events()) {
|
||||||
|
if (obj->get_object_id() != match.id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||||
|
auto detail = DETAIL_STATE;
|
||||||
|
auto *param = request->getParam("detail");
|
||||||
|
if (param && param->value() == "all") {
|
||||||
|
detail = DETAIL_ALL;
|
||||||
|
}
|
||||||
|
std::string data = this->event_json(obj, "", detail);
|
||||||
|
request->send(200, "application/json", data.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request->send(404);
|
||||||
|
}
|
||||||
std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) {
|
std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) {
|
||||||
return json::build_json([obj, event_type, start_config](JsonObject root) {
|
return json::build_json([this, obj, event_type, start_config](JsonObject root) {
|
||||||
set_json_id(root, obj, "event-" + obj->get_object_id(), start_config);
|
set_json_id(root, obj, "event-" + obj->get_object_id(), start_config);
|
||||||
if (!event_type.empty()) {
|
if (!event_type.empty()) {
|
||||||
root["event_type"] = event_type;
|
root["event_type"] = event_type;
|
||||||
|
@ -1454,6 +1471,12 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty
|
||||||
event_types.add(event_type);
|
event_types.add(event_type);
|
||||||
}
|
}
|
||||||
root["device_class"] = obj->get_device_class();
|
root["device_class"] = obj->get_device_class();
|
||||||
|
if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
|
||||||
|
root["sorting_weight"] = this->sorting_entitys_[obj].weight;
|
||||||
|
if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
|
||||||
|
root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1645,6 +1668,11 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) {
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_EVENT
|
||||||
|
if (request->method() == HTTP_GET && match.domain == "event")
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update")
|
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update")
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -322,6 +322,9 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
void on_event(event::Event *obj, const std::string &event_type) override;
|
void on_event(event::Event *obj, const std::string &event_type) override;
|
||||||
|
|
||||||
|
/// Handle a event request under '/event<id>'.
|
||||||
|
void handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
||||||
|
|
||||||
/// Dump the event details with its value as a JSON string.
|
/// Dump the event details with its value as a JSON string.
|
||||||
std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config);
|
std::string event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -651,35 +651,45 @@ void delay_microseconds_safe(uint32_t us);
|
||||||
/// @name Memory management
|
/// @name Memory management
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/** An STL allocator that uses SPI RAM.
|
/** An STL allocator that uses SPI or internal RAM.
|
||||||
|
* Returns `nullptr` in case no memory is available.
|
||||||
*
|
*
|
||||||
* By setting flags, it can be configured to don't try main memory if SPI RAM is full or unavailable, and to return
|
* By setting flags, it can be configured to:
|
||||||
* `nulllptr` instead of aborting when no memory is available.
|
* - perform external allocation falling back to main memory if SPI RAM is full or unavailable
|
||||||
|
* - perform external allocation only
|
||||||
|
* - perform internal allocation only
|
||||||
*/
|
*/
|
||||||
template<class T> class ExternalRAMAllocator {
|
template<class T> class RAMAllocator {
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
NONE = 0,
|
NONE = 0, // Perform external allocation and fall back to internal memory
|
||||||
REFUSE_INTERNAL = 1 << 0, ///< Refuse falling back to internal memory when external RAM is full or unavailable.
|
ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only.
|
||||||
ALLOW_FAILURE = 1 << 1, ///< Don't abort when memory allocation fails.
|
ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only.
|
||||||
|
ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility.
|
||||||
};
|
};
|
||||||
|
|
||||||
ExternalRAMAllocator() = default;
|
RAMAllocator() = default;
|
||||||
ExternalRAMAllocator(Flags flags) : flags_{flags} {}
|
RAMAllocator(uint8_t flags) : flags_{flags} {}
|
||||||
template<class U> constexpr ExternalRAMAllocator(const ExternalRAMAllocator<U> &other) : flags_{other.flags_} {}
|
template<class U> constexpr RAMAllocator(const RAMAllocator<U> &other) : flags_{other.flags_} {}
|
||||||
|
|
||||||
T *allocate(size_t n) {
|
T *allocate(size_t n) {
|
||||||
size_t size = n * sizeof(T);
|
size_t size = n * sizeof(T);
|
||||||
T *ptr = nullptr;
|
T *ptr = nullptr;
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
|
// External allocation by default or if explicitely requested
|
||||||
#endif
|
if ((this->flags_ & Flags::ALLOC_EXTERNAL) || ((this->flags_ & Flags::ALLOC_INTERNAL) == 0)) {
|
||||||
if (ptr == nullptr && (this->flags_ & Flags::REFUSE_INTERNAL) == 0)
|
ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
|
||||||
|
}
|
||||||
|
// Fallback to internal allocation if explicitely requested or no flag is specified
|
||||||
|
if (ptr == nullptr && ((this->flags_ & Flags::ALLOC_INTERNAL) || (this->flags_ & Flags::ALLOC_EXTERNAL) == 0)) {
|
||||||
ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
|
ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
|
||||||
if (ptr == nullptr && (this->flags_ & Flags::ALLOW_FAILURE) == 0)
|
}
|
||||||
abort();
|
#else
|
||||||
|
// Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
|
||||||
|
ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
|
||||||
|
#endif
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,9 +698,11 @@ template<class T> class ExternalRAMAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Flags flags_{Flags::ALLOW_FAILURE};
|
uint8_t flags_{Flags::ALLOW_FAILURE};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T> using ExternalRAMAllocator = RAMAllocator<T>;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @name Internal functions
|
/// @name Internal functions
|
||||||
|
|
|
@ -2,6 +2,15 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
help() {
|
||||||
|
echo "Usage: $0 [-e <config|compile|clean>] [-c <string>] [-t <string>]" 1>&2
|
||||||
|
echo 1>&2
|
||||||
|
echo " - e - Parameter for esphome command. Default compile. Common alternative is config." 1>&2
|
||||||
|
echo " - c - Component folder name to test. Default *. E.g. '-c logger'." 1>&2
|
||||||
|
echo " - t - Target name to test. Put '-t list' to display all possibilities. E.g. '-t esp32-s2-idf-51'." 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# Parse parameter:
|
# Parse parameter:
|
||||||
# - `e` - Parameter for `esphome` command. Default `compile`. Common alternative is `config`.
|
# - `e` - Parameter for `esphome` command. Default `compile`. Common alternative is `config`.
|
||||||
# - `c` - Component folder name to test. Default `*`.
|
# - `c` - Component folder name to test. Default `*`.
|
||||||
|
@ -13,7 +22,7 @@ do
|
||||||
e) esphome_command=${OPTARG};;
|
e) esphome_command=${OPTARG};;
|
||||||
c) target_component=${OPTARG};;
|
c) target_component=${OPTARG};;
|
||||||
t) requested_target_platform=${OPTARG};;
|
t) requested_target_platform=${OPTARG};;
|
||||||
\?) echo "Usage: $0 [-e <config|compile|clean>] [-c <string>] [-t <string>]" 1>&2; exit 1;;
|
\?) help;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -24,8 +33,8 @@ if ! [ -d "./tests/test_build_components/build" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
start_esphome() {
|
start_esphome() {
|
||||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform" ]; then
|
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||||
echo "Skiping $target_platform"
|
echo "Skipping $target_platform_with_version"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
# create dynamic yaml file in `build` folder.
|
# create dynamic yaml file in `build` folder.
|
||||||
|
|
Loading…
Reference in a new issue