mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 08:55:22 +01:00
6682c43dfa
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
280 lines
6.9 KiB
C++
280 lines
6.9 KiB
C++
#include "esphome/core/esphal.h"
|
|
#include "esphome/core/helpers.h"
|
|
#include "esphome/core/defines.h"
|
|
#include "esphome/core/log.h"
|
|
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
extern "C" {
|
|
typedef struct { // NOLINT
|
|
void *interruptInfo; // NOLINT
|
|
void *functionInfo; // NOLINT
|
|
} ArgStructure;
|
|
|
|
void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, void (*)(void *), void *fp, // NOLINT
|
|
int mode);
|
|
};
|
|
#endif
|
|
|
|
namespace esphome {
|
|
|
|
static const char *TAG = "esphal";
|
|
|
|
GPIOPin::GPIOPin(uint8_t pin, uint8_t mode, bool inverted)
|
|
: pin_(pin),
|
|
mode_(mode),
|
|
inverted_(inverted),
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
gpio_read_(pin < 16 ? &GPI : &GP16I),
|
|
gpio_mask_(pin < 16 ? (1UL << pin) : 1)
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
gpio_set_(pin < 32 ? &GPIO.out_w1ts : &GPIO.out1_w1ts.val),
|
|
gpio_clear_(pin < 32 ? &GPIO.out_w1tc : &GPIO.out1_w1tc.val),
|
|
gpio_read_(pin < 32 ? &GPIO.in : &GPIO.in1.val),
|
|
gpio_mask_(pin < 32 ? (1UL << pin) : (1UL << (pin - 32)))
|
|
#endif
|
|
{
|
|
}
|
|
|
|
const char *GPIOPin::get_pin_mode_name() const {
|
|
const char *mode_s;
|
|
switch (this->mode_) {
|
|
case INPUT:
|
|
mode_s = "INPUT";
|
|
break;
|
|
case OUTPUT:
|
|
mode_s = "OUTPUT";
|
|
break;
|
|
case INPUT_PULLUP:
|
|
mode_s = "INPUT_PULLUP";
|
|
break;
|
|
case OUTPUT_OPEN_DRAIN:
|
|
mode_s = "OUTPUT_OPEN_DRAIN";
|
|
break;
|
|
case SPECIAL:
|
|
mode_s = "SPECIAL";
|
|
break;
|
|
case FUNCTION_1:
|
|
mode_s = "FUNCTION_1";
|
|
break;
|
|
case FUNCTION_2:
|
|
mode_s = "FUNCTION_2";
|
|
break;
|
|
case FUNCTION_3:
|
|
mode_s = "FUNCTION_3";
|
|
break;
|
|
case FUNCTION_4:
|
|
mode_s = "FUNCTION_4";
|
|
break;
|
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
case PULLUP:
|
|
mode_s = "PULLUP";
|
|
break;
|
|
case PULLDOWN:
|
|
mode_s = "PULLDOWN";
|
|
break;
|
|
case INPUT_PULLDOWN:
|
|
mode_s = "INPUT_PULLDOWN";
|
|
break;
|
|
case OPEN_DRAIN:
|
|
mode_s = "OPEN_DRAIN";
|
|
break;
|
|
case FUNCTION_5:
|
|
mode_s = "FUNCTION_5";
|
|
break;
|
|
case FUNCTION_6:
|
|
mode_s = "FUNCTION_6";
|
|
break;
|
|
case ANALOG:
|
|
mode_s = "ANALOG";
|
|
break;
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
case FUNCTION_0:
|
|
mode_s = "FUNCTION_0";
|
|
break;
|
|
case WAKEUP_PULLUP:
|
|
mode_s = "WAKEUP_PULLUP";
|
|
break;
|
|
case WAKEUP_PULLDOWN:
|
|
mode_s = "WAKEUP_PULLDOWN";
|
|
break;
|
|
case INPUT_PULLDOWN_16:
|
|
mode_s = "INPUT_PULLDOWN_16";
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
mode_s = "UNKNOWN";
|
|
break;
|
|
}
|
|
|
|
return mode_s;
|
|
}
|
|
|
|
unsigned char GPIOPin::get_pin() const { return this->pin_; }
|
|
unsigned char GPIOPin::get_mode() const { return this->mode_; }
|
|
|
|
bool GPIOPin::is_inverted() const { return this->inverted_; }
|
|
void GPIOPin::setup() { this->pin_mode(this->mode_); }
|
|
bool ICACHE_RAM_ATTR HOT GPIOPin::digital_read() {
|
|
return bool((*this->gpio_read_) & this->gpio_mask_) != this->inverted_;
|
|
}
|
|
bool ICACHE_RAM_ATTR HOT ISRInternalGPIOPin::digital_read() {
|
|
return bool((*this->gpio_read_) & this->gpio_mask_) != this->inverted_;
|
|
}
|
|
void ICACHE_RAM_ATTR HOT GPIOPin::digital_write(bool value) {
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
if (this->pin_ != 16) {
|
|
if (value != this->inverted_) {
|
|
GPOS = this->gpio_mask_;
|
|
} else {
|
|
GPOC = this->gpio_mask_;
|
|
}
|
|
} else {
|
|
if (value != this->inverted_) {
|
|
GP16O |= 1;
|
|
} else {
|
|
GP16O &= ~1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
if (value != this->inverted_) {
|
|
(*this->gpio_set_) = this->gpio_mask_;
|
|
} else {
|
|
(*this->gpio_clear_) = this->gpio_mask_;
|
|
}
|
|
#endif
|
|
}
|
|
void ISRInternalGPIOPin::digital_write(bool value) {
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
if (this->pin_ != 16) {
|
|
if (value != this->inverted_) {
|
|
GPOS = this->gpio_mask_;
|
|
} else {
|
|
GPOC = this->gpio_mask_;
|
|
}
|
|
} else {
|
|
if (value != this->inverted_) {
|
|
GP16O |= 1;
|
|
} else {
|
|
GP16O &= ~1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
if (value != this->inverted_) {
|
|
(*this->gpio_set_) = this->gpio_mask_;
|
|
} else {
|
|
(*this->gpio_clear_) = this->gpio_mask_;
|
|
}
|
|
#endif
|
|
}
|
|
ISRInternalGPIOPin::ISRInternalGPIOPin(uint8_t pin,
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
volatile uint32_t *gpio_clear, volatile uint32_t *gpio_set,
|
|
#endif
|
|
volatile uint32_t *gpio_read, uint32_t gpio_mask, bool inverted)
|
|
: pin_(pin),
|
|
inverted_(inverted),
|
|
gpio_read_(gpio_read),
|
|
gpio_mask_(gpio_mask)
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
,
|
|
gpio_clear_(gpio_clear),
|
|
gpio_set_(gpio_set)
|
|
#endif
|
|
{
|
|
}
|
|
void ICACHE_RAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, this->gpio_mask_);
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
if (this->pin_ < 32) {
|
|
GPIO.status_w1tc = this->gpio_mask_;
|
|
} else {
|
|
GPIO.status1_w1tc.intr_st = this->gpio_mask_;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ICACHE_RAM_ATTR HOT GPIOPin::pin_mode(uint8_t mode) {
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
if (this->pin_ == 16 && mode == INPUT_PULLUP) {
|
|
// pullups are not available on GPIO16, manually override with
|
|
// input mode.
|
|
pinMode(16, INPUT);
|
|
return;
|
|
}
|
|
#endif
|
|
pinMode(this->pin_, mode);
|
|
}
|
|
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
struct ESPHomeInterruptFuncInfo {
|
|
void (*func)(void *);
|
|
void *arg;
|
|
};
|
|
|
|
void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
|
|
ArgStructure *as = static_cast<ArgStructure *>(arg);
|
|
auto *info = static_cast<ESPHomeInterruptFuncInfo *>(as->functionInfo);
|
|
info->func(info->arg);
|
|
}
|
|
#endif
|
|
|
|
void GPIOPin::attach_interrupt_(void (*func)(void *), void *arg, int mode) const {
|
|
if (this->inverted_) {
|
|
if (mode == RISING) {
|
|
mode = FALLING;
|
|
} else if (mode == FALLING) {
|
|
mode = RISING;
|
|
}
|
|
}
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
ArgStructure *as = new ArgStructure;
|
|
as->interruptInfo = nullptr;
|
|
|
|
as->functionInfo = new ESPHomeInterruptFuncInfo{
|
|
.func = func,
|
|
.arg = arg,
|
|
};
|
|
|
|
__attachInterruptArg(this->pin_, interrupt_handler, as, mode);
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
// work around issue https://github.com/espressif/arduino-esp32/pull/1776 in arduino core
|
|
// yet again proves how horrible code is there :( - how could that have been accepted...
|
|
auto *attach = reinterpret_cast<void (*)(uint8_t, void (*)(void *), void *, int)>(attachInterruptArg);
|
|
attach(this->pin_, func, arg, mode);
|
|
#endif
|
|
}
|
|
|
|
ISRInternalGPIOPin *GPIOPin::to_isr() const {
|
|
return new ISRInternalGPIOPin(this->pin_,
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
this->gpio_clear_, this->gpio_set_,
|
|
#endif
|
|
this->gpio_read_, this->gpio_mask_, this->inverted_);
|
|
}
|
|
|
|
} // namespace esphome
|
|
|
|
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0
|
|
// Fix 2.3.0 std missing memchr
|
|
extern "C" {
|
|
void *memchr(const void *s, int c, size_t n) {
|
|
if (n == 0)
|
|
return nullptr;
|
|
const uint8_t *p = reinterpret_cast<const uint8_t *>(s);
|
|
do {
|
|
if (*p++ == c)
|
|
return const_cast<void *>(reinterpret_cast<const void *>(p - 1));
|
|
} while (--n != 0);
|
|
return nullptr;
|
|
}
|
|
};
|
|
#endif
|