Tasmota/tasmota/tasmota_support/support_esp8266.ino

289 lines
8.1 KiB
C++

/*
support_esp8266.ino - ESP8266 specific support for Tasmota
SPDX-FileCopyrightText: 2023 Theo Arends
SPDX-License-Identifier: GPL-3.0-only
*/
#ifdef ESP8266
/*********************************************************************************************\
* ESP8266 and ESP8285 Support
\*********************************************************************************************/
const static char kWifiPhyMode[] PROGMEM = "low rate|11b|11g|11n"; // Wi-Fi Modes
extern "C" {
extern struct rst_info resetInfo;
}
/*********************************************************************************************\
* Core overrides executed by core
\*********************************************************************************************/
// Add below line to tasmota_globals.h
// extern "C" void resetPins();
//
// This function overrules __resetPins() which is executed by core init() as initPins() in core_esp8266_wiring.cpp
//
// 20221229 - (v12.3.1.2) Enabled with additional check to execute on power on only to fix relay clicks on power on
// 20200321 - (v8.2.0.1) Disable core functionality to fix relay clicks on restart after OTA - make function return without setting pinMode
void resetPins() {
if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) {
// Only perform at power on
for (int i = 0; i <= 5; ++i) {
pinMode(i, INPUT);
}
// pins 6-11 are used for the SPI flash interface ESP8266
for (int i = 12; i <= 16; ++i) {
pinMode(i, INPUT);
}
}
}
/*********************************************************************************************\
* Hardware related
\*********************************************************************************************/
void HwWdtDisable(void) {
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
}
void HwWdtEnable(void) {
*((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON
}
void WdtDisable(void) {
ESP.wdtDisable();
HwWdtDisable();
}
void WdtEnable(void) {
HwWdtEnable();
ESP.wdtEnable(0);
}
/*********************************************************************************************\
* ESP8266 specifics
\*********************************************************************************************/
uint32_t ESP_ResetInfoReason(void) {
return resetInfo.reason;
}
String ESP_getResetReason(void) {
return ESP.getResetReason();
}
uint32_t ESP_getChipId(void) {
return ESP.getChipId();
}
uint32_t ESP_getFreeSketchSpace(void) {
return ESP.getFreeSketchSpace();
}
uint32_t ESP_getSketchSize(void) {
return ESP.getSketchSize();
}
uint32_t ESP_getHeapSize(void) {
return 32768; // Using default heap (No PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED)
}
uint32_t ESP_getFreeHeap(void) {
return ESP.getFreeHeap();
}
uint32_t ESP_getFreeHeap1024(void) {
return ESP_getFreeHeap() / 1024;
}
/*
float ESP_getFreeHeap1024(void) {
return ((float)ESP_getFreeHeap()) / 1024;
}
*/
uint32_t ESP_getMaxAllocHeap(void) {
return ESP.getFreeHeap();
}
uint32_t ESP_getFlashChipId(void) {
return ESP.getFlashChipId();
}
uint32_t ESP_getFlashChipRealSize(void) {
return ESP.getFlashChipRealSize();
}
uint32_t ESP_getFlashChipSize(void) {
return ESP.getFlashChipSize();
}
uint32_t ESP_getPsramSize(void) {
return 0;
}
uint32_t ESP_getFreePsram(void) {
return 0;
}
uint32_t ESP_getMaxAllocPsram(void) {
return 0;
}
void ESP_Restart(void) {
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset();
}
uint32_t FlashWriteStartSector(void) {
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
}
uint32_t FlashWriteMaxSector(void) {
return (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE) - 2;
}
uint8_t* FlashDirectAccess(void) {
return (uint8_t*)(0x40200000 + (FlashWriteStartSector() * SPI_FLASH_SEC_SIZE));
}
void *special_malloc(uint32_t size) {
return malloc(size);
}
void *special_realloc(void *ptr, size_t size) {
return realloc(ptr, size);
}
void *special_calloc(size_t num, size_t size) {
return calloc(num, size);
}
String GetDeviceHardware(void) {
/*
ESP8266 SoCs
- 32-bit MCU & 2.4 GHz Wi-Fi
- High-performance 160 MHz single-core CPU
- +19.5 dBm output power ensures a good physical range
- Sleep current is less than 20 μA, making it suitable for battery-powered and wearable-electronics applications
- Peripherals include UART, GPIO, I2C, I2S, SDIO, PWM, ADC and SPI
*/
// esptool.py get_efuses
uint32_t efuse0 = *(uint32_t*)(0x3FF00050);
// uint32_t efuse1 = *(uint32_t*)(0x3FF00054);
uint32_t efuse2 = *(uint32_t*)(0x3FF00058);
uint32_t efuse3 = *(uint32_t*)(0x3FF0005C);
bool r0_4 = efuse0 & (1 << 4); // ESP8285
bool r2_16 = efuse2 & (1 << 16); // ESP8285
if (r0_4 || r2_16) { // ESP8285
// 1M 2M 2M 4M flash size
// r0_4 1 1 0 0
bool r3_25 = efuse3 & (1 << 25); // flash matrix 0 0 1 1
bool r3_26 = efuse3 & (1 << 26); // flash matrix 0 1 0 1
bool r3_27 = efuse3 & (1 << 27); // flash matrix 0 0 0 0
uint32_t pkg_version = 0;
if (!r3_27) {
if (r0_4 && !r3_25) {
pkg_version = (r3_26) ? 2 : 1;
}
else if (!r0_4 && r3_25) {
pkg_version = (r3_26) ? 4 : 2;
}
}
bool max_temp = efuse0 & (1 << 5); // Max flash temperature (0 = 85C, 1 = 105C)
switch (pkg_version) {
case 1:
if (max_temp) { return F("ESP8285H08"); } // 1M flash
else { return F("ESP8285N08"); }
case 2:
if (max_temp) { return F("ESP8285H16"); } // 2M flash
else { return F("ESP8285N16"); }
case 4:
if (max_temp) { return F("ESP8285H32"); } // 4M flash
else { return F("ESP8285N32"); }
}
return F("ESP8285");
}
return F("ESP8266EX");
}
String GetDeviceHardwareRevision(void) {
// No known revisions for ESP8266/85
return GetDeviceHardware();
}
String GetCodeCores(void) {
return F("");
}
uint32_t ESP_getChipCores(void) {
return 1;
}
uint32_t ESP_getChipRevision(void) {
return 1;
}
String ESP_getEfuseMac(void) {
uint32_t mac0 = *(uint32_t*)(0x3FF00050);
uint32_t mac1 = *(uint32_t*)(0x3FF00054);
uint32_t mac3 = *(uint32_t*)(0x3FF0005C);
uint32_t mach = 0;
uint32_t macl = 0;
if (mac3 != 0) {
macl = (mac3 >> 16) & 0xFF;
macl |= ((mac3 >> 8) & 0xFF) << 8;
macl |= (mac3 & 0xFF) << 16;
}
else if (((mac1 >> 16) & 0xFF) == 0) {
macl = 0x34FE18;
}
else if (((mac1 >> 16) & 0xFF) == 1) {
macl = 0x74D0AC;
}
String macStr = "";
if (macl > 0) {
mach = (mac1 >> 8) & 0xFF;
mach |= (mac1 & 0xFF) << 8;
mach |= ((mac0 >> 24) & 0xFF) << 16;
uint64_t maca = ((uint64_t)mach << 24) | macl;
// Need uint64ToString with base 10 as ESP8266 WStrings does not support uint64_t
while (maca > 0) {
macStr = String((uint32_t)(maca % 10), 10) + macStr;
maca /= 10;
}
}
return String(macStr);
}
String WifiGetPhyMode(void) {
char stemp[10];
return String(GetTextIndexed(stemp, sizeof(stemp), WiFiHelper::getPhyMode() & 0x3, kWifiPhyMode));
}
/*********************************************************************************************\
* High entropy hardware random generator
* Thanks to DigitalAlchemist
\*********************************************************************************************/
// Based on code from https://raw.githubusercontent.com/espressif/esp-idf/master/components/esp32/hw_random.c
uint32_t HwRandom(void) {
// https://web.archive.org/web/20160922031242/http://esp8266-re.foogod.com/wiki/Random_Number_Generator
#define _RAND_ADDR 0x3FF20E44UL
static uint32_t last_ccount = 0;
uint32_t ccount;
uint32_t result = 0;
do {
ccount = ESP.getCycleCount();
result ^= *(volatile uint32_t *)_RAND_ADDR;
} while (ccount - last_ccount < 64);
last_ccount = ccount;
return result ^ *(volatile uint32_t *)_RAND_ADDR;
#undef _RAND_ADDR
}
#endif // ESP8266