diff --git a/boards/esp8285-8285.json b/boards/esp8285-8285.json new file mode 100644 index 00000000..578af0ad --- /dev/null +++ b/boards/esp8285-8285.json @@ -0,0 +1,34 @@ +{ + "comment": "From ExpressLRS project, https://github.com/ExpressLRS/ExpressLRS/blob/master/src/boards/esp8285-8285.json: esp8285 variant for ExpressLRS that uses variant=esp8285 instead of variant=generic", + "build": { + "arduino": { + "ldscript": "eagle.flash.1m256.ld" + }, + "core": "esp8266", + "extra_flags": "-DESP8266 -DESP8285 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_ESP01", + "f_cpu": "80000000L", + "f_flash": "40000000L", + "flash_mode": "dout", + "mcu": "esp8266", + "variant": "esp8285" + }, + "connectivity": [ + "wifi" + ], + "frameworks": [ + "arduino", + "espidf", + "esp8266-rtos-sdk", + "esp8266-nonos-sdk" + ], + "name": "Generic ESP8285 Module", + "upload": { + "maximum_ram_size": 81920, + "maximum_size": 1048576, + "require_upload_port": true, + "resetmethod": "ck", + "speed": 115200 + }, + "url": "http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family", + "vendor": "Espressif" + } \ No newline at end of file diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 29ec7028..085a5c1e 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -5,6 +5,8 @@ #include #elif defined(ESP32) #include +#elif defined(ESP8285) || defined(ESP866) + #include #endif #define RADIOLIB_STATIC_ONLY 1 @@ -92,6 +94,10 @@ #include #include static TechoBoard board; +#elif defined(ESP8285) + #include + #include + static ESP8285Board board; #else #error "need to provide a 'board' object" #endif @@ -244,7 +250,12 @@ class MyMesh : public BaseChatMesh { void loadContacts() { if (_fs->exists("/contacts3")) { - File file = _fs->open("/contacts3"); + + #if defined(ESP8285) + File file = _fs->open("/contacts3", "r"); + #else + File file = _fs->open("/contacts3"); + #endif if (file) { bool full = false; while (!full) { @@ -280,7 +291,11 @@ class MyMesh : public BaseChatMesh { File file = _fs->open("/contacts3", FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } #else + #if defined(ESP8285) + File file = _fs->open("/contacts3", "w"); + #else File file = _fs->open("/contacts3", "w", true); + #endif #endif if (file) { ContactsIterator iter; @@ -316,7 +331,11 @@ class MyMesh : public BaseChatMesh { sprintf(path, "/bl/%s", fname); if (_fs->exists(path)) { - File f = _fs->open(path); + #if defined(ESP8285) + File f = _fs->open(path, "r"); + #else + File f = _fs->open(path); + #endif if (f) { int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!! f.close(); @@ -337,8 +356,12 @@ class MyMesh : public BaseChatMesh { #if defined(NRF52_PLATFORM) File f = _fs->open(path, FILE_O_WRITE); if (f) { f.seek(0); f.truncate(); } + #else + #if defined(ESP8285) + File f = _fs->open(path, "w"); #else File f = _fs->open(path, "w", true); + #endif #endif if (f) { int n = f.write(src_buf, len); @@ -657,7 +680,11 @@ class MyMesh : public BaseChatMesh { // load persisted prefs if (_fs->exists("/node_prefs")) { - File file = _fs->open("/node_prefs"); + #if defined(ESP8285) + File file = _fs->open("/node_prefs", "r"); + #else + File file = _fs->open("/node_prefs"); + #endif if (file) { uint8_t pad[8]; @@ -731,7 +758,11 @@ class MyMesh : public BaseChatMesh { File file = _fs->open("/node_prefs", FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } #else + #if defined(ESP8285) + File file = _fs->open("/node_prefs", "w"); + #else File file = _fs->open("/node_prefs", "w", true); + #endif #endif if (file) { uint8_t pad[8]; @@ -1211,6 +1242,17 @@ class MyMesh : public BaseChatMesh { #include ArduinoSerialInterface serial_interface; #endif +#elif defined(ESP8285) + #ifdef WIFI_SSID + #ifndef TCP_PORT + #define TCP_PORT 5000 + #endif + #include + SerialWifiInterface serial_interface(TCP_PORT); // Pass TCP_PORT to the constructor + #else + #include + ArduinoSerialInterface serial_interface; + #endif #elif defined(NRF52_PLATFORM) #ifdef BLE_PIN_CODE #include @@ -1224,15 +1266,15 @@ class MyMesh : public BaseChatMesh { #endif #if defined(NRF52_PLATFORM) -RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); -#elif defined(LILYGO_TLORA) -SPIClass spi; -RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); +#elif defined(LILYGO_TLORA) || defined(ESP8285) + SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); #elif defined(P_LORA_SCLK) -SPIClass spi; -RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); #else -RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); #endif StdRNG fast_rng; SimpleMeshTables tables; @@ -1245,6 +1287,7 @@ void halt() { void setup() { Serial.begin(115200); + board.begin(); #ifdef SX126X_DIO3_TCXO_VOLTAGE float tcxo = SX126X_DIO3_TCXO_VOLTAGE; @@ -1255,6 +1298,8 @@ void setup() { #if defined(NRF52_PLATFORM) SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); +#elif defined(ESP8285) + spi.begin(); #elif defined(P_LORA_SCLK) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif @@ -1304,6 +1349,11 @@ void setup() { SPIFFS.begin(true); the_mesh.begin(SPIFFS, trng); +#elif defined(ESP8285) + SPIFFS.begin(); + the_mesh.begin(SPIFFS, trng); + + #ifdef WIFI_SSID WiFi.begin(WIFI_SSID, WIFI_PWD); serial_interface.begin(TCP_PORT); diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 5743647b..286bf732 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -5,6 +5,8 @@ #include #elif defined(ESP32) #include +#elif defined(ESP8285) || defined(ESP866) + #include #endif #define RADIOLIB_STATIC_ONLY 1 @@ -96,6 +98,10 @@ #include #include static TechoBoard board; +#elif defined(ESP8285) + #include + #include + static ESP8285Board board; #else #error "need to provide a 'board' object" #endif @@ -224,6 +230,8 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { File openAppend(const char* fname) { #if defined(NRF52_PLATFORM) return _fs->open(fname, FILE_O_WRITE); + #elif defined(ESP8285) + return _fs->open(fname, "a"); #else return _fs->open(fname, "a", true); #endif @@ -566,7 +574,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { bool formatFileSystem() override { #if defined(NRF52_PLATFORM) return InternalFS.format(); -#elif defined(ESP32) +#elif defined(ESP32) || defined(ESP8285) return SPIFFS.format(); #else #error "need to implement file system erase" @@ -598,7 +606,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { } void dumpLogFile() override { - File f = _fs->open(PACKET_LOG_FILE); + #if defined(ESP8285) + File f = _fs->open(PACKET_LOG_FILE, "r"); + #else + File f = _fs->open(PACKET_LOG_FILE); + #endif if (f) { while (f.available()) { int c = f.read(); @@ -632,7 +644,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { #if defined(NRF52_PLATFORM) RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); -#elif defined(LILYGO_TLORA) +#elif defined(LILYGO_TLORA) || defined(ESP8285) SPIClass spi; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); #elif defined(P_LORA_SCLK) @@ -678,6 +690,8 @@ void setup() { #if defined(NRF52_PLATFORM) SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); +#elif defined(ESP8285) + spi.begin(); #elif defined(P_LORA_SCLK) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif @@ -712,6 +726,10 @@ void setup() { SPIFFS.begin(true); fs = &SPIFFS; IdentityStore store(SPIFFS, "/identity"); +#elif defined(ESP8285) + SPIFFS.begin(); + fs = &SPIFFS; + IdentityStore store(SPIFFS, "/identity"); #else #error "need to define filesystem" #endif diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 951d51dc..24836f50 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -3,8 +3,10 @@ #if defined(NRF52_PLATFORM) #include -#elif defined(ESP32) +#elif defined(ESP32) #include +#elif defined(ESP8285) || defined(ESP866) + #include #endif #define RADIOLIB_STATIC_ONLY 1 diff --git a/platformio.ini b/platformio.ini index 4aeb7d86..a6c00768 100644 --- a/platformio.ini +++ b/platformio.ini @@ -948,3 +948,67 @@ build_src_filter = ${LilyGo_Techo.build_src_filter} lib_deps = ${LilyGo_Techo.lib_deps} densaugeo/base64 @ ~1.4.0 + + +; ----------------- ELRS ESP8285--------------------- + +[esp82xx_base] +platform = espressif8266 +extends = arduino_base +board = esp8285-8285 +build_flags = + ${arduino_base.build_flags} + -D ESP8285 + -D PLATFORM_ESP8266=1 +build_src_filter = ${arduino_base.build_src_filter} +monitor_filters = esp8266_exception_decoder +upload_resetmethod = nodemcu + +; -- pin defs from https://github.com/ExpressLRS/targets/blob/master/RX/Generic%20900.json +[ELRS_ESP8285_RX] +extends = esp82xx_base +build_flags = + ${esp82xx_base.build_flags} + -D RADIO_CLASS=CustomSX1276 + -D WRAPPER_CLASS=CustomSX1276Wrapper + -D LORA_TX_POWER=20 + -D SERIAL_INTERFACE=Serial + -D P_LORA_DIO_0=4 + -D P_LORA_DIO_1=5 + -D P_LORA_NSS=15 + -D P_LORA_RESET=2 + -D P_LORA_SCLK=14 + -D P_LORA_MISO=12 + -D P_LORA_MOSI=13 + -D PIN_RX=3 + -D PIN_TX=1 + -D PIN_LED_BUILTIN=16 +build_src_filter = ${esp82xx_base.build_src_filter} + +[env:ELRS_ESP8285_RX_companion_radio_usb] +extends = ELRS_ESP8285_RX +build_flags = + ${ELRS_ESP8285_RX.build_flags} + -D MAX_CONTACTS=25 ; crash = 50, 40, + -D MAX_GROUP_CHANNELS=1 +build_src_filter = + ${ELRS_ESP8285_RX.build_src_filter} + + + +<../examples/companion_radio/main.cpp> +lib_deps = + ${arduino_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:ELRS_ESP8285_RX_repeater] +extends = ELRS_ESP8285_RX +build_flags = + ${ELRS_ESP8285_RX.build_flags} + -D ADVERT_NAME="\"ELRSRX Repeater\"" + -D ADVERT_LAT=-37.0 + -D ADVERT_LON=145.0 + -D ADMIN_PASSWORD="\"password\"" +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = + ${ELRS_ESP8285_RX.build_src_filter} + +<../examples/simple_repeater/main.cpp> \ No newline at end of file diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 21cd690f..8e29a31d 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -15,7 +15,11 @@ static uint32_t _atoi(const char* sp) { void CommonCLI::loadPrefs(FILESYSTEM* fs) { if (fs->exists("/node_prefs")) { - File file = fs->open("/node_prefs"); + #if defined(ESP8285) + File file = fs->open("/node_prefs", "r"); + #else + File file = fs->open("/node_prefs"); + #endif if (file) { uint8_t pad[8]; @@ -63,7 +67,11 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { File file = fs->open("/node_prefs", FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } #else - File file = fs->open("/node_prefs", "w", true); + #if defined(ESP8285) + File file = fs->open("/node_prefs", "w"); + #else + File file = fs->open("/node_prefs", "w", true); + #endif #endif if (file) { uint8_t pad[8]; diff --git a/src/helpers/ESP8285Board.h b/src/helpers/ESP8285Board.h new file mode 100644 index 00000000..d793c4e8 --- /dev/null +++ b/src/helpers/ESP8285Board.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include + +#if defined(ESP8266) + +#include // For ESP.getResetReason() and ESP.restart() +#include + +#ifndef BD_STARTUP_UNKNOWN + // For ESP8266/ESP8285, if no proper startup reason is available, fall back to a known value. + #define BD_STARTUP_UNKNOWN BD_STARTUP_NORMAL +#endif + + +class ESP8285Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin() { + // Determine startup reason using ESP8266 API + String reason = ESP.getResetReason(); + if (reason == "Power on") { + startup_reason = BD_STARTUP_NORMAL; + } else { + // Add more mappings as needed for your enum + startup_reason = BD_STARTUP_UNKNOWN; // Assuming this exists in MainBoard + } + + #ifdef PIN_VBAT_READ + // battery read support + pinMode(PIN_VBAT_READ, INPUT); + adcAttachPin(PIN_VBAT_READ); + #endif + + #ifdef PIN_LED_BUILTIN + pinMode(PIN_LED_BUILTIN, OUTPUT); + digitalWrite(PIN_LED_BUILTIN, LOW); + #endif + + #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL); + #else + Wire.begin(); + #endif + } + + uint8_t getStartupReason() const override { return startup_reason; } + +#if defined(PIN_LED_BUILTIN) + void onBeforeTransmit() override { + digitalWrite(PIN_LED_BUILTIN, HIGH); // turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(PIN_LED_BUILTIN, LOW); // turn TX LED off + } +#endif + + uint16_t getBattMilliVolts() override { + return 0; // not supported + } + + const char* getManufacturerName() const override { + return "Generic ESP8285 ELRS Receiver"; + } + + void reboot() override { + ESP.restart(); // ESP8266 reboot function + } +}; + +class ESP8285RTCClock : public mesh::RTCClock { +public: + ESP8285RTCClock() { } + void begin() { + String reason = ESP.getResetReason(); + if (reason == "Power on") { + // Initialize with a default time on power-on + struct timeval tv; + tv.tv_sec = 1715770351; // 15 May 2024, 8:50pm + tv.tv_usec = 0; + settimeofday(&tv, NULL); + } + // On other resets, assume time persists unless synced externally + } + + uint32_t getCurrentTime() override { + time_t now; + time(&now); + return now; + } + + void setCurrentTime(uint32_t time) override { + struct timeval tv; + tv.tv_sec = time; + tv.tv_usec = 0; + settimeofday(&tv, NULL); + } +}; + +#endif diff --git a/src/helpers/IdentityStore.cpp b/src/helpers/IdentityStore.cpp index 3b44eb4a..984f5e80 100644 --- a/src/helpers/IdentityStore.cpp +++ b/src/helpers/IdentityStore.cpp @@ -5,7 +5,11 @@ bool IdentityStore::load(const char *name, mesh::LocalIdentity& id) { char filename[40]; sprintf(filename, "%s/%s.id", _dir, name); if (_fs->exists(filename)) { +#if defined(ESP8285) + File file = _fs->open(filename, "r"); +#else File file = _fs->open(filename); +#endif if (file) { loaded = id.readFrom(file); file.close(); @@ -19,7 +23,11 @@ bool IdentityStore::load(const char *name, mesh::LocalIdentity& id, char display char filename[40]; sprintf(filename, "%s/%s.id", _dir, name); if (_fs->exists(filename)) { +#if defined(ESP8285) + File file = _fs->open(filename, "r"); +#else File file = _fs->open(filename); +#endif if (file) { loaded = id.readFrom(file); @@ -41,6 +49,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) { #if defined(NRF52_PLATFORM) File file = _fs->open(filename, FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } +#elif defined(ESP8285) + File file = _fs->open(filename, "w"); #else File file = _fs->open(filename, "w", true); #endif @@ -61,6 +71,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id, const #if defined(NRF52_PLATFORM) File file = _fs->open(filename, FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } +#elif defined(ESP8285) + File file = _fs->open(filename, "w"); #else File file = _fs->open(filename, "w", true); #endif diff --git a/src/helpers/IdentityStore.h b/src/helpers/IdentityStore.h index 2a5363ea..5953aadd 100644 --- a/src/helpers/IdentityStore.h +++ b/src/helpers/IdentityStore.h @@ -1,6 +1,6 @@ #pragma once -#if defined(ESP32) +#if defined(ESP32) || defined(ESP8266) #include #define FILESYSTEM fs::FS #elif defined(NRF52_PLATFORM) diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index 03f8f3ce..2966f2df 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -13,7 +13,7 @@ static volatile uint8_t state = STATE_IDLE; // this function is called when a complete packet // is transmitted by the module static -#if defined(ESP8266) || defined(ESP32) +#if defined(ESP8266) || defined(ESP32) || defined(ESP8285) ICACHE_RAM_ATTR #endif void setFlag(void) {