diff --git a/Bluetooth.h b/Bluetooth.h index 099a442..a22e5dc 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -109,7 +109,7 @@ char bt_devname[11]; bool bt_init() { bt_state = BT_STATE_OFF; if (bt_setup_hw()) { - if (bt_enabled) bt_start(); + if (bt_enabled && !console_active) bt_start(); return true; } else { return false; diff --git a/Config.h b/Config.h index b3beb4b..23424b4 100644 --- a/Config.h +++ b/Config.h @@ -42,6 +42,11 @@ bool bt_enabled = false; bool bt_allow_pairing = false; + #define M_FRQ_S 27388122 + #define M_FRQ_R 27388061 + bool console_active = false; + bool sx1276_installed = false; + #if defined(__AVR_ATmega1284P__) #define PLATFORM PLATFORM_AVR #define MCU_VARIANT MCU_1284P diff --git a/Console.h b/Console.h new file mode 100644 index 0000000..e51b5bb --- /dev/null +++ b/Console.h @@ -0,0 +1,178 @@ +#include +#include +#include +#include + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +// Replace with your network credentials +const char* ssid = "RNode Test"; +const char* password = "somepass"; + +WebServer server(80); + +void console_dbg(String msg) { + Serial.print("[Webserver] "); + Serial.println(msg); +} + +bool exists(String path){ + bool yes = false; + File file = SPIFFS.open(path, "r"); + if(!file.isDirectory()){ + yes = true; + } + file.close(); + return yes; +} + +String console_get_content_type(String filename) { + if (server.hasArg("download")) { + return "application/octet-stream"; + } else if (filename.endsWith(".htm")) { + return "text/html"; + } else if (filename.endsWith(".html")) { + return "text/html"; + } else if (filename.endsWith(".css")) { + return "text/css"; + } else if (filename.endsWith(".js")) { + return "application/javascript"; + } else if (filename.endsWith(".png")) { + return "image/png"; + } else if (filename.endsWith(".gif")) { + return "image/gif"; + } else if (filename.endsWith(".jpg")) { + return "image/jpeg"; + } else if (filename.endsWith(".ico")) { + return "image/x-icon"; + } else if (filename.endsWith(".xml")) { + return "text/xml"; + } else if (filename.endsWith(".pdf")) { + return "application/x-pdf"; + } else if (filename.endsWith(".zip")) { + return "application/x-zip"; + } else if (filename.endsWith(".gz")) { + return "application/x-gzip"; + } + return "text/plain"; +} + +bool console_serve_file(String path) { + console_dbg("Request for: "+path); + if (path.endsWith("/")) { + path += "index.html"; + } + + String content_type = console_get_content_type(path); + String pathWithGz = path + ".gz"; + if (exists(pathWithGz) || exists(path)) { + if (exists(pathWithGz)) { + path += ".gz"; + } + + File file = SPIFFS.open(path, "r"); + console_dbg("Serving file to client"); + server.streamFile(file, content_type); + file.close(); + + console_dbg("File serving done"); + return true; + } + + console_dbg("Error: Could not open file for serving"); + return false; +} + +void console_register_pages() { + server.onNotFound([]() { + if (!console_serve_file(server.uri())) { + server.send(404, "text/plain", "Not Found"); + } + }); +} + +void console_start() { + Serial.println(""); + console_dbg("Starting Access Point..."); + // WiFi.softAP(ssid, password); + WiFi.softAP(bt_devname, password); + delay(150); + IPAddress ip(10, 0, 0, 1); + IPAddress nm(255, 255, 255, 0); + WiFi.softAPConfig(ip, ip, nm); + + if(!SPIFFS.begin(true)){ + console_dbg("Error: Could not mount SPIFFS"); + return; + } else { + console_dbg("SPIFFS Ready"); + } + + console_register_pages(); + server.begin(); + led_indicate_console(); +} + +void console_loop(){ + server.handleClient(); + + // Internally, this yields the thread and allows + // other tasks to run. + delay(5); +} + +// void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ +// Serial.printf("Listing directory: %s\r\n", dirname); + +// File root = fs.open(dirname); +// if(!root){ +// Serial.println("- failed to open directory"); +// return; +// } +// if(!root.isDirectory()){ +// Serial.println(" - not a directory"); +// return; +// } + +// File file = root.openNextFile(); +// while(file){ +// if(file.isDirectory()){ +// Serial.print(" DIR : "); +// Serial.println(file.name()); +// if(levels){ +// listDir(fs, file.path(), levels -1); +// } +// } else { +// Serial.print(" FILE: "); +// Serial.print(file.name()); +// Serial.print("\tSIZE: "); +// Serial.println(file.size()); +// } +// file = root.openNextFile(); +// } +// } + +// void readFile(fs::FS &fs, const char * path){ +// Serial.printf("Reading file: %s\r\n", path); + +// File file = fs.open(path); +// if(!file || file.isDirectory()){ +// Serial.println("− failed to open file for reading"); +// return; +// } + +// Serial.println("− read from file:"); +// while(file.available()){ +// Serial.write(file.read()); +// } +// } diff --git a/Console/index.html b/Console/index.html new file mode 100644 index 0000000..b1c0e90 --- /dev/null +++ b/Console/index.html @@ -0,0 +1,14 @@ + + + + + +RNode Bootstrap Console + + + + + + \ No newline at end of file diff --git a/LoRa.cpp b/LoRa.cpp index ca28ab4..08df454 100644 --- a/LoRa.cpp +++ b/LoRa.cpp @@ -85,6 +85,8 @@ #define MAX_PKT_LENGTH 255 +bool lora_preinit_done = false; + LoRaClass::LoRaClass() : _spiSettings(8E6, MSBFIRST, SPI_MODE0), _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), @@ -97,13 +99,26 @@ LoRaClass::LoRaClass() : setTimeout(0); } -int LoRaClass::begin(long frequency) -{ +bool LoRaClass::preInit() { // setup pins pinMode(_ss, OUTPUT); // set SS high digitalWrite(_ss, HIGH); + + SPI.begin(); + // check version + uint8_t version = readRegister(REG_VERSION); + if (version != 0x12) { + return false; + } + + lora_preinit_done = true; + return true; +} + +int LoRaClass::begin(long frequency) +{ if (_reset != -1) { pinMode(_reset, OUTPUT); @@ -114,13 +129,10 @@ int LoRaClass::begin(long frequency) delay(10); } - // start SPI - SPI.begin(); - - // check version - uint8_t version = readRegister(REG_VERSION); - if (version != 0x12) { - return 0; + if (!lora_preinit_done) { + if (!preInit()) { + return false; + } } // put in sleep mode @@ -433,6 +445,11 @@ void LoRaClass::setTxPower(int level, int outputPin) { } } +uint8_t LoRaClass::getTxPower() { + byte txp = readRegister(REG_PA_CONFIG); + return txp; +} + void LoRaClass::setFrequency(long frequency) { _frequency = frequency; diff --git a/LoRa.h b/LoRa.h index 02a48c9..1df158d 100644 --- a/LoRa.h +++ b/LoRa.h @@ -54,6 +54,8 @@ public: void idle(); void sleep(); + bool preInit(); + uint8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(long frequency); diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 1f5c132..51945c4 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -32,9 +32,6 @@ char sbuf[128]; bool packet_ready = false; #endif -// TODO: Implement -bool console_active = true; - void setup() { #if MCU_VARIANT == MCU_ESP32 boot_seq(); @@ -75,6 +72,26 @@ void setup() { // Set chip select, reset and interrupt // pins for the LoRa module LoRa.setPins(pin_cs, pin_reset, pin_dio); + + if (LoRa.preInit()) { + sx1276_installed = true; + uint32_t lfr = LoRa.getFrequency(); + if (lfr == 0) { + // Normal boot + } else if (lfr == M_FRQ_R) { + // Quick reboot + #if HAS_CONSOLE + if (rtc_get_reset_reason(0) == POWERON_RESET) { + console_active = true; + } + #endif + } else { + // Unknown boot + } + LoRa.setFrequency(M_FRQ_S); + } else { + sx1276_installed = false; + } #if HAS_DISPLAY disp_ready = display_init(); @@ -91,15 +108,17 @@ void setup() { bt_init_ran = true; #endif - kiss_indicate_reset(); - if (console_active) { console_start(); + } else { + kiss_indicate_reset(); } #endif // Validate board health, EEPROM and config validate_status(); + + LoRa.setFrequency(0); } void lora_receive() { @@ -864,16 +883,27 @@ void validate_status() { if (eeprom_product_valid() && eeprom_model_valid() && eeprom_hwrev_valid()) { if (eeprom_checksum_valid()) { eeprom_ok = true; - #if PLATFORM == PLATFORM_ESP32 - if (device_init()) { + if (sx1276_installed) { + #if PLATFORM == PLATFORM_ESP32 + if (device_init()) { + hw_ready = true; + } else { + hw_ready = false; + } + #else hw_ready = true; - } else { - hw_ready = false; - } - #else - hw_ready = true; - #endif - + #endif + } else { + hw_ready = false; + Serial.write("No SX1276/SX1278 radio module found\r\n"); + #if HAS_DISPLAY + if (disp_ready) { + device_init_done = true; + update_display(); + } + #endif + } + if (hw_ready && eeprom_have_conf()) { eeprom_conf_load(); op_mode = MODE_TNC; @@ -969,8 +999,10 @@ void loop() { } #if MCU_VARIANT == MCU_ESP32 - buffer_serial(); - if (!fifo_isempty(&serialFIFO)) serial_poll(); + // if (!console_active) { + buffer_serial(); + if (!fifo_isempty(&serialFIFO)) serial_poll(); + // } #else if (!fifo_isempty_locked(&serialFIFO)) serial_poll(); #endif @@ -984,7 +1016,7 @@ void loop() { #endif #if HAS_BLUETOOTH - if (bt_ready) update_bt(); + if (!console_active && bt_ready) update_bt(); #endif } diff --git a/Release/spiffs.bin b/Release/spiffs.bin new file mode 100644 index 0000000..909ec9f Binary files /dev/null and b/Release/spiffs.bin differ diff --git a/Utilities.h b/Utilities.h index e224d14..f49e1da 100644 --- a/Utilities.h +++ b/Utilities.h @@ -326,6 +326,7 @@ unsigned long led_standby_ticks = 0; int8_t led_notready_direction = 0; unsigned long led_notready_ticks = 0; unsigned long led_standby_wait = 350; + unsigned long led_console_wait = 1; unsigned long led_notready_wait = 200; #else @@ -389,6 +390,34 @@ int8_t led_standby_direction = 0; } } + void led_indicate_console() { + npset(0x60, 0x00, 0x60); + // led_standby_ticks++; + + // if (led_standby_ticks > led_console_wait) { + // led_standby_ticks = 0; + + // if (led_standby_value <= led_standby_min) { + // led_standby_direction = 1; + // } else if (led_standby_value >= led_standby_max) { + // led_standby_direction = -1; + // } + + // uint8_t led_standby_intensity; + // led_standby_value += led_standby_direction; + // int led_standby_ti = led_standby_value - led_standby_lng; + + // if (led_standby_ti < 0) { + // led_standby_intensity = 0; + // } else if (led_standby_ti > led_standby_cut) { + // led_standby_intensity = led_standby_cut; + // } else { + // led_standby_intensity = led_standby_ti; + // } + // npset(led_standby_intensity, 0x00, led_standby_intensity); + // } + } + #else void led_indicate_standby() { led_standby_ticks++; @@ -418,6 +447,10 @@ int8_t led_standby_direction = 0; #endif } } + + void led_indicate_console() { + led_indicate_standby(); + } #endif #endif @@ -804,6 +837,11 @@ void set_implicit_length(uint8_t len) { } } +int getTxPower() { + uint8_t txp = LoRa.getTxPower(); + return (int)txp; +} + void setTXPower() { if (radio_online) { if (model == MODEL_A2) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);