diff --git a/boards/nano-g2-ultra.json b/boards/nano-g2-ultra.json new file mode 100644 index 00000000..11e7ebaa --- /dev/null +++ b/boards/nano-g2-ultra.json @@ -0,0 +1,72 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + [ + "0x239A", + "0x8029" + ], + [ + "0x239A", + "0x0029" + ], + [ + "0x239A", + "0x002A" + ], + [ + "0x239A", + "0x802A" + ] + ], + "usb_product": "BQ nRF52840", + "mcu": "nrf52840", + "variant": "nano-g2-ultra", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "BQ nRF52840", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra", + "vendor": "BQ Consulting" +} \ No newline at end of file diff --git a/boards/rak3172.json b/boards/rak3172.json new file mode 100644 index 00000000..dbb70b03 --- /dev/null +++ b/boards/rak3172.json @@ -0,0 +1,33 @@ +{ + "build": { + "arduino": { + "variant_h": "variant_RAK3172_MODULE.h" + }, + "core": "stm32", + "cpu": "cortex-m4", + "extra_flags": "-DSTM32WL -DSTM32WLxx -DSTM32WLE5xx", + "framework_extra_flags": { + "arduino": "-DUSE_CM4_STARTUP_FILE -DARDUINO_RAK3172_MODULE" + }, + "f_cpu": "48000000L", + "mcu": "stm32wle5ccu", + "product_line": "STM32WLE5xx", + "variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U" + }, + "debug": { + "default_tools": ["stlink"], + "jlink_device": "STM32WLE5CC", + "openocd_target": "stm32wlx", + "svd_path": "STM32WLE5_CM4.svd" + }, + "frameworks": ["arduino"], + "name": "BB-STM32WL", + "upload": { + "maximum_ram_size": 65536, + "maximum_size": 262144, + "protocol": "stlink", + "protocols": ["stlink", "jlink"] + }, + "url": "https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172", + "vendor": "RAK" +} diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 2f209c54..09d04266 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -19,6 +19,7 @@ struct NodePrefs { // persisted to file uint8_t tx_power_dbm; uint8_t telemetry_mode_base; uint8_t telemetry_mode_loc; + uint8_t telemetry_mode_env; float rx_delay_base; uint32_t ble_pin; }; diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index e0c2ec51..f4e3fb0b 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -53,6 +53,31 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs, const char* bu // v1.2.3 (1 Jan 2025) sprintf(_version_info, "%s (%s)", version, build_date); + +#ifdef PIN_BUZZER + buzzer.begin(); +#endif +} + +void UITask::soundBuzzer(UIEventType bet) { +#if defined(PIN_BUZZER) +switch(bet){ + case UIEventType::contactMessage: + // gemini's pick + buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); + break; + case UIEventType::channelMessage: + buzzer.play("kerplop:d=16,o=6,b=120:32g#,32c#"); + break; + case UIEventType::roomMessage: + case UIEventType::newContactMessage: + case UIEventType::none: + default: + break; +} +#endif +// Serial.print("DBG: Buzzzzzz -> "); +// Serial.println((int) bet); } void UITask::msgRead(int msgcount) { @@ -85,7 +110,7 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i } } -void renderBatteryIndicator(DisplayDriver* _display, uint16_t batteryMilliVolts) { +void UITask::renderBatteryIndicator(uint16_t batteryMilliVolts) { // Convert millivolts to percentage const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V) const int maxMilliVolts = 4200; // Maximum voltage (e.g., 4.2V) @@ -107,8 +132,8 @@ void renderBatteryIndicator(DisplayDriver* _display, uint16_t batteryMilliVolts) _display->fillRect(iconX + iconWidth, iconY + (iconHeight / 4), 3, iconHeight / 2); // fill the battery based on the percentage - int fillWidth = (batteryPercentage * (iconWidth - 2)) / 100; - _display->fillRect(iconX + 1, iconY + 1, fillWidth, iconHeight - 2); + int fillWidth = (batteryPercentage * (iconWidth - 4)) / 100; + _display->fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4); } void UITask::renderCurrScreen() { @@ -155,7 +180,7 @@ void UITask::renderCurrScreen() { _display->print(_node_prefs->node_name); // battery voltage - renderBatteryIndicator(_display, _board->getBattMilliVolts()); + renderBatteryIndicator(_board->getBattMilliVolts()); // freq / sf _display->setCursor(0, 20); @@ -209,45 +234,58 @@ void UITask::userLedHandler() { } void UITask::buttonHandler() { -#ifdef PIN_USER_BTN - static int prev_btn_state = !USER_BTN_PRESSED; - static unsigned long btn_state_change_time = 0; - static unsigned long next_read = 0; - int cur_time = millis(); - if (cur_time >= next_read) { - int btn_state = digitalRead(PIN_USER_BTN); - if (btn_state != prev_btn_state) { - if (btn_state == USER_BTN_PRESSED) { // pressed? - if (_display != NULL) { - if (_display->isOn()) { - clearMsgPreview(); - } else { - _display->turnOn(); - _need_refresh = true; + #if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA) + static int prev_btn_state = !USER_BTN_PRESSED; + static int prev_btn_state_ana = !USER_BTN_PRESSED; + static unsigned long btn_state_change_time = 0; + static unsigned long next_read = 0; + int cur_time = millis(); + if (cur_time >= next_read) { + int btn_state = 0; + int btn_state_ana = 0; + #ifdef PIN_USER_BTN + btn_state = digitalRead(PIN_USER_BTN); + #endif + #ifdef PIN_USER_BTN_ANA + btn_state_ana = (analogRead(PIN_USER_BTN_ANA) < 20); // analogRead returns a value hopefully below 20 when button is pressed. + #endif + if (btn_state != prev_btn_state || btn_state_ana != prev_btn_state_ana) { // check for either digital or analogue button change of state + if (btn_state == USER_BTN_PRESSED || btn_state_ana == USER_BTN_PRESSED) { // pressed? + if (_display != NULL) { + if (_display->isOn()) { + clearMsgPreview(); + } else { + _display->turnOn(); + _need_refresh = true; + } + _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer + } + } else { // unpressed ? check pressed time ... + if ((cur_time - btn_state_change_time) > 5000) { + #ifdef PIN_STATUS_LED + digitalWrite(PIN_STATUS_LED, LOW); + delay(10); + #endif + _board->powerOff(); } - _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer - } - } else { // unpressed ? check pressed time ... - if ((cur_time - btn_state_change_time) > 5000) { - #ifdef PIN_STATUS_LED - digitalWrite(PIN_STATUS_LED, LOW); - delay(10); - #endif - _board->powerOff(); } + btn_state_change_time = millis(); + prev_btn_state = btn_state; + prev_btn_state_ana = btn_state_ana; } - btn_state_change_time = millis(); - prev_btn_state = btn_state; + next_read = millis() + 100; // 10 reads per second } - next_read = millis() + 100; // 10 reads per second + #endif } -#endif -} void UITask::loop() { buttonHandler(); userLedHandler(); +#ifdef PIN_BUZZER + if (buzzer.isPlaying()) buzzer.loop(); +#endif + if (_display != NULL && _display->isOn()) { static bool _firstBoot = true; if(_firstBoot && millis() >= BOOT_SCREEN_MILLIS) { diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 5edaa8e2..134b5a16 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -4,11 +4,27 @@ #include #include +#ifdef PIN_BUZZER + #include +#endif + #include "NodePrefs.h" + enum class UIEventType +{ + none, + contactMessage, + channelMessage, + roomMessage, + newContactMessage +}; + class UITask { DisplayDriver* _display; mesh::MainBoard* _board; +#ifdef PIN_BUZZER + genericBuzzer buzzer; +#endif unsigned long _next_refresh, _auto_off; bool _connected; uint32_t _pin_code; @@ -22,7 +38,9 @@ class UITask { void renderCurrScreen(); void buttonHandler(); void userLedHandler(); + void renderBatteryIndicator(uint16_t batteryMilliVolts); + public: UITask(mesh::MainBoard* board) : _board(board), _display(NULL) { @@ -36,5 +54,6 @@ public: void clearMsgPreview(); void msgRead(int msgcount); void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); + void soundBuzzer(UIEventType bet = UIEventType::none); void loop(); }; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 02f16ab0..13db88c0 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -60,30 +60,7 @@ #define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" -#ifdef DISPLAY_CLASS // TODO: refactor this -- move to variants/*/target - #include "UITask.h" - #ifdef ST7735 - #include - #elif ST7789 - #include - #elif SH1106 - #include - #elif defined(HAS_GxEPD) - #include - #else - #include - #endif - - #if defined(HELTEC_LORA_V3) && defined(ST7735) - static DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared - #else - static DISPLAY_CLASS display; - #endif - - #define HAS_UI -#endif - -#if defined(HAS_UI) +#ifdef DISPLAY_CLASS #include "UITask.h" static UITask ui_task(&board); @@ -104,11 +81,11 @@ static uint32_t _atoi(const char* sp) { #define FIRMWARE_VER_CODE 5 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #define CMD_APP_START 1 @@ -294,8 +271,8 @@ class MyMesh : public BaseChatMesh { void saveContacts() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/contacts3"); File file = _fs->open("/contacts3", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "w"); #else @@ -359,8 +336,8 @@ class MyMesh : public BaseChatMesh { void saveChannels() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/channels2"); File file = _fs->open("/channels2", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "w"); #else @@ -416,8 +393,8 @@ class MyMesh : public BaseChatMesh { sprintf(path, "/bl/%s", fname); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(path); File f = _fs->open(path, FILE_O_WRITE); - if (f) { f.seek(0); f.truncate(); } #elif defined(RP2040_PLATFORM) File f = _fs->open(path, "w"); #else @@ -506,10 +483,6 @@ class MyMesh : public BaseChatMesh { return 0; // queue is empty } - void soundBuzzer() { - // TODO - } - protected: float getAirtimeBudgetFactor() const override { return _prefs.airtime_factor; @@ -546,7 +519,9 @@ protected: _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::newContactMessage); + #endif } saveContacts(); @@ -607,9 +582,11 @@ protected: frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::contactMessage); + #endif } - #ifdef HAS_UI + #ifdef DISPLAY_CLASS ui_task.newMsg(path_len, from.name, text, offline_queue_len); #endif } @@ -658,9 +635,11 @@ protected: frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::channelMessage); + #endif } - #ifdef HAS_UI + #ifdef DISPLAY_CLASS ui_task.newMsg(path_len, "Public", text, offline_queue_len); #endif } @@ -682,6 +661,12 @@ protected: permissions |= cp & TELEM_PERM_LOCATION; } + if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { + permissions |= TELEM_PERM_ENVIRONMENT; + } else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { + permissions |= cp & TELEM_PERM_ENVIRONMENT; + } + if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set telemetry.reset(); telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); @@ -845,7 +830,7 @@ public: file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.read((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 file.read((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.read(pad, 1); // 71 + file.read((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 file.read(pad, 4); // 76 file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 @@ -884,6 +869,11 @@ public: mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4); strcpy(_prefs.node_name, pub_key_hex); + // if name is provided as a build flag, use that as default node name instead + #ifdef ADVERT_NAME + strcpy(_prefs.node_name, ADVERT_NAME); + #endif + // load persisted prefs if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename @@ -895,7 +885,7 @@ public: #ifdef BLE_PIN_CODE if (_prefs.ble_pin == 0) { - #ifdef HAS_UI + #ifdef DISPLAY_CLASS if (has_display) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session @@ -936,8 +926,8 @@ public: void savePrefs() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/new_prefs"); File file = _fs->open("/new_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/new_prefs", "w"); #else @@ -961,7 +951,7 @@ public: file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.write((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 file.write((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.write(pad, 1); // 71 + file.write((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 file.write((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 file.write(pad, 4); // 76 file.write((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 @@ -1006,7 +996,7 @@ public: memcpy(&out_frame[i], &lon, 4); i += 4; out_frame[i++] = 0; // reserved out_frame[i++] = 0; // reserved - out_frame[i++] = (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ + out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; @@ -1244,7 +1234,7 @@ public: int out_len; if ((out_len = getFromOfflineQueue(out_frame)) > 0) { _serial->writeFrame(out_frame, out_len); - #ifdef HAS_UI + #ifdef DISPLAY_CLASS ui_task.msgRead(offline_queue_len); #endif } else { @@ -1298,6 +1288,7 @@ public: if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; + _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; } savePrefs(); writeOKFrame(); @@ -1572,7 +1563,7 @@ public: checkConnections(); } - #ifdef HAS_UI + #ifdef DISPLAY_CLASS ui_task.setHasConnection(_serial->isConnected()); ui_task.loop(); #endif @@ -1643,16 +1634,14 @@ void setup() { board.begin(); -#ifdef HAS_UI +#ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; - #ifdef DISPLAY_CLASS if (display.begin()) { disp = &display; disp->startFrame(); disp->print("Please wait..."); disp->endFrame(); } - #endif #endif if (!radio_init()) { halt(); } @@ -1662,7 +1651,7 @@ void setup() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) InternalFS.begin(); the_mesh.begin(InternalFS, - #ifdef HAS_UI + #ifdef DISPLAY_CLASS disp != NULL #else false @@ -1680,7 +1669,7 @@ void setup() { #elif defined(RP2040_PLATFORM) LittleFS.begin(); the_mesh.begin(LittleFS, - #ifdef HAS_UI + #ifdef DISPLAY_CLASS disp != NULL #else false @@ -1705,7 +1694,7 @@ void setup() { #elif defined(ESP32) SPIFFS.begin(true); the_mesh.begin(SPIFFS, - #ifdef HAS_UI + #ifdef DISPLAY_CLASS disp != NULL #else false @@ -1733,7 +1722,7 @@ void setup() { sensors.begin(); -#ifdef HAS_UI +#ifdef DISPLAY_CLASS ui_task.begin(disp, the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION, the_mesh.getBLEPin()); #endif } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 7b38f5c3..12c843b7 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #ifndef LORA_FREQ @@ -60,10 +60,6 @@ #endif #ifdef DISPLAY_CLASS - #include - - static DISPLAY_CLASS display; - #include "UITask.h" static UITask ui_task(display); #endif @@ -735,7 +731,7 @@ void setup() { board.begin(); #ifdef DISPLAY_CLASS - if(display.begin()){ + if (display.begin()) { display.startFrame(); display.print("Please wait..."); display.endFrame(); diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index c041c621..dad7ce78 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #ifndef LORA_FREQ @@ -68,10 +68,6 @@ #endif #ifdef DISPLAY_CLASS - #include - - static DISPLAY_CLASS display; - #include "UITask.h" static UITask ui_task(display); #endif @@ -909,7 +905,7 @@ void setup() { board.begin(); #ifdef DISPLAY_CLASS - if(display.begin()){ + if (display.begin()) { display.startFrame(); display.print("Please wait..."); display.endFrame(); diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 1d0d847f..63ff20da 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -127,8 +127,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { void saveContacts() { #if defined(NRF52_PLATFORM) + _fs->remove("/contacts"); File file = _fs->open("/contacts", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/contacts", "w"); #else @@ -341,8 +341,8 @@ public: void savePrefs() { #if defined(NRF52_PLATFORM) + _fs->remove("/node_prefs"); File file = _fs->open("/node_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/node_prefs", "w"); #else diff --git a/src/Mesh.cpp b/src/Mesh.cpp index fe3b2473..6029c192 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -71,7 +71,15 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { // remove our hash from 'path', then re-broadcast pkt->path_len -= PATH_HASH_SIZE; + #if 0 memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len); + #elif PATH_HASH_SIZE == 1 + for (int k = 0; k < pkt->path_len; k++) { // shuffle bytes by 1 + pkt->path[k] = pkt->path[k + 1]; + } + #else + #error "need path remove impl" + #endif uint32_t d = getDirectRetransmitDelay(pkt); return ACTION_RETRANSMIT_DELAYED(0, d); // Routed traffic is HIGHEST priority diff --git a/src/helpers/AdvertDataHelpers.cpp b/src/helpers/AdvertDataHelpers.cpp index 5972bce2..88253f61 100644 --- a/src/helpers/AdvertDataHelpers.cpp +++ b/src/helpers/AdvertDataHelpers.cpp @@ -8,8 +8,14 @@ memcpy(&app_data[i], &_lat, 4); i += 4; memcpy(&app_data[i], &_lon, 4); i += 4; } - // TODO: BATTERY encoding - // TODO: TEMPERATURE encoding + if (_extra1) { + app_data[0] |= ADV_FEAT1_MASK; + memcpy(&app_data[i], &_extra1, 2); i += 2; + } + if (_extra2) { + app_data[0] |= ADV_FEAT2_MASK; + memcpy(&app_data[i], &_extra2, 2); i += 2; + } if (_name && *_name != 0) { app_data[0] |= ADV_NAME_MASK; const char* sp = _name; @@ -25,17 +31,18 @@ _lat = _lon = 0; _flags = app_data[0]; _valid = false; - + _extra1 = _extra2 = 0; + int i = 1; if (_flags & ADV_LATLON_MASK) { memcpy(&_lat, &app_data[i], 4); i += 4; memcpy(&_lon, &app_data[i], 4); i += 4; } - if (_flags & ADV_BATTERY_MASK) { - /* TODO: somewhere to store battery volts? */ i += 2; + if (_flags & ADV_FEAT1_MASK) { + memcpy(&_extra1, &app_data[i], 2); i += 2; } - if (_flags & ADV_TEMPERATURE_MASK) { - /* TODO: somewhere to store temperature? */ i += 2; + if (_flags & ADV_FEAT2_MASK) { + memcpy(&_extra2, &app_data[i], 2); i += 2; } if (app_data_len >= i) { diff --git a/src/helpers/AdvertDataHelpers.h b/src/helpers/AdvertDataHelpers.h index a8a24a0a..14815eac 100644 --- a/src/helpers/AdvertDataHelpers.h +++ b/src/helpers/AdvertDataHelpers.h @@ -11,20 +11,25 @@ //FUTURE: 4..15 #define ADV_LATLON_MASK 0x10 -#define ADV_BATTERY_MASK 0x20 -#define ADV_TEMPERATURE_MASK 0x40 +#define ADV_FEAT1_MASK 0x20 // FUTURE +#define ADV_FEAT2_MASK 0x40 // FUTURE #define ADV_NAME_MASK 0x80 class AdvertDataBuilder { uint8_t _type; const char* _name; int32_t _lat, _lon; + uint16_t _extra1 = 0; + uint16_t _extra2 = 0; public: AdvertDataBuilder(uint8_t adv_type) : _type(adv_type), _name(NULL), _lat(0), _lon(0) { } AdvertDataBuilder(uint8_t adv_type, const char* name) : _type(adv_type), _name(name), _lat(0), _lon(0) { } AdvertDataBuilder(uint8_t adv_type, const char* name, double lat, double lon) : _type(adv_type), _name(name), _lat(lat * 1E6), _lon(lon * 1E6) { } + void setFeat1(uint16_t extra) { _extra1 = extra; } + void setFeat2(uint16_t extra) { _extra2 = extra; } + /** * \brief encode the given advertisement data. * \param app_data dest array, must be MAX_ADVERT_DATA_SIZE @@ -38,11 +43,15 @@ class AdvertDataParser { bool _valid; char _name[MAX_ADVERT_DATA_SIZE]; int32_t _lat, _lon; + uint16_t _extra1; + uint16_t _extra2; public: AdvertDataParser(const uint8_t app_data[], uint8_t app_data_len); bool isValid() const { return _valid; } uint8_t getType() const { return _flags & 0x0F; } + uint16_t getFeat1() const { return _extra1; } + uint16_t getFeat2() const { return _extra2; } bool hasName() const { return _name[0] != 0; } const char* getName() const { return _name; } diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index f3f7727c..8b8296f5 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -74,8 +74,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { void CommonCLI::savePrefs(FILESYSTEM* fs) { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + fs->remove("/com_prefs"); File file = fs->open("/com_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = fs->open("/com_prefs", "w"); #else @@ -358,6 +358,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _callbacks->dumpLogFile(); strcpy(reply, " EOF"); } else { - sprintf(reply, "Unknown: %s", command); + strcpy(reply, "Unknown command"); } } diff --git a/src/helpers/IdentityStore.cpp b/src/helpers/IdentityStore.cpp index 85f146c5..dc85d69c 100644 --- a/src/helpers/IdentityStore.cpp +++ b/src/helpers/IdentityStore.cpp @@ -47,8 +47,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) { sprintf(filename, "%s/%s.id", _dir, name); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(filename); File file = _fs->open(filename, FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open(filename, "w"); #else @@ -69,8 +69,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id, const sprintf(filename, "%s/%s.id", _dir, name); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(filename); File file = _fs->open(filename, FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open(filename, "w"); #else diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index 839e2736..0e4bc27d 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -11,8 +11,9 @@ class SensorManager { public: double node_lat, node_lon; // modify these, if you want to affect Advert location + double node_altitude; // altitude in meters - SensorManager() { node_lat = 0; node_lon = 0; } + SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; } virtual bool begin() { return false; } virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; } virtual void loop() { } diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h index 5a8070b9..74d9ca2e 100644 --- a/src/helpers/TBeamS3SupremeBoard.h +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -15,8 +15,8 @@ #define P_LORA_MISO 13 //SX1262 MISO pin #define P_LORA_MOSI 11 //SX1262 MOSI pin -#define PIN_BOARD_SDA 17 //SDA for OLED, BME280, and QMC6310U (0x1C) -#define PIN_BOARD_SCL 18 //SCL for OLED, BME280, and QMC6310U (0x1C) +//#define PIN_BOARD_SDA 17 //SDA for OLED, BME280, and QMC6310U (0x1C) +//#define PIN_BOARD_SCL 18 //SCL for OLED, BME280, and QMC6310U (0x1C) #define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC) #define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC) @@ -58,6 +58,7 @@ public: void printPMU(); #endif bool power_init(); + void begin() { power_init(); diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 8b368734..eb1a42c5 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -26,6 +26,10 @@ void RAK4631Board::begin() { pinMode(PIN_USER_BTN, INPUT_PULLUP); #endif +#ifdef PIN_USER_BTN_ANA + pinMode(PIN_USER_BTN_ANA, INPUT_PULLUP); +#endif + #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp new file mode 100644 index 00000000..dda1fd55 --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -0,0 +1,231 @@ +#include "EnvironmentSensorManager.h" + +#if ENV_INCLUDE_AHTX0 +#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address +#include +static Adafruit_AHTX0 AHTX0; +#endif + +#if ENV_INCLUDE_BME280 +#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address +#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level +#include +static Adafruit_BME280 BME280; +#endif + +#if ENV_INCLUDE_INA3221 +#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address +#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts +#define TELEM_INA3221_NUM_CHANNELS 3 +#include +static Adafruit_INA3221 INA3221; +#endif + +#if ENV_INCLUDE_INA219 +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address +#include +static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS); +#endif + +bool EnvironmentSensorManager::begin() { + #if ENV_INCLUDE_GPS + initBasicGPS(); + #endif + + #if ENV_INCLUDE_AHTX0 + if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); + AHTX0_initialized = true; + } else { + AHTX0_initialized = false; + MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); + } + #endif + + #if ENV_INCLUDE_BME280 + if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); + MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID()); + BME280_initialized = true; + } else { + BME280_initialized = false; + MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); + } + #endif + + #if ENV_INCLUDE_INA3221 + if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); + MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); + + for(int i = 0; i < 3; i++) { + INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); + } + INA3221_initialized = true; + } else { + INA3221_initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + } + #endif + + #if ENV_INCLUDE_INA219 + if (INA219.begin(&Wire)) { + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); + INA219_initialized = true; + } else { + INA219_initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + } + #endif + + return true; +} + +bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + next_available_channel = TELEM_CHANNEL_SELF + 1; + + if (requester_permissions & TELEM_PERM_LOCATION) { + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); // allow lat/lon via telemetry even if no GPS is detected + } + + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + + #if ENV_INCLUDE_AHTX0 + if (AHTX0_initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); + } + #endif + + #if ENV_INCLUDE_BME280 + if (BME280_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA)); + } + #endif + + #if ENV_INCLUDE_INA3221 + if (INA3221_initialized) { + for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { + // add only enabled INA3221 channels to telemetry + if (INA3221.isChannelEnabled(i)) { + float voltage = INA3221.getBusVoltage(i); + float current = INA3221.getCurrentAmps(i); + telemetry.addVoltage(next_available_channel, voltage); + telemetry.addCurrent(next_available_channel, current); + telemetry.addPower(next_available_channel, voltage * current); + next_available_channel++; + } + } + } + #endif + + #if ENV_INCLUDE_INA219 + if (INA219_initialized) { + telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); + telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); + telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); + next_available_channel++; + } + #endif + + } + + return true; +} + + +int EnvironmentSensorManager::getNumSettings() const { + #if ENV_INCLUDE_GPS + return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + #else + return 0; + #endif +} + +const char* EnvironmentSensorManager::getSettingName(int i) const { + #if ENV_INCLUDE_GPS + return (gps_detected && i == 0) ? "gps" : NULL; + #else + return NULL; + #endif +} + +const char* EnvironmentSensorManager::getSettingValue(int i) const { + #if ENV_INCLUDE_GPS + if (gps_detected && i == 0) { + return gps_active ? "1" : "0"; + } + #endif + return NULL; +} + +bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { + #if ENV_INCLUDE_GPS + if (gps_detected && strcmp(name, "gps") == 0) { + if (strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + #endif + return false; // not supported +} + +#if ENV_INCLUDE_GPS +void EnvironmentSensorManager::initBasicGPS() { + Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); + Serial1.begin(9600); + + // Try to detect if GPS is physically connected to determine if we should expose the setting + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS + + // Give GPS a moment to power up and send data + delay(1000); + + // We'll consider GPS detected if we see any data on Serial1 + gps_detected = (Serial1.available() > 0); + + if (gps_detected) { + MESH_DEBUG_PRINTLN("GPS detected"); + digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed + } else { + MESH_DEBUG_PRINTLN("No GPS detected"); + digitalWrite(PIN_GPS_EN, LOW); + } +} + +void EnvironmentSensorManager::start_gps() { + gps_active = true; + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, HIGH); +} + +void EnvironmentSensorManager::stop_gps() { + gps_active = false; + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, LOW); +} + +void EnvironmentSensorManager::loop() { + static long next_gps_update = 0; + + _location->loop(); + + if (millis() > next_gps_update) { + if (_location->isValid()) { + node_lat = ((double)_location->getLatitude())/1000000.; + node_lon = ((double)_location->getLongitude())/1000000.; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } +} +#endif \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h new file mode 100644 index 00000000..c9ec6870 --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +class EnvironmentSensorManager : public SensorManager { +protected: + int next_available_channel = TELEM_CHANNEL_SELF + 1; + + bool AHTX0_initialized = false; + bool BME280_initialized = false; + bool INA3221_initialized = false; + bool INA219_initialized = false; + + bool gps_detected = false; + bool gps_active = false; + + #if ENV_INCLUDE_GPS + LocationProvider* _location; + void start_gps(); + void stop_gps(); + void initBasicGPS(); + #endif + + +public: + #if ENV_INCLUDE_GPS + EnvironmentSensorManager(LocationProvider &location): _location(&location){}; + #else + EnvironmentSensorManager(){}; + #endif + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + #if ENV_INCLUDE_GPS + void loop() override; + #endif + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; diff --git a/src/helpers/sensors/LocationProvider.h b/src/helpers/sensors/LocationProvider.h index b5ac5812..056e61e0 100644 --- a/src/helpers/sensors/LocationProvider.h +++ b/src/helpers/sensors/LocationProvider.h @@ -8,6 +8,7 @@ class LocationProvider { public: virtual long getLatitude() = 0; virtual long getLongitude() = 0; + virtual long getAltitude() = 0; virtual bool isValid() = 0; virtual long getTimestamp() = 0; virtual void reset(); diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index da9f74f6..9f439e25 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -61,6 +61,11 @@ public : long getLatitude() override { return nmea.getLatitude(); } long getLongitude() override { return nmea.getLongitude(); } + long getAltitude() override { + long alt = 0; + nmea.getAltitude(alt); + return alt; + } bool isValid() override { return nmea.isValid(); } long getTimestamp() override { diff --git a/src/helpers/stm32/InternalFileSystem.cpp b/src/helpers/stm32/InternalFileSystem.cpp index 47706bac..2714ec6b 100644 --- a/src/helpers/stm32/InternalFileSystem.cpp +++ b/src/helpers/stm32/InternalFileSystem.cpp @@ -126,6 +126,9 @@ InternalFileSystem::InternalFileSystem(void) bool InternalFileSystem::begin(void) { + #ifdef FORMAT_FS + this->format(); + #endif // failed to mount, erase all sector then format and mount again if ( !Adafruit_LittleFS::begin() ) { diff --git a/src/helpers/ui/ST7735Display.cpp b/src/helpers/ui/ST7735Display.cpp index 91c40ea5..e9eea69b 100644 --- a/src/helpers/ui/ST7735Display.cpp +++ b/src/helpers/ui/ST7735Display.cpp @@ -1,5 +1,3 @@ -#ifdef ST7735 - #include "ST7735Display.h" #ifndef DISPLAY_ROTATION @@ -130,5 +128,3 @@ uint16_t ST7735Display::getTextWidth(const char* str) { void ST7735Display::endFrame() { // display.display(); } - -#endif \ No newline at end of file diff --git a/src/helpers/ui/buzzer.cpp b/src/helpers/ui/buzzer.cpp new file mode 100644 index 00000000..ccc18cd3 --- /dev/null +++ b/src/helpers/ui/buzzer.cpp @@ -0,0 +1,54 @@ +#ifdef PIN_BUZZER +#include "buzzer.h" + +void genericBuzzer::begin() { +// Serial.print("DBG: Setting up buzzer on pin "); +// Serial.println(PIN_BUZZER); + #ifdef PIN_BUZZER_EN + pinMode(PIN_BUZZER_EN, OUTPUT); + digitalWrite(PIN_BUZZER_EN, HIGH); + #endif + + quiet(false); + pinMode(PIN_BUZZER, OUTPUT); + startup(); +} + +void genericBuzzer::play(const char *melody) { + if (isPlaying()) // interrupt existing + { + rtttl::stop(); + } + + if (_is_quiet) return; + + rtttl::begin(PIN_BUZZER,melody); +// Serial.print("DBG: Playing melody - isQuiet: "); +// Serial.println(isQuiet()); +} + +bool genericBuzzer::isPlaying() { + return rtttl::isPlaying(); +} + +void genericBuzzer::loop() { + if (!rtttl::done()) rtttl::play(); +} + +void genericBuzzer::startup() { + play(startup_song); +} + +void genericBuzzer::shutdown() { + play(shutdown_song); +} + +void genericBuzzer::quiet(bool buzzer_state) { + _is_quiet = buzzer_state; +} + +bool genericBuzzer::isQuiet() { + return _is_quiet; +} + +#endif // ifdef PIN_BUZZER \ No newline at end of file diff --git a/src/helpers/ui/buzzer.h b/src/helpers/ui/buzzer.h new file mode 100644 index 00000000..0a500552 --- /dev/null +++ b/src/helpers/ui/buzzer.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +/* class abstracts underlying RTTTL library + + Just a simple imlementation to start. At the moment use same + melody for message and discovery + Suggest enum type for different sounds + - on message + - on discovery + + TODO + - make message ring tone configurable + +*/ + +class genericBuzzer +{ + public: + void begin(); // set up buzzer port + void play(const char *melody); // Generic play function + void loop(); // loop driven-nonblocking + void startup(); // play startup sound + void shutdown(); // play shutdown sound + bool isPlaying(); // returns true if a sound is still playing else false + void quiet(bool buzzer_state); // enables or disables the buzzer + bool isQuiet(); // get buzzer state on/off + + private: + // gemini's picks: + const char *startup_song = "Startup:d=4,o=5,b=160:16c6,16e6,8g6"; + const char *shutdown_song = "Shutdown:d=4,o=5,b=100:8g5,16e5,16c5"; + + bool _is_quiet = true; +}; diff --git a/variants/heltec_tracker/platformio.ini b/variants/heltec_tracker/platformio.ini index e0ad8b0f..d62771f4 100644 --- a/variants/heltec_tracker/platformio.ini +++ b/variants/heltec_tracker/platformio.ini @@ -31,6 +31,8 @@ build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_tracker> lib_deps = ${esp32_base.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0 [env:Heltec_Wireless_Tracker_companion_radio_ble] extends = Heltec_tracker_base @@ -38,7 +40,6 @@ build_flags = ${Heltec_tracker_base.build_flags} -I src/helpers/ui ; -D ARDUINO_USB_CDC_ON_BOOT=1 ; need for debugging - -D ST7735 -D DISPLAY_ROTATION=1 -D DISPLAY_CLASS=ST7735Display -D MAX_CONTACTS=100 @@ -57,5 +58,43 @@ build_src_filter = ${Heltec_tracker_base.build_src_filter} lib_deps = ${Heltec_tracker_base.lib_deps} densaugeo/base64 @ ~1.4.0 - stevemarple/MicroNMEA @ ^2.0.6 - adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0 + +[env:Heltec_Wireless_Tracker_repeater] +extends = Heltec_tracker_base +build_flags = + ${Heltec_tracker_base.build_flags} + -D DISPLAY_ROTATION=1 + -D DISPLAY_CLASS=ST7735Display + -D ADVERT_NAME='"Heltec Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_tracker_base.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${Heltec_tracker_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:Heltec_Wireless_Tracker_room_server] +extends = Heltec_tracker_base +build_flags = + ${Heltec_tracker_base.build_flags} + -D DISPLAY_ROTATION=1 + -D DISPLAY_CLASS=ST7735Display + -D ADVERT_NAME='"Heltec Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_tracker_base.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${Heltec_tracker_base.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index c82b70ad..042c7c0d 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -19,6 +19,10 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); HWTSensorManager sensors = HWTSensorManager(nmea); +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif @@ -103,7 +107,7 @@ bool HWTSensorManager::begin() { bool HWTSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } return true; } @@ -117,6 +121,7 @@ void HWTSensorManager::loop() { if (gps_active && _location->isValid()) { node_lat = ((double)_location->getLatitude())/1000000.; node_lon = ((double)_location->getLongitude())/1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); } next_gps_update = millis() + 1000; diff --git a/variants/heltec_tracker/target.h b/variants/heltec_tracker/target.h index 422e6f14..3184bec9 100644 --- a/variants/heltec_tracker/target.h +++ b/variants/heltec_tracker/target.h @@ -8,6 +8,9 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif class HWTSensorManager : public SensorManager { bool gps_active = false; @@ -31,6 +34,10 @@ extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern HWTSensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp index 44eb8def..a7e9fa67 100644 --- a/variants/heltec_v2/target.cpp +++ b/variants/heltec_v2/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/heltec_v2/target.h b/variants/heltec_v2/target.h index 92aec7f2..f758c193 100644 --- a/variants/heltec_v2/target.h +++ b/variants/heltec_v2/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern HeltecV2Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/heltec_v3/target.cpp b/variants/heltec_v3/target.cpp index 27e0ebf9..ab9b709f 100644 --- a/variants/heltec_v3/target.cpp +++ b/variants/heltec_v3/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/heltec_v3/target.h b/variants/heltec_v3/target.h index b6ab2577..76ad58a7 100644 --- a/variants/heltec_v3/target.h +++ b/variants/heltec_v3/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern HeltecV3Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/lilygo_t3s3/target.cpp b/variants/lilygo_t3s3/target.cpp index 4073518f..7fa45e54 100644 --- a/variants/lilygo_t3s3/target.cpp +++ b/variants/lilygo_t3s3/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/lilygo_t3s3/target.h b/variants/lilygo_t3s3/target.h index eef923ab..609248ae 100644 --- a/variants/lilygo_t3s3/target.h +++ b/variants/lilygo_t3s3/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern ESP32Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/lilygo_tbeam/platformio.ini b/variants/lilygo_tbeam/platformio.ini index 14ce144e..c471e44c 100644 --- a/variants/lilygo_tbeam/platformio.ini +++ b/variants/lilygo_tbeam/platformio.ini @@ -7,6 +7,7 @@ build_flags = -D LILYGO_TBEAM -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper + -D SX127X_CURRENT_LIMIT=120 -D LORA_TX_POWER=20 -D P_LORA_TX_LED=4 -D PIN_BOARD_SDA=21 @@ -31,8 +32,6 @@ build_flags = -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 ; -D RADIOLIB_DEBUG_BASIC=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 diff --git a/variants/lilygo_tbeam/target.cpp b/variants/lilygo_tbeam/target.cpp index 4e761cb2..116088d6 100644 --- a/variants/lilygo_tbeam/target.cpp +++ b/variants/lilygo_tbeam/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/lilygo_tbeam/target.h b/variants/lilygo_tbeam/target.h index 2c1897ef..4a9f0b3c 100644 --- a/variants/lilygo_tbeam/target.h +++ b/variants/lilygo_tbeam/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern TBeamBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/lilygo_tbeam_SX1262/target.cpp b/variants/lilygo_tbeam_SX1262/target.cpp index 4dcc3cf1..2f6666c5 100644 --- a/variants/lilygo_tbeam_SX1262/target.cpp +++ b/variants/lilygo_tbeam_SX1262/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/lilygo_tbeam_SX1262/target.h b/variants/lilygo_tbeam_SX1262/target.h index bcc80ef1..3f4d77fa 100644 --- a/variants/lilygo_tbeam_SX1262/target.h +++ b/variants/lilygo_tbeam_SX1262/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern TBeamBoardSX1262 board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index abcd89bc..e618613c 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -6,10 +6,13 @@ build_flags = -I variants/lilygo_tbeam_supreme_SX1262 -D LORA_TX_POWER=22 -D P_LORA_TX_LED=6 + -D PIN_BOARD_SDA=17 + -D PIN_BOARD_SCL=18 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper ;-D DISPLAY_CLASS=SSD1306Display ;Needs to be modified for SH1106 -D SX126X_RX_BOOSTED_GAIN=1 + -D SX126X_CURRENT_LIMIT=140 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_tbeam_supreme_SX1262> board_build.partitions = min_spiffs.csv ; get around 4mb flash limit diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 3808e5fd..f5b7080b 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -27,7 +27,68 @@ TbeamSupSensorManager sensors = TbeamSupSensorManager(nmea); static void setPMUIntFlag(){ pmuIntFlag = true; } + #ifdef MESH_DEBUG +uint32_t deviceOnline = 0x00; +void scanDevices(TwoWire *w) +{ + uint8_t err, addr; + int nDevices = 0; + uint32_t start = 0; + + Serial.println("Scanning I2C for Devices"); + for (addr = 1; addr < 127; addr++) { + start = millis(); + w->beginTransmission(addr); delay(2); + err = w->endTransmission(); + if (err == 0) { + nDevices++; + switch (addr) { + case 0x77: + case 0x76: + Serial.println("\tFound BMX280 Sensor"); + deviceOnline |= BME280_ONLINE; + break; + case 0x34: + Serial.println("\tFound AXP192/AXP2101 PMU"); + deviceOnline |= POWERMANAGE_ONLINE; + break; + case 0x3C: + Serial.println("\tFound SSD1306/SH1106 dispaly"); + deviceOnline |= DISPLAY_ONLINE; + break; + case 0x51: + Serial.println("\tFound PCF8563 RTC"); + deviceOnline |= PCF8563_ONLINE; + break; + case 0x1C: + Serial.println("\tFound QMC6310 MAG Sensor"); + deviceOnline |= QMC6310_ONLINE; + break; + default: + Serial.print("\tI2C device found at address 0x"); + if (addr < 16) { + Serial.print("0"); + } + Serial.print(addr, HEX); + Serial.println(" !"); + break; + } + + } else if (err == 4) { + Serial.print("Unknow error at address 0x"); + if (addr < 16) { + Serial.print("0"); + } + Serial.println(addr, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found\n"); + + Serial.println("Scan for devices is complete."); + Serial.println("\n"); +} void TBeamS3SupremeBoard::printPMU() { Serial.print("isCharging:"); Serial.println(PMU.isCharging() ? "YES" : "NO"); @@ -58,9 +119,9 @@ bool TBeamS3SupremeBoard::power_init() PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); // Set up PMU interrupts - MESH_DEBUG_PRINTLN("Setting up PMU interrupts"); - pinMode(PIN_PMU_IRQ, INPUT_PULLUP); - attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING); + // MESH_DEBUG_PRINTLN("Setting up PMU interrupts"); + // pinMode(PIN_PMU_IRQ, INPUT_PULLUP); + // attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING); // GPS MESH_DEBUG_PRINTLN("Setting and enabling a-ldo4 for GPS"); @@ -73,74 +134,83 @@ bool TBeamS3SupremeBoard::power_init() PMU.enableALDO3(); // To avoid SPI bus issues during power up, reset OLED, sensor, and SD card supplies - MESH_DEBUG_PRINTLN("Reset a-ldo1&2 and b-ldo1"); - if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) - { - PMU.disableALDO1(); - PMU.disableALDO2(); - PMU.disableBLDO1(); - delay(250); - } + // MESH_DEBUG_PRINTLN("Reset a-ldo1&2 and b-ldo1"); + // if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) + // { + // PMU.disableALDO1(); + // PMU.disableALDO2(); + // PMU.disableBLDO1(); + // delay(250); + // } - // BME280 and OLED - MESH_DEBUG_PRINTLN("Setting and enabling a-ldo1 for oled"); - PMU.setALDO1Voltage(3300); - PMU.enableALDO1(); + // m.2 interface + MESH_DEBUG_PRINTLN("Setting and enabling dcdc3 for m.2 interface"); + PMU.setDC3Voltage(3300); // doesn't go anywhere in the schematic?? + PMU.enableDC3(); // QMC6310U MESH_DEBUG_PRINTLN("Setting and enabling a-ldo2 for QMC"); PMU.setALDO2Voltage(3300); PMU.enableALDO2(); // disable to save power + // BME280 and OLED + MESH_DEBUG_PRINTLN("Setting and enabling a-ldo1 for oled"); + PMU.setALDO1Voltage(3300); + PMU.enableALDO1(); + // SD card MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for SD card"); PMU.setBLDO1Voltage(3300); PMU.enableBLDO1(); // Out to header pins - MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header"); - PMU.setBLDO2Voltage(3300); - PMU.enableBLDO2(); + // MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header"); + // PMU.setBLDO2Voltage(3300); + // PMU.enableBLDO2(); - MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header"); - PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V - PMU.enableDC4(); + // MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header"); + // PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V + // PMU.enableDC4(); - MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header"); - PMU.setDC5Voltage(3300); - PMU.enableDC5(); - - // Other power rails - MESH_DEBUG_PRINTLN("Setting and enabling dcdc3 for ?"); - PMU.setDC3Voltage(3300); // doesn't go anywhere in the schematic?? - PMU.enableDC3(); + // MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header"); + // PMU.setDC5Voltage(3300); + // PMU.enableDC5(); // Unused power rails MESH_DEBUG_PRINTLN("Disabling unused supplies dcdc2, dldo1 and dldo2"); PMU.disableDC2(); + PMU.disableDC5(); PMU.disableDLDO1(); PMU.disableDLDO2(); - // Set charge current to 300mA + PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + + // Set charge current to 500mA MESH_DEBUG_PRINTLN("Setting battery charge current limit and voltage"); PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + PMU.clearIrqStatus(); + PMU.disableTSPinMeasure(); + // enable battery voltage measurement MESH_DEBUG_PRINTLN("Enabling battery measurement"); PMU.enableBattVoltageMeasure(); + PMU.enableVbusVoltageMeasure(); // Reset and re-enable PMU interrupts - MESH_DEBUG_PRINTLN("Re-enable interrupts"); - PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); - PMU.clearIrqStatus(); - PMU.enableIRQ( - XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts - XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts - XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts - XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts - ); + // MESH_DEBUG_PRINTLN("Re-enable interrupts"); + // PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + // PMU.clearIrqStatus(); + // PMU.enableIRQ( + // XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts + // XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts + // XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts + // XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts + // ); #ifdef MESH_DEBUG + // scanDevices(&Wire); + // scanDevices(&Wire1); printPMU(); #endif @@ -217,7 +287,7 @@ static bool l76kProbe() bool radio_init() { fallback_clock.begin(); - Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1); + rtc_clock.begin(Wire1); #ifdef SX126X_DIO3_TCXO_VOLTAGE @@ -287,7 +357,7 @@ bool TbeamSupSensorManager::begin() { bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } return true; } @@ -301,6 +371,7 @@ void TbeamSupSensorManager::loop() { if (_nmea->isValid()) { node_lat = ((double)_nmea->getLatitude())/1000000.; node_lon = ((double)_nmea->getLongitude())/1000000.; + node_altitude = ((double)_nmea->getAltitude()) / 1000.0; //Serial.printf("lat %f lon %f\r\n", _lat, _lon); } next_gps_update = millis() + 1000; diff --git a/variants/lilygo_tlora_v2_1/target.cpp b/variants/lilygo_tlora_v2_1/target.cpp index f5c14fe7..4d513ed9 100644 --- a/variants/lilygo_tlora_v2_1/target.cpp +++ b/variants/lilygo_tlora_v2_1/target.cpp @@ -12,6 +12,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/lilygo_tlora_v2_1/target.h b/variants/lilygo_tlora_v2_1/target.h index 9e73bc37..edf28eb4 100644 --- a/variants/lilygo_tlora_v2_1/target.h +++ b/variants/lilygo_tlora_v2_1/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern LilyGoTLoraBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/nano_g2_ultra/nano-g2.cpp b/variants/nano_g2_ultra/nano-g2.cpp new file mode 100644 index 00000000..8088ddd0 --- /dev/null +++ b/variants/nano_g2_ultra/nano-g2.cpp @@ -0,0 +1,102 @@ +#include +#include "nano-g2.h" + +#ifdef NANO_G2_ULTRA + +#include +#include + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) +{ + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + +void NanoG2Ultra::begin() +{ + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + + // set user button + pinMode(PIN_BUTTON1, INPUT); + + // the external notification circuit is shared for both buzzer and led + pinMode(EXT_NOTIFY_OUT, OUTPUT); + digitalWrite(EXT_NOTIFY_OUT, LOW); + + Wire.begin(); + pinMode(SX126X_POWER_EN, OUTPUT); + digitalWrite(SX126X_POWER_EN, HIGH); + + delay(10); +} + +uint16_t NanoG2Ultra::getBattMilliVolts() +{ + int adcvalue = 0; + + analogReference(AR_INTERNAL_3_0); + analogReadResolution(12); + delay(10); + + // ADC range is 0..3000mV and resolution is 12-bit (0..4095) + adcvalue = analogRead(PIN_VBAT_READ); + // Convert the raw value to compensated mv, taking the resistor- + // divider into account (providing the actual LIPO voltage) + return (uint16_t)((float)adcvalue * REAL_VBAT_MV_PER_LSB); +} + +bool NanoG2Ultra::startOTAUpdate(const char *id, char reply[]) +{ + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("TECHO_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + return true; +} +#endif diff --git a/variants/nano_g2_ultra/nano-g2.h b/variants/nano_g2_ultra/nano-g2.h new file mode 100644 index 00000000..99dc75fa --- /dev/null +++ b/variants/nano_g2_ultra/nano-g2.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +// LoRa radio module pins +#define P_LORA_DIO_1 (32 + 10) +#define P_LORA_NSS (32 + 13) +#define P_LORA_RESET (32 + 15) +#define P_LORA_BUSY (32 + 11) +#define P_LORA_SCLK (0 + 12) +#define P_LORA_MISO (32 + 9) +#define P_LORA_MOSI (0 + 11) + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define SX126X_POWER_EN 37 + +// buttons +#define PIN_BUTTON1 (32 + 6) +#define BUTTON_PIN PIN_BUTTON1 +#define PIN_USER_BTN BUTTON_PIN + +// built-ins +#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096 + +#define VBAT_DIVIDER (0.5F) // 150K + 150K voltage divider on VBAT, actually 100K + 100K +#define VBAT_DIVIDER_COMP (2.0F) // Compensation factor for the VBAT divider + +#define PIN_VBAT_READ (0 + 2) +#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) + +class NanoG2Ultra : public mesh::MainBoard +{ +protected: + uint8_t startup_reason; + +public: + void begin(); + uint16_t getBattMilliVolts() override; + bool startOTAUpdate(const char *id, char reply[]) override; + + uint8_t getStartupReason() const override + { + return startup_reason; + } + + const char *getManufacturerName() const override + { + return "Nano G2 Ultra"; + } + + void reboot() override + { + NVIC_SystemReset(); + } +}; diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini new file mode 100644 index 00000000..98feb35c --- /dev/null +++ b/variants/nano_g2_ultra/platformio.ini @@ -0,0 +1,59 @@ +[nrf52840_g2_ultra] +extends = nrf52_base +platform_packages = framework-arduinoadafruitnrf52 +build_flags = ${nrf52_base.build_flags} + -I src/helpers/nrf52 + -I lib/nrf52/s140_nrf52_6.1.1_API/include + -I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52 +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + lewisxhe/PCF8563_Library@^1.0.1 + +[Nano_G2_Ultra] +extends = nrf52840_g2_ultra +board = nano-g2-ultra +board_build.ldscript = boards/nrf52840_s140_v6.ld +build_flags = ${nrf52840_g2_ultra.build_flags} + -I variants/nano_g2_ultra + -D NANO_G2_ULTRA + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_USER_BTN=38 +build_src_filter = ${nrf52840_g2_ultra.build_src_filter} + + + +<../variants/nano_g2_ultra> +debug_tool = jlink +upload_protocol = nrfutil + +[env:Nano_G2_Ultra_companion_radio_ble] +extends = Nano_G2_Ultra +build_flags = + ${Nano_G2_Ultra.build_flags} + -I src/helpers/ui + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=0 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D DISPLAY_CLASS=SH1106Display + -D PIN_BUZZER=4 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Nano_G2_Ultra.build_src_filter} + + + + + + + +<../examples/companion_radio> +lib_deps = + ${Nano_G2_Ultra.lib_deps} + densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit SH110X @ ~2.1.13 + adafruit/Adafruit GFX Library @ ^1.12.1 + stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp new file mode 100644 index 00000000..33824f62 --- /dev/null +++ b/variants/nano_g2_ultra/target.cpp @@ -0,0 +1,183 @@ +#include +#include "target.h" +#include +#include + +NanoG2Ultra board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea); + +#ifdef DISPLAY_CLASS +DISPLAY_CLASS display; +#endif + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +bool radio_init() +{ + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + + SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); + SPI.begin(); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + if (status != RADIOLIB_ERR_NONE) + { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() +{ + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) +{ + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) +{ + radio.setOutputPower(dbm); +} + +void NanoG2UltraSensorManager::start_gps() +{ + if (!gps_active) + { + MESH_DEBUG_PRINTLN("starting GPS"); + digitalWrite(PIN_GPS_STANDBY, HIGH); + gps_active = true; + } +} + +void NanoG2UltraSensorManager::stop_gps() +{ + if (gps_active) + { + MESH_DEBUG_PRINTLN("stopping GPS"); + digitalWrite(PIN_GPS_STANDBY, LOW); + gps_active = false; + } +} + +bool NanoG2UltraSensorManager::begin() +{ + Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); // be sure to tx into rx and rx into tx + Serial1.begin(115200); + + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, HIGH); // Wake GPS from standby + delay(500); + + // We'll consider GPS detected if we see any data on Serial1 + if (Serial1.available() > 0) + { + MESH_DEBUG_PRINTLN("GPS detected"); + } + else + { + MESH_DEBUG_PRINTLN("No GPS detected"); + } + digitalWrite(GPS_EN, LOW); // Put GPS back into standby mode + return true; +} + +bool NanoG2UltraSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) +{ + if (requester_permissions & TELEM_PERM_LOCATION) + { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + return true; +} + +void NanoG2UltraSensorManager::loop() +{ + static long next_gps_update = 0; + _location->loop(); + if (millis() > next_gps_update && gps_active) // don't bother if gps position is not enabled + { + if (_location->isValid()) + { + node_lat = ((double)_location->getLatitude()) / 1000000.; + node_lon = ((double)_location->getLongitude()) / 1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + (1000 * 60); // after initial update, only check every minute TODO: should be configurable + } +} + +int NanoG2UltraSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char *NanoG2UltraSensorManager::getSettingName(int i) const +{ + return i == 0 ? "gps" : NULL; +} + +const char *NanoG2UltraSensorManager::getSettingValue(int i) const +{ + if (i == 0) + { + return gps_active ? "1" : "0"; + } + return NULL; +} + +bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *value) +{ + if (strcmp(name, "gps") == 0) + { + if (strcmp(value, "0") == 0) + { + stop_gps(); + } + else + { + start_gps(); + } + return true; + } + return false; // not supported +} + +mesh::LocalIdentity radio_new_identity() +{ + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/nano_g2_ultra/target.h b/variants/nano_g2_ultra/target.h new file mode 100644 index 00000000..e0d891e9 --- /dev/null +++ b/variants/nano_g2_ultra/target.h @@ -0,0 +1,47 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include "nano-g2.h" +#include +#include +#include +#include +#ifdef DISPLAY_CLASS +#include +#endif +#include + +class NanoG2UltraSensorManager : public SensorManager +{ + bool gps_active = false; + LocationProvider *_location; + + void start_gps(); + void stop_gps(); + +public: + NanoG2UltraSensorManager(LocationProvider &location) : _location(&location) {} + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) override; + void loop() override; + int getNumSettings() const override; + const char *getSettingName(int i) const override; + const char *getSettingValue(int i) const override; + bool setSettingValue(const char *name, const char *value) override; +}; + +extern NanoG2Ultra board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern NanoG2UltraSensorManager sensors; + +#ifdef DISPLAY_CLASS +extern DISPLAY_CLASS display; +#endif + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/nano_g2_ultra/variant.cpp b/variants/nano_g2_ultra/variant.cpp new file mode 100644 index 00000000..4ad554cd --- /dev/null +++ b/variants/nano_g2_ultra/variant.cpp @@ -0,0 +1,36 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // Nothing need to be inited for now +} \ No newline at end of file diff --git a/variants/nano_g2_ultra/variant.h b/variants/nano_g2_ultra/variant.h new file mode 100644 index 00000000..b8a53fcf --- /dev/null +++ b/variants/nano_g2_ultra/variant.h @@ -0,0 +1,193 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_Nano_G2_ +#define _VARIANT_Nano_G2_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// #define USE_LFRC // Board uses 32khz RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (-1) +#define PIN_LED2 (-1) +#define PIN_LED3 (-1) + +#define LED_RED PIN_LED3 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 + +#define LED_BUILTIN LED_BLUE +#define LED_CONN PIN_GREEN + +#define LED_STATE_ON 0 // State when LED is lit + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 6) + +#define EXT_NOTIFY_OUT (0 + 4) // Default pin to use for Ext Notify Module. + +/* + * Analog pins + */ +#define PIN_A4 (0 + 2) // Battery ADC + +#define BATTERY_PIN PIN_A4 + + static const uint8_t A4 = PIN_A4; + +#define ADC_RESOLUTION 14 + +/* + * Serial interfaces + */ +#define PIN_SERIAL2_RX (0 + 22) +#define PIN_SERIAL2_TX (0 + 20) + +/** + Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (0 + 17) +#define PIN_WIRE_SCL (0 + 15) + +#define PIN_RTC_INT (0 + 14) // Interrupt from the PCF8563 RTC + +/* +External serial flash W25Q16JV_IQ +*/ + +// QSPI Pins +#define PIN_QSPI_SCK (0 + 8) +#define PIN_QSPI_CS (32 + 7) +#define PIN_QSPI_IO0 (0 + 6) // MOSI if using two bit interface +#define PIN_QSPI_IO1 (0 + 26) // MISO if using two bit interface +#define PIN_QSPI_IO2 (32 + 4) // WP if using two bit interface (i.e. not used) +#define PIN_QSPI_IO3 (32 + 2) // HOLD if using two bit interface (i.e. not used) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES W25Q16JV_IQ +#define EXTERNAL_FLASH_USE_QSPI + + /* + * Lora radio + */ + +#define USE_SX1262 +#define SX126X_CS (32 + 13) // FIXME - we really should define LORA_CS instead +#define SX126X_DIO1 (32 + 10) +// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching +// #define SX1262_DIO3 (0 + 21) +// This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main CPU? +#define SX126X_BUSY (32 + 11) +#define SX126X_RESET (32 + 15) +// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + + // #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) + + // #undef SX126X_CS + + /* + * GPS pins + */ + +#define HAS_GPS 1 +#define GPS_L76K + +#define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY +#define PIN_GPS_TX (0 + 9) // This is for bits going TOWARDS the CPU +#define PIN_GPS_RX (0 + 10) // This is for bits going TOWARDS the GPS +#define GPS_RX_PIN PIN_GPS_RX +#define GPS_TX_PIN PIN_GPS_TX + + + // #define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX PIN_GPS_TX +#define PIN_SERIAL1_TX PIN_GPS_RX + +// PCF8563 RTC Module +#define PCF8563_RTC 0x51 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +// For LORA, spi 0 +#define PIN_SPI_MISO (32 + 9) +#define PIN_SPI_MOSI (0 + 11) +#define PIN_SPI_SCK (0 + 12) + +// #define PIN_PWR_EN (0 + 6) + +// To debug via the segger JLINK console rather than the CDC-ACM serial device +// #define USE_SEGGER + +// Battery +// The battery sense is hooked to pin A0 (2) +// it is defined in the anlaolgue pin section of this file +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (2.0F) + +#define HAS_RTC 1 + +/** + OLED Screen Model + */ +#define ARDUINO_ARCH_AVR +#define USE_SH1107_128_64 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 1cae8cdd..11f73d81 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -9,20 +9,30 @@ build_flags = ${nrf52840_base.build_flags} -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 - -D DISPLAY_CLASS=SSD1306Display -D PIN_BOARD_SCL=7 -D PIN_BOARD_SDA=8 -D PIN_OLED_RESET=-1 -D PIN_USER_BTN=6 + -D PIN_GPS_RX=3 + -D PIN_GPS_TX=4 + -D PIN_GPS_EN=5 + -D ENV_INCLUDE_GPS=1 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_base.build_src_filter} + + + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 - robtillaart/INA3221 @ ^0.4.1 - robtillaart/INA219 @ ^0.4.1 - adafruit/Adafruit AHTX0@^2.0.5 - + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + stevemarple/MicroNMEA @ ^2.0.6 + [env:Faketec_Repeater] extends = Faketec build_src_filter = ${Faketec.build_src_filter} @@ -35,6 +45,7 @@ build_flags = -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=SSD1306Display ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 lib_deps = ${Faketec.lib_deps} @@ -51,6 +62,7 @@ build_flags = ${Faketec.build_flags} -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' -D ROOM_PASSWORD='"hello"' + -D DISPLAY_CLASS=SSD1306Display ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 lib_deps = ${Faketec.lib_deps} @@ -74,6 +86,7 @@ extends = Faketec build_flags = ${Faketec.build_flags} -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=SSD1306Display ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${Faketec.build_src_filter} @@ -93,8 +106,9 @@ build_flags = ${Faketec.build_flags} -D ENABLE_PRIVATE_KEY_EXPORT=1 -D ENABLE_PRIVATE_KEY_IMPORT=1 -D OFFLINE_QUEUE_SIZE=256 + -D DISPLAY_CLASS=SSD1306Display ; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 + -D MESH_DEBUG=1 build_src_filter = ${Faketec.build_src_filter} + +<../examples/companion_radio> @@ -117,11 +131,13 @@ build_flags = ${nrf52840_base.build_flags} build_src_filter = ${nrf52840_base.build_src_filter} + + + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} - robtillaart/INA3221 @ ^0.4.1 - robtillaart/INA219 @ ^0.4.1 - adafruit/Adafruit AHTX0@^2.0.5 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:ProMicroLLCC68_Repeater] extends = ProMicroLLCC68 diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index b945fcf4..2369bd7a 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -2,6 +2,9 @@ #include "target.h" #include +#if ENV_INCLUDE_GPS +#endif + PromicroBoard board; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); @@ -10,7 +13,17 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -PromicroSensorManager sensors; +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif #ifndef LORA_CR #define LORA_CR 5 @@ -75,120 +88,3 @@ mesh::LocalIdentity radio_new_identity() { return mesh::LocalIdentity(&rng); // create new random identity } -static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); -static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); -static Adafruit_AHTX0 AHTX; - -bool PromicroSensorManager::begin() { - initINA3221(); - initINA219(); - initAHTX(); - - return true; -} - -bool PromicroSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - int nextAvalableChannel = TELEM_CHANNEL_SELF + 1; - if (requester_permissions & TELEM_PERM_ENVIRONMENT) { - if (INA3221initialized) { - for(int i = 0; i < 3; i++) { - // add only enabled INA3221 channels to telemetry - if (INA3221_CHANNEL_ENABLED[i]) { - telemetry.addVoltage(nextAvalableChannel, INA_3221.getBusVoltage(i)); - telemetry.addCurrent(nextAvalableChannel, INA_3221.getCurrent(i)); - telemetry.addPower(nextAvalableChannel, INA_3221.getPower(i)); - nextAvalableChannel++; - } - } - } - if (INA219initialized) { - telemetry.addVoltage(nextAvalableChannel, INA_219.getBusVoltage()); - telemetry.addCurrent(nextAvalableChannel, INA_219.getCurrent()); - telemetry.addPower(nextAvalableChannel, INA_219.getPower()); - nextAvalableChannel++; - } - if (AHTXinitialized) { - sensors_event_t humidity, temp; - AHTX.getEvent(&humidity, &temp); - telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); - } - } - - return true; -} - -int PromicroSensorManager::getNumSettings() const { - return NUM_SENSOR_SETTINGS; -} - -const char* PromicroSensorManager::getSettingName(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_NAMES[i]; - } - return NULL; -} - -const char* PromicroSensorManager::getSettingValue(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_ENABLED[i] ? "1" : "0"; - } - return NULL; -} - -bool PromicroSensorManager::setSettingValue(const char* name, const char* value) { - for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { - if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { - int channelEnabled = INA_3221.getEnableChannel(i); - if (strcmp(value, "1") == 0) { - INA3221_CHANNEL_ENABLED[i] = true; - if (!channelEnabled) { - INA_3221.enableChannel(i); - } - } else { - INA3221_CHANNEL_ENABLED[i] = false; - if (channelEnabled) { - INA_3221.disableChannel(i); - } - } - return true; - } - } - return false; -} - -void PromicroSensorManager::initINA3221() { - if (INA_3221.begin()) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); - MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); - - for(int i = 0; i < 3; i++) { - INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221initialized = true; - } else { - INA3221initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); - } -} - -void PromicroSensorManager::initINA219() { - if (INA_219.begin()) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); - INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); - INA219initialized = true; - } else { - INA219initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); - } -} - -void PromicroSensorManager::initAHTX() { - if (AHTX.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { - MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); - AHTXinitialized = true; - } else { - AHTXinitialized = false; - MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); - } -} diff --git a/variants/promicro/target.h b/variants/promicro/target.h index d77c4d1d..c634d18a 100644 --- a/variants/promicro/target.h +++ b/variants/promicro/target.h @@ -7,17 +7,20 @@ #include #include #include -#include -#include -#include -#include +#ifdef DISPLAY_CLASS + #include +#endif -#define NUM_SENSOR_SETTINGS 3 +#include extern PromicroBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif bool radio_init(); uint32_t radio_get_rng_seed(); @@ -25,39 +28,3 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); void radio_set_tx_power(uint8_t dbm); mesh::LocalIdentity radio_new_identity(); -#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address -#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address - -#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts -#define TELEM_INA3221_SETTING_CH1 "INA3221-1" -#define TELEM_INA3221_SETTING_CH2 "INA3221-2" -#define TELEM_INA3221_SETTING_CH3 "INA3221-3" - -#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) -#define TELEM_INA219_MAX_CURRENT 5 - -class PromicroSensorManager: public SensorManager { - bool INA3221initialized = false; - bool INA219initialized = false; - bool AHTXinitialized = false; - - // INA3221 channels in telemetry - const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; - bool INA3221_CHANNEL_ENABLED[NUM_SENSOR_SETTINGS] = {true, true, true}; - - void initINA3221(); - void initINA219(); - void initAHTX(); -public: - PromicroSensorManager(){}; - bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; -}; - - -extern PromicroSensorManager sensors; \ No newline at end of file diff --git a/variants/rak3x72/platformio.ini b/variants/rak3x72/platformio.ini new file mode 100644 index 00000000..94e8f595 --- /dev/null +++ b/variants/rak3x72/platformio.ini @@ -0,0 +1,33 @@ +[rak3x72] +extends = stm32_base +board = rak3172 +board_upload.maximum_size = 229376 ; 32kb for FS +build_flags = ${stm32_base.build_flags} + -D RADIO_CLASS=CustomSTM32WLx + -D WRAPPER_CLASS=CustomSTM32WLxWrapper + -D SPI_INTERFACES_COUNT=0 + -D RX_BOOSTED_GAIN=true + -I variants/rak3x72 +build_src_filter = ${stm32_base.build_src_filter} + +<../variants/rak3x72> + +[env:rak3x72-repeater] +extends = rak3x72 +build_flags = ${rak3x72.build_flags} + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"RAK3x72 Repeater"' + -D ADMIN_PASSWORD='"password"' +build_src_filter = ${rak3x72.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:rak3x72_companion_radio_usb] +extends = rak3x72 +build_flags = ${rak3x72.build_flags} +; -D FORMAT_FS=true + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +build_src_filter = ${rak3x72.build_src_filter} + +<../examples/companion_radio/*.cpp> +lib_deps = ${rak3x72.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp new file mode 100644 index 00000000..4cb5929a --- /dev/null +++ b/variants/rak3x72/target.cpp @@ -0,0 +1,67 @@ +#include +#include "target.h" +#include + +RAK3x72Board board; + +RADIO_CLASS radio = new STM32WLx_Module(); + +WRAPPER_CLASS radio_driver(radio, board); + +static const uint32_t rfswitch_pins[] = {LORAWAN_RFSWITCH_PINS, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {LOW, HIGH}}, + {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +VolatileRTCClock rtc_clock; +SensorManager sensors; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +bool radio_init() { +// rtc_clock.begin(Wire); + + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 0, 0); // TCXO set to 0 for RAK3172 + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + #ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); + #endif + + radio.setCRC(1); + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/rak3x72/target.h b/variants/rak3x72/target.h new file mode 100644 index 00000000..c39b69b1 --- /dev/null +++ b/variants/rak3x72/target.h @@ -0,0 +1,35 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include + +#define PIN_VBAT_READ A0 +#define ADC_MULTIPLIER (5 * 1.73 * 1000) + +class RAK3x72Board : public STM32Board { +public: + const char* getManufacturerName() const override { + return "RAK 3x72"; + } + + uint16_t getBattMilliVolts() override { + uint32_t raw = analogRead(PIN_VBAT_READ); + return (ADC_MULTIPLIER * raw) / 1024; + } +}; + +extern RAK3x72Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak3x72/variant.h b/variants/rak3x72/variant.h new file mode 100644 index 00000000..4405be0b --- /dev/null +++ b/variants/rak3x72/variant.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#undef RNG diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index d7584456..c2845fd4 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,6 +7,7 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index aaa3e8f1..9b23af83 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -12,6 +12,10 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/rak4631/target.h b/variants/rak4631/target.h index 91f1d719..a50d6f2c 100644 --- a/variants/rak4631/target.h +++ b/variants/rak4631/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern RAK4631Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/t1000-e/NullDisplayDriver.h b/variants/t1000-e/NullDisplayDriver.h new file mode 100644 index 00000000..2a9670bd --- /dev/null +++ b/variants/t1000-e/NullDisplayDriver.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +class NullDisplayDriver : public DisplayDriver { +public: + NullDisplayDriver() : DisplayDriver(128, 64) { } + bool begin() { return false; } // not present + + bool isOn() override { return false; } + void turnOn() override { } + void turnOff() override { } + void clear() override { } + void startFrame(Color bkg = DARK) override { } + void setTextSize(int sz) override { } + void setColor(Color c) override { } + void setCursor(int x, int y) override { } + void print(const char* str) override { } + void fillRect(int x, int y, int w, int h) override { } + void drawRect(int x, int y, int w, int h) override { } + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override { } + uint16_t getTextWidth(const char* str) override { return 0; } + void endFrame() { } +}; diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index 9f1a3b06..00974208 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -46,10 +46,14 @@ build_flags = ${t1000-e.build_flags} -D OFFLINE_QUEUE_SIZE=256 -D RX_BOOSTED_GAIN=true -D RF_SWITCH_TABLE - -D HAS_UI + -D DISPLAY_CLASS=NullDisplayDriver + -D PIN_BUZZER=25 + -D PIN_BUZZER_EN=37 ; P1/5 - required for T1000-E build_src_filter = ${t1000-e.build_src_filter} + + + +<../examples/companion_radio/*.cpp> lib_deps = ${t1000-e.lib_deps} densaugeo/base64 @ ~1.4.0 stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 \ No newline at end of file diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index f4bb75f6..be82ca76 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -12,6 +12,10 @@ VolatileRTCClock rtc_clock; MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); T1000SensorManager sensors = T1000SensorManager(nmea); +#ifdef DISPLAY_CLASS + NullDisplayDriver display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif @@ -154,7 +158,7 @@ bool T1000SensorManager::begin() { bool T1000SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } return true; } @@ -168,6 +172,7 @@ void T1000SensorManager::loop() { if (_nmea->isValid()) { node_lat = ((double)_nmea->getLatitude())/1000000.; node_lon = ((double)_nmea->getLongitude())/1000000.; + node_altitude = ((double)_nmea->getAltitude()) / 1000.0; //Serial.printf("lat %f lon %f\r\n", _lat, _lon); } next_gps_update = millis() + 1000; diff --git a/variants/t1000-e/target.h b/variants/t1000-e/target.h index 8e9fd9c7..1b569481 100644 --- a/variants/t1000-e/target.h +++ b/variants/t1000-e/target.h @@ -8,6 +8,9 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include "NullDisplayDriver.h" +#endif class T1000SensorManager: public SensorManager { bool gps_active = false; @@ -27,6 +30,10 @@ public: bool setSettingValue(const char* name, const char* value) override; }; +#ifdef DISPLAY_CLASS + extern NullDisplayDriver display; +#endif + extern T1000eBoard board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; diff --git a/variants/t114/target.cpp b/variants/t114/target.cpp index e8773dbb..a57a55e2 100644 --- a/variants/t114/target.cpp +++ b/variants/t114/target.cpp @@ -14,6 +14,10 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); T114SensorManager sensors = T114SensorManager(nmea); +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif @@ -93,7 +97,7 @@ bool T114SensorManager::begin() { digitalWrite(GPS_EN, HIGH); // Power on GPS // Give GPS a moment to power up and send data - delay(500); + delay(1500); // We'll consider GPS detected if we see any data on Serial1 gps_detected = (Serial1.available() > 0); @@ -111,7 +115,7 @@ bool T114SensorManager::begin() { bool T114SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } return true; } @@ -125,6 +129,7 @@ void T114SensorManager::loop() { if (_location->isValid()) { node_lat = ((double)_location->getLatitude())/1000000.; node_lon = ((double)_location->getLongitude())/1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); } next_gps_update = millis() + 1000; diff --git a/variants/t114/target.h b/variants/t114/target.h index 38d0e02a..0f6ebaa1 100644 --- a/variants/t114/target.h +++ b/variants/t114/target.h @@ -8,6 +8,9 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif class T114SensorManager : public SensorManager { bool gps_active = false; @@ -32,6 +35,10 @@ extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern T114SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/t114/variant.h b/variants/t114/variant.h index bceb1954..a0fd2e4f 100644 --- a/variants/t114/variant.h +++ b/variants/t114/variant.h @@ -72,7 +72,7 @@ #define LED_BLUE (-1) // No blue led, prevents Bluefruit flashing the green LED during advertising #define LED_PIN LED_BUILTIN -#define LED_STATE_ON HIGH +#define LED_STATE_ON LOW #define PIN_NEOPIXEL (14) #define NEOPIXEL_NUM (2) @@ -109,7 +109,7 @@ //////////////////////////////////////////////////////////////////////////////// // Buzzer -#define PIN_BUZZER (46) +// #define PIN_BUZZER (46) //////////////////////////////////////////////////////////////////////////////// diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index d9346948..c4bc8f85 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -64,7 +64,6 @@ build_flags = -D BLE_DEBUG_LOGGING=1 -D DISPLAY_CLASS=GxEPDDisplay -D OFFLINE_QUEUE_SIZE=256 - -D HAS_GxEPD ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/techo/target.cpp b/variants/techo/target.cpp index 0aabfd47..880af612 100644 --- a/variants/techo/target.cpp +++ b/variants/techo/target.cpp @@ -12,6 +12,10 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/techo/target.h b/variants/techo/target.h index 0ec9ab04..15524111 100644 --- a/variants/techo/target.h +++ b/variants/techo/target.h @@ -7,12 +7,20 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif + extern TechoBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/thinknode_m1/platformio.ini b/variants/thinknode_m1/platformio.ini index eec255d0..9bad98e2 100644 --- a/variants/thinknode_m1/platformio.ini +++ b/variants/thinknode_m1/platformio.ini @@ -70,7 +70,6 @@ build_flags = -D BLE_DEBUG_LOGGING=1 -D DISPLAY_ROTATION=4 -D DISPLAY_CLASS=GxEPDDisplay - -D HAS_GxEPD -D OFFLINE_QUEUE_SIZE=256 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index c31749f6..5a09eb9a 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -12,6 +12,10 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/thinknode_m1/target.h b/variants/thinknode_m1/target.h index 73e8a134..c958d0e3 100644 --- a/variants/thinknode_m1/target.h +++ b/variants/thinknode_m1/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern ThinkNodeM1Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index 4de13e7f..d8f7954f 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -6,6 +6,7 @@ build_flags = ${stm32_base.build_flags} -D RADIO_CLASS=CustomSTM32WLx -D WRAPPER_CLASS=CustomSTM32WLxWrapper -D SPI_INTERFACES_COUNT=0 + -D RX_BOOSTED_GAIN=true -I variants/wio-e5 build_src_filter = ${stm32_base.build_src_filter} +<../variants/wio-e5> @@ -13,7 +14,7 @@ build_src_filter = ${stm32_base.build_src_filter} [env:wio-e5-repeater] extends = lora_e5 build_flags = ${lora_e5.build_flags} - -D LORA_TX_POWER=20 + -D LORA_TX_POWER=22 -D ADVERT_NAME='"WIO-E5 Repeater"' -D ADMIN_PASSWORD='"password"' build_src_filter = ${lora_e5.build_src_filter} @@ -22,7 +23,7 @@ build_src_filter = ${lora_e5.build_src_filter} [env:wio-e5_companion_radio_usb] extends = lora_e5 build_flags = ${lora_e5.build_flags} - -D LORA_TX_POWER=20 + -D LORA_TX_POWER=22 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 build_src_filter = ${lora_e5.build_src_filter} diff --git a/variants/wio-e5/target.cpp b/variants/wio-e5/target.cpp index aee0dafb..8ccbe384 100644 --- a/variants/wio-e5/target.cpp +++ b/variants/wio-e5/target.cpp @@ -2,7 +2,7 @@ #include "target.h" #include -STM32Board board; +WIOE5Board board; RADIO_CLASS radio = new STM32WLx_Module(); @@ -42,7 +42,11 @@ bool radio_init() { Serial.println(status); return false; // fail } - + + #ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); + #endif + radio.setCRC(1); return true; // success diff --git a/variants/wio-e5/target.h b/variants/wio-e5/target.h index f2dae108..cc6131cf 100644 --- a/variants/wio-e5/target.h +++ b/variants/wio-e5/target.h @@ -8,7 +8,14 @@ #include #include -extern STM32Board board; +class WIOE5Board : public STM32Board { +public: + const char* getManufacturerName() const override { + return "Seeed Wio E5"; + } +}; + +extern WIOE5Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; extern SensorManager sensors; diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index 5083b1a3..2f468f4f 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -16,6 +16,11 @@ lib_ignore = lib_deps = ${nrf52_base.lib_deps} rweather/Crypto @ ^0.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + [Xiao_nrf52] extends = nrf52840_xiao @@ -35,8 +40,15 @@ build_flags = ${nrf52840_xiao.build_flags} -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_WIRE_SCL=6 + -D PIN_WIRE_SDA=7 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + +<../variants/xiao_nrf52> debug_tool = jlink diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp index 1d23e76a..c78ea159 100644 --- a/variants/xiao_nrf52/target.cpp +++ b/variants/xiao_nrf52/target.cpp @@ -9,7 +9,7 @@ RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BU WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock rtc_clock; -SensorManager sensors; +EnvironmentSensorManager sensors; #ifndef LORA_CR #define LORA_CR 5 diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index 868664b5..ec298a43 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -6,12 +6,12 @@ #include #include #include -#include +#include extern XiaoNrf52Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; -extern SensorManager sensors; +extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h index 0d0950af..d941463e 100644 --- a/variants/xiao_nrf52/variant.h +++ b/variants/xiao_nrf52/variant.h @@ -110,8 +110,8 @@ static const uint8_t A5 = PIN_A5; // Wire Interfaces #define WIRE_INTERFACES_COUNT (1) -#define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! -#define PIN_WIRE_SCL (16) // use WIRE1_SDA +// #define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! +// #define PIN_WIRE_SCL (16) // use WIRE1_SDA static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/xiao_s3_wio/target.cpp b/variants/xiao_s3_wio/target.cpp index 517b9ef6..09ee5daa 100644 --- a/variants/xiao_s3_wio/target.cpp +++ b/variants/xiao_s3_wio/target.cpp @@ -16,6 +16,10 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + #ifndef LORA_CR #define LORA_CR 5 #endif diff --git a/variants/xiao_s3_wio/target.h b/variants/xiao_s3_wio/target.h index eef923ab..609248ae 100644 --- a/variants/xiao_s3_wio/target.h +++ b/variants/xiao_s3_wio/target.h @@ -7,12 +7,19 @@ #include #include #include +#ifdef DISPLAY_CLASS + #include +#endif extern ESP32Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);