diff --git a/build_as_lib.py b/build_as_lib.py new file mode 100644 index 00000000..d8e95378 --- /dev/null +++ b/build_as_lib.py @@ -0,0 +1,64 @@ +from os.path import realpath + +Import("env") # type: ignore +menv=env # type: ignore + +src_filter = [ + '+<*.cpp>', + '+', + '+', + '+', + '+', + '+', +] + +# add build and include dirs according to CPPDEFINES +for item in menv.get("CPPDEFINES", []): + + # PLATFORM HANDLING + if item == "STM32_PLATFORM": + src_filter.append("+") + elif item == "ESP32": + src_filter.append("+") + elif item == "NRF52_PLATFORM": + src_filter.append("+") + elif item == "RP2040_PLATFORM": + src_filter.append("+") + + # DISPLAY HANDLING + elif isinstance(item, tuple) and item[0] == "DISPLAY_CLASS": + display_class = item[1] + src_filter.append(f"+") + if (display_class == "ST7789Display") : + src_filter.append(f"+") + src_filter.append(f"+") + + # VARIANTS HANDLING + elif isinstance(item, tuple) and item[0] == "MC_VARIANT": + variant_name = item[1] + src_filter.append(f"+<../variants/{variant_name}>") + + # INCLUDE EXAMPLE CODE IN BUILD (to provide your own support files without touching the tree) + elif isinstance(item, tuple) and item[0] == "BUILD_EXAMPLE": + example_name = item[1] + src_filter.append(f"+<../examples/{example_name}/*.cpp>") + + # EXCLUDE A SOURCE FILE FROM AN EXAMPLE (must be placed after example name or boom) + elif isinstance(item, tuple) and item[0] == "EXCLUDE_FROM_EXAMPLE": + exclude_name = item[1] + if example_name is None: + print("***** PLEASE DEFINE EXAMPLE FIRST *****") + break + src_filter.append(f"-<../examples/{example_name}/{exclude_name}>") + + # DEAL WITH UI VARIANT FOR AN EXAMPLE + elif isinstance(item, tuple) and item[0] == "MC_UI_FLAVOR": + ui_flavor = item[1] + if example_name is None: + print("***** PLEASE DEFINE EXAMPLE FIRST *****") + break + src_filter.append(f"+<../examples/{example_name}/{ui_flavor}/*.cpp>") + +menv.Replace(SRC_FILTER=src_filter) + +#print (menv.Dump()) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 9f34d913..1920dd26 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -213,10 +213,10 @@ public: display.setColor(DisplayDriver::GREEN); display.setTextSize(1); if (_shutdown_init) { - display.drawTextCentered(display.width() / 2, 34, "shutting down..."); + display.drawTextCentered(display.width() / 2, 34, "hibernating..."); } else { display.drawXbm((display.width() - 32) / 2, 18, power_icon, 32, 32); - display.drawTextCentered(display.width() / 2, 64 - 11, "off: " PRESS_LABEL); + display.drawTextCentered(display.width() / 2, 64 - 11, "hibernate: " PRESS_LABEL); } } return 5000; // next render after 5000 ms @@ -494,6 +494,20 @@ void UITask::loop() { c = handleLongPress(KEY_ENTER); } #endif +#if defined(WIO_TRACKER_L1) + ev = joystick_left.check(); + if (ev == BUTTON_EVENT_CLICK) { + c = checkDisplayOn(KEY_LEFT); + } else if (ev == BUTTON_EVENT_LONG_PRESS) { + c = handleLongPress(KEY_LEFT); + } + ev = joystick_right.check(); + if (ev == BUTTON_EVENT_CLICK) { + c = checkDisplayOn(KEY_RIGHT); + } else if (ev == BUTTON_EVENT_LONG_PRESS) { + c = handleLongPress(KEY_RIGHT); + } +#endif if (c != 0 && curr) { curr->handleInput(c); diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 7ad0e64a..81c4d455 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -159,7 +159,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { } void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr) { - #if MAX_NEIGHBOURS // check if neighbours enabled + #if MAX_NEIGHBOURS // check if neighbours enabled // find existing neighbour, else use least recently updated uint32_t oldest_timestamp = 0xFFFFFFFF; NeighbourInfo* neighbour = &neighbours[0]; @@ -589,7 +589,7 @@ public: _prefs.cr = LORA_CR; _prefs.tx_power_dbm = LORA_TX_POWER; _prefs.advert_interval = 1; // default to 2 minutes for NEW installs - _prefs.flood_advert_interval = 3; // 3 hours + _prefs.flood_advert_interval = 12; // 12 hours _prefs.flood_max = 64; _prefs.interference_threshold = 0; // disabled } @@ -611,8 +611,8 @@ public: const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; } const char* getRole() override { return FIRMWARE_ROLE; } const char* getNodeName() { return _prefs.node_name; } - NodePrefs* getNodePrefs() { - return &_prefs; + NodePrefs* getNodePrefs() { + return &_prefs; } void savePrefs() override { @@ -719,6 +719,17 @@ public: *dp = 0; // null terminator } + void removeNeighbor(const uint8_t* pubkey, int key_len) override { +#if MAX_NEIGHBOURS + for (int i = 0; i < MAX_NEIGHBOURS; i++) { + NeighbourInfo* neighbour = &neighbours[i]; + if(memcmp(neighbour->id.pub_key, pubkey, key_len) == 0){ + neighbours[i] = NeighbourInfo(); // clear neighbour entry + } + } +#endif + } + mesh::LocalIdentity& getSelfId() override { return self_id; } void clearStats() override { diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 34b94ad2..712d02a5 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -298,7 +298,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { // uint32_t now = getRTCClock()->getCurrentTimeUnique(); // memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp memcpy(reply_data, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') - + switch (payload[0]) { case REQ_TYPE_GET_STATUS: { ServerStats stats; @@ -746,9 +746,9 @@ public: _prefs.tx_power_dbm = LORA_TX_POWER; _prefs.disable_fwd = 1; _prefs.advert_interval = 1; // default to 2 minutes for NEW installs - _prefs.flood_advert_interval = 3; // 3 hours + _prefs.flood_advert_interval = 12; // 12 hours _prefs.flood_max = 64; - _prefs.interference_threshold = 0; // disabled + _prefs.interference_threshold = 0; // disabled #ifdef ROOM_PASSWORD StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password)); #endif @@ -778,8 +778,8 @@ public: const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; } const char* getRole() override { return FIRMWARE_ROLE; } const char* getNodeName() { return _prefs.node_name; } - NodePrefs* getNodePrefs() { - return &_prefs; + NodePrefs* getNodePrefs() { + return &_prefs; } void savePrefs() override { diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index ce36e0c2..ad295501 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -613,6 +613,23 @@ void SensorMesh::getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) { } } +void SensorMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) { + if (dest.out_path_len < 0) { + mesh::Packet* ack = createAck(ack_hash); + if (ack) sendFlood(ack, TXT_ACK_DELAY); + } else { + uint32_t d = TXT_ACK_DELAY; + if (getExtraAckTransmitCount() > 0) { + mesh::Packet* a1 = createMultiAck(ack_hash, 1); + if (a1) sendDirect(a1, dest.out_path, dest.out_path_len, d); + d += 300; + } + + mesh::Packet* a2 = createAck(ack_hash); + if (a2) sendDirect(a2, dest.out_path, dest.out_path_len, d); + } +} + void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) { int i = matching_peer_indexes[sender_idx]; if (i < 0 || i >= num_contacts) { @@ -656,38 +673,55 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong) uint flags = (data[4] >> 2); // message attempt number, and other flags - if (!(flags == TXT_TYPE_CLI_DATA)) { - MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); - } else if (sender_timestamp > from.last_timestamp) { // prevent replay attacks - from.last_timestamp = sender_timestamp; - from.last_activity = getRTCClock()->getCurrentTime(); + if (sender_timestamp > from.last_timestamp) { // prevent replay attacks + if (flags == TXT_TYPE_PLAIN) { + bool handled = handleIncomingMsg(from, sender_timestamp, &data[5], flags, len - 5); + if (handled) { // if msg was handled then send an ack + uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it + mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), from.id.pub_key, PUB_KEY_SIZE); - // len can be > original length, but 'text' will be padded with zeroes - data[len] = 0; // need to make a C string again, with null terminator - - uint8_t temp[166]; - char *command = (char *) &data[5]; - char *reply = (char *) &temp[5]; - handleCommand(sender_timestamp, command, reply); - - int text_len = strlen(reply); - if (text_len > 0) { - uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); - if (timestamp == sender_timestamp) { - // WORKAROUND: the two timestamps need to be different, in the CLI view - timestamp++; - } - memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique - temp[4] = (TXT_TYPE_CLI_DATA << 2); - - auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len); - if (reply) { - if (from.out_path_len < 0) { - sendFlood(reply, CLI_REPLY_DELAY_MILLIS); + if (packet->isRouteFlood()) { + // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the ACK + mesh::Packet* path = createPathReturn(from.id, secret, packet->path, packet->path_len, + PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4); + if (path) sendFlood(path, TXT_ACK_DELAY); } else { - sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS); + sendAckTo(from, ack_hash); + } + } + } else if (flags == TXT_TYPE_CLI_DATA) { + from.last_timestamp = sender_timestamp; + from.last_activity = getRTCClock()->getCurrentTime(); + + // len can be > original length, but 'text' will be padded with zeroes + data[len] = 0; // need to make a C string again, with null terminator + + uint8_t temp[166]; + char *command = (char *) &data[5]; + char *reply = (char *) &temp[5]; + handleCommand(sender_timestamp, command, reply); + + int text_len = strlen(reply); + if (text_len > 0) { + uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); + if (timestamp == sender_timestamp) { + // WORKAROUND: the two timestamps need to be different, in the CLI view + timestamp++; + } + memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique + temp[4] = (TXT_TYPE_CLI_DATA << 2); + + auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len); + if (reply) { + if (from.out_path_len < 0) { + sendFlood(reply, CLI_REPLY_DELAY_MILLIS); + } else { + sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS); + } } } + } else { + MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); } } else { MESH_DEBUG_PRINTLN("onPeerDataRecv: possible replay attack detected"); @@ -695,6 +729,15 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i } } +bool SensorMesh::handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len) { + MESH_DEBUG_PRINT("handleIncomingMsg: unhandled msg from "); + #ifdef MESH_DEBUG + mesh::Utils::printHex(Serial, from.id.pub_key, PUB_KEY_SIZE); + Serial.printf(": %s\n", data); + #endif + return false; +} + bool SensorMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) { int i = matching_peer_indexes[sender_idx]; if (i < 0 || i >= num_contacts) { diff --git a/examples/simple_sensor/SensorMesh.h b/examples/simple_sensor/SensorMesh.h index 0d87617b..62c1867e 100644 --- a/examples/simple_sensor/SensorMesh.h +++ b/examples/simple_sensor/SensorMesh.h @@ -140,7 +140,8 @@ protected: void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override; bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override; void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override; - + virtual bool handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len); + void sendAckTo(const ContactInfo& dest, uint32_t ack_hash); private: FILESYSTEM* _fs; unsigned long next_local_advert, next_flood_advert; diff --git a/library.json b/library.json new file mode 100644 index 00000000..982983a3 --- /dev/null +++ b/library.json @@ -0,0 +1,16 @@ +{ + "name": "MeshCore", + "version" : "1.7.4", + "dependencies": { + "SPI": "*", + "Wire": "*", + "jgromes/RadioLib": "^7.1.2", + "rweather/Crypto": "^0.4.0", + "adafruit/RTClib": "^2.1.3", + "melopero/Melopero RV3028": "^1.1.0", + "electroniccats/CayenneLPP": "1.4.0" + }, + "build": { + "extraScript": "build_as_lib.py" + } +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 02190102..e935d77e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -47,6 +47,7 @@ build_src_filter = +<*.cpp> + + + + ; ----------------- ESP32 --------------------- @@ -114,12 +115,14 @@ build_flags = -D ENV_INCLUDE_LPS22HB=1 -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 + -D ENV_INCLUDE_INA226=1 -D ENV_INCLUDE_INA260=1 -D ENV_INCLUDE_MLX90614=1 -D ENV_INCLUDE_VL53L0X=1 lib_deps = adafruit/Adafruit INA3221 Library @ ^1.0.1 adafruit/Adafruit INA219 @ ^1.2.3 + robtillaart/INA226 @ ^0.6.4 adafruit/Adafruit INA260 Library @ ^1.5.3 adafruit/Adafruit AHTX0 @ ^2.0.5 adafruit/Adafruit BME280 Library @ ^2.3.0 diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 2abb4f7c..443fcc30 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -165,6 +165,17 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } } else if (memcmp(command, "neighbors", 9) == 0) { _callbacks->formatNeighborsReply(reply); + } else if (memcmp(command, "neighbor.remove ", 16) == 0) { + const char* hex = &command[16]; + uint8_t pubkey[PUB_KEY_SIZE]; + int hex_len = min((int)strlen(hex), PUB_KEY_SIZE*2); + int pubkey_len = hex_len / 2; + if (mesh::Utils::fromHex(pubkey, pubkey_len, hex)) { + _callbacks->removeNeighbor(pubkey, pubkey_len); + strcpy(reply, "OK"); + } else { + strcpy(reply, "ERR: bad pubkey"); + } } else if (memcmp(command, "tempradio ", 10) == 0) { strcpy(tmp, &command[10]); const char *parts[5]; diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 92deb718..d1e49873 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -43,6 +43,9 @@ public: virtual void dumpLogFile() = 0; virtual void setTxPower(uint8_t power_dbm) = 0; virtual void formatNeighborsReply(char *reply) = 0; + virtual void removeNeighbor(const uint8_t* pubkey, int key_len) { + // no op by default + }; virtual mesh::LocalIdentity& getSelfId() = 0; virtual void clearStats() = 0; virtual void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) = 0; diff --git a/src/helpers/nrf52/T114Board.cpp b/src/helpers/nrf52/T114Board.cpp index 1f8c5854..78c21b33 100644 --- a/src/helpers/nrf52/T114Board.cpp +++ b/src/helpers/nrf52/T114Board.cpp @@ -26,6 +26,45 @@ void T114Board::begin() { pinMode(PIN_VBAT_READ, INPUT); + // Enable SoftDevice low-power mode + sd_power_mode_set(NRF_POWER_MODE_LOWPWR); + + // Enable DC/DC converter for better efficiency (REG1 stage) + NRF_POWER->DCDCEN = 1; + + // Power down unused communication peripherals + // UART1 - Not used on T114 + NRF_UARTE1->ENABLE = 0; + + // SPIM2/SPIS2 - Not used (SPI is on SPIM0) + NRF_SPIM2->ENABLE = 0; + NRF_SPIS2->ENABLE = 0; + + // TWI1 (I2C1) - Not used (I2C is on TWI0) + NRF_TWIM1->ENABLE = 0; + NRF_TWIS1->ENABLE = 0; + + // PWM modules - Not used for standard T114 functions + NRF_PWM1->ENABLE = 0; + NRF_PWM2->ENABLE = 0; + NRF_PWM3->ENABLE = 0; + + // PDM (Digital Microphone Interface) - Not used + NRF_PDM->ENABLE = 0; + + // I2S - Not used + NRF_I2S->ENABLE = 0; + + // QSPI - Not used (no external flash) + NRF_QSPI->ENABLE = 0; + + // Disable unused analog peripherals + // SAADC channels - only keep what's needed for battery monitoring + NRF_SAADC->ENABLE = 0; // Re-enable only when needed for measurements + + // COMP - Comparator not used + NRF_COMP->ENABLE = 0; + #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif diff --git a/src/helpers/nrf52/T114Board.h b/src/helpers/nrf52/T114Board.h index cd58134d..cf345937 100644 --- a/src/helpers/nrf52/T114Board.h +++ b/src/helpers/nrf52/T114Board.h @@ -40,6 +40,9 @@ public: uint16_t getBattMilliVolts() override { int adcvalue = 0; + + NRF_SAADC->ENABLE = 1; + analogReadResolution(12); analogReference(AR_INTERNAL_3_0); pinMode(PIN_BAT_CTL, OUTPUT); // battery adc can be read only ctrl pin 6 set to high @@ -49,6 +52,8 @@ public: adcvalue = analogRead(PIN_VBAT_READ); digitalWrite(6, 0); + NRF_SAADC->ENABLE = 0; + return (uint16_t)((float)adcvalue * MV_LSB * 4.9); } diff --git a/src/helpers/nrf52/TechoBoard.h b/src/helpers/nrf52/TechoBoard.h index c8ef7006..2c05c4ed 100644 --- a/src/helpers/nrf52/TechoBoard.h +++ b/src/helpers/nrf52/TechoBoard.h @@ -43,6 +43,25 @@ public: return "LilyGo T-Echo"; } + void powerOff() override { + #ifdef LED_RED + digitalWrite(LED_RED, LOW); + #endif + #ifdef LED_GREEN + digitalWrite(LED_GREEN, LOW); + #endif + #ifdef LED_BLUE + digitalWrite(LED_BLUE, LOW); + #endif + #ifdef DISP_BACKLIGHT + digitalWrite(DISP_BACKLIGHT, LOW); + #endif + #ifdef PIN_PWR_EN + digitalWrite(PIN_PWR_EN, LOW); + #endif + sd_power_system_off(); + } + void reboot() override { NVIC_SystemReset(); } diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 0f3289b8..f444b67b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -65,6 +65,14 @@ static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS); static Adafruit_INA260 INA260; #endif +#if ENV_INCLUDE_INA226 +#define TELEM_INA226_ADDRESS 0x44 +#define TELEM_INA226_SHUNT_VALUE 0.100 +#define TELEM_INA226_MAX_AMP 0.8 +#include +static INA226 INA226(TELEM_INA226_ADDRESS); +#endif + #if ENV_INCLUDE_MLX90614 #define TELEM_MLX90614_ADDRESS 0x5A // MLX90614 IR temperature sensor I2C address #include @@ -202,6 +210,17 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_INA226 + if (INA226.begin()) { + MESH_DEBUG_PRINTLN("Found INA226 at address: %02X", TELEM_INA226_ADDRESS); + INA226.setMaxCurrentShunt(TELEM_INA226_MAX_AMP, TELEM_INA226_SHUNT_VALUE); + INA226_initialized = true; + } else { + INA226_initialized = false; + MESH_DEBUG_PRINTLN("INA226 was not found at I2C address %02X", TELEM_INA226_ADDRESS); + } + #endif + #if ENV_INCLUDE_MLX90614 if (MLX90614.begin(TELEM_MLX90614_ADDRESS, TELEM_WIRE)) { MESH_DEBUG_PRINTLN("Found MLX90614 at address: %02X", TELEM_MLX90614_ADDRESS); @@ -323,6 +342,15 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } #endif + #if ENV_INCLUDE_INA226 + if (INA226_initialized) { + telemetry.addVoltage(next_available_channel, INA226.getBusVoltage()); + telemetry.addCurrent(next_available_channel, INA226.getCurrent_mA() / 1000.0); + telemetry.addPower(next_available_channel, INA226.getPower_mW() / 1000.0); + next_available_channel++; + } + #endif + #if ENV_INCLUDE_MLX90614 if (MLX90614_initialized) { telemetry.addTemperature(TELEM_CHANNEL_SELF, MLX90614.readObjectTempC()); diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index bb0fd2b9..3302d6f6 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -14,6 +14,7 @@ protected: bool INA3221_initialized = false; bool INA219_initialized = false; bool INA260_initialized = false; + bool INA226_initialized = false; bool SHTC3_initialized = false; bool LPS22HB_initialized = false; bool MLX90614_initialized = false; diff --git a/src/helpers/ui/ST7789Display.h b/src/helpers/ui/ST7789Display.h index 8056de81..0f06da4c 100644 --- a/src/helpers/ui/ST7789Display.h +++ b/src/helpers/ui/ST7789Display.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include "ST7789Spi.h" class ST7789Display : public DisplayDriver { ST7789Spi display; diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index b9193431..32673b1f 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -17,7 +17,7 @@ build_flags = -D PIN_VEXT_EN=36 -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 - -D SX126X_CURRENT_LIMIT=140 + -D SX126X_CURRENT_LIMIT=160 -D SX126X_RX_BOOSTED_GAIN=1 -D PIN_GPS_RX=47 -D PIN_GPS_TX=48 @@ -129,6 +129,7 @@ lib_deps = extends = Heltec_lora32_v3 build_flags = ${Heltec_lora32_v3.build_flags} + -I examples/companion_radio/ui-new -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display @@ -141,7 +142,8 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} + + + - +<../examples/companion_radio> + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini index b3ba33be..d52dcc0d 100644 --- a/variants/heltec_vision_master_e290/platformio.ini +++ b/variants/heltec_vision_master_e290/platformio.ini @@ -31,6 +31,7 @@ lib_deps = extends = Heltec_Vision_Master_E290_base build_flags = ${Heltec_Vision_Master_E290_base.build_flags} + -I examples/companion_radio/ui-new -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=E290Display @@ -40,7 +41,8 @@ build_flags = build_src_filter = ${Heltec_Vision_Master_E290_base.build_src_filter} + + - +<../examples/companion_radio> + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> lib_deps = ${Heltec_Vision_Master_E290_base.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/heltec_vision_master_e290/target.cpp b/variants/heltec_vision_master_e290/target.cpp index 2e897e49..92b02092 100644 --- a/variants/heltec_vision_master_e290/target.cpp +++ b/variants/heltec_vision_master_e290/target.cpp @@ -19,6 +19,7 @@ SensorManager sensors; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; +MomentaryButton user_btn(PIN_USER_BTN, 1000, true); #endif bool radio_init() { diff --git a/variants/heltec_vision_master_e290/target.h b/variants/heltec_vision_master_e290/target.h index 00b27e54..60770112 100644 --- a/variants/heltec_vision_master_e290/target.h +++ b/variants/heltec_vision_master_e290/target.h @@ -9,6 +9,7 @@ #include #ifdef DISPLAY_CLASS #include +#include #endif extern HeltecE290Board board; @@ -18,6 +19,7 @@ extern SensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; +extern MomentaryButton user_btn; #endif bool radio_init(); diff --git a/variants/ikoka_stick_nrf/ikoka_stick_nrf_board.h b/variants/ikoka_stick_nrf/ikoka_stick_nrf_board.h index 1bd8b31d..c66f4827 100644 --- a/variants/ikoka_stick_nrf/ikoka_stick_nrf_board.h +++ b/variants/ikoka_stick_nrf/ikoka_stick_nrf_board.h @@ -5,20 +5,6 @@ #ifdef XIAO_NRF52 -// redefine lora pins if using the S3 variant of SX1262 board -#ifdef SX1262_XIAO_S3_VARIANT - #undef P_LORA_DIO_1 - #undef P_LORA_BUSY - #undef P_LORA_RESET - #undef P_LORA_NSS - #undef SX126X_RXEN - #define P_LORA_DIO_1 D0 - #define P_LORA_BUSY D1 - #define P_LORA_RESET D2 - #define P_LORA_NSS D3 - #define SX126X_RXEN D4 -#endif - class ikoka_stick_nrf_board : public mesh::MainBoard { protected: uint8_t startup_reason; @@ -29,10 +15,10 @@ public: #if defined(P_LORA_TX_LED) void onBeforeTransmit() override { - digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on } void onAfterTransmit() override { - digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off } #endif diff --git a/variants/ikoka_stick_nrf/platformio.ini b/variants/ikoka_stick_nrf/platformio.ini index e78bc058..6e6ae101 100644 --- a/variants/ikoka_stick_nrf/platformio.ini +++ b/variants/ikoka_stick_nrf/platformio.ini @@ -19,11 +19,10 @@ lib_deps = 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 + adafruit/Adafruit BME280 Library @ ^2.3.0 adafruit/Adafruit SSD1306 @ ^2.5.13 - -[ikoka_stick_nrf] +[ikoka_stick_nrf_baseboard] extends = nrf52840_xiao ;board_build.ldscript = boards/nrf52840_s140_v7.ld build_flags = ${nrf52840_xiao.build_flags} @@ -34,7 +33,6 @@ build_flags = ${nrf52840_xiao.build_flags} -D DISPLAY_ROTATION=2 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper - -D LORA_TX_POWER=9 -D P_LORA_DIO_1=D1 -D P_LORA_RESET=D2 -D P_LORA_BUSY=D3 @@ -52,19 +50,59 @@ build_flags = ${nrf52840_xiao.build_flags} -D ENV_INCLUDE_BME280=1 -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 +debug_tool = jlink +upload_protocol = nrfutil + + +;;; abstracted hardware variants + +[ikoka_stick_nrf_e22_22dbm] +extends = ikoka_stick_nrf_baseboard +; No PA in this model, full 22dBm +build_flags = + ${ikoka_stick_nrf_baseboard.build_flags} + -D LORA_TX_POWER=22 build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + +<../variants/ikoka_stick_nrf> -debug_tool = jlink -upload_protocol = nrfutil -[env:ikoka_stick_nrf_companion_radio_ble] -extends = ikoka_stick_nrf +[ikoka_stick_nrf_e22_30dbm] +extends = ikoka_stick_nrf_baseboard +; limit txpower to 20dBm on E22-900M30S. Anything higher will +; cause distortion in the PA output. 20dBm in -> 30dBm out build_flags = - ${ikoka_stick_nrf.build_flags} + ${ikoka_stick_nrf_baseboard.build_flags} + -D LORA_TX_POWER=20 +build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + + + + + + +<../variants/ikoka_stick_nrf> + +[ikoka_stick_nrf_e22_33dbm] +extends = ikoka_stick_nrf_baseboard +; limit txpower to 9dBm on E22-900M33S to avoid hardware damage +; to the rf amplifier frontend. 9dBm in -> 33dBm out +build_flags = + ${ikoka_stick_nrf_baseboard.build_flags} + -D LORA_TX_POWER=9 +build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + + + + + + +<../variants/ikoka_stick_nrf> + +;;; abstracted firmware roles + +[ikoka_stick_nrf_companion_radio_ble] +extends = ikoka_stick_nrf_baseboard +build_flags = + ${ikoka_stick_nrf_baseboard.build_flags} -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 @@ -73,35 +111,35 @@ build_flags = ; -D BLE_DEBUG_LOGGING=1 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 -build_src_filter = ${ikoka_stick_nrf.build_src_filter} +build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter} + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = - ${ikoka_stick_nrf.lib_deps} + ${ikoka_stick_nrf_baseboard.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:ikoka_stick_nrf_companion_radio_usb] -extends = ikoka_stick_nrf +[ikoka_stick_nrf_companion_radio_usb] +extends = ikoka_stick_nrf_baseboard build_flags = - ${ikoka_stick_nrf.build_flags} + ${ikoka_stick_nrf_baseboard.build_flags} -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -I examples/companion_radio/ui-new ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 -build_src_filter = ${ikoka_stick_nrf.build_src_filter} +build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter} + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = - ${ikoka_stick_nrf.lib_deps} + ${ikoka_stick_nrf_baseboard.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:ikoka_stick_nrf_repeater] -extends = ikoka_stick_nrf +[ikoka_stick_nrf_repeater] +extends = ikoka_stick_nrf_baseboard build_flags = - ${ikoka_stick_nrf.build_flags} + ${ikoka_stick_nrf_baseboard.build_flags} -D ADVERT_NAME='"Ikoka Stick Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -109,19 +147,161 @@ build_flags = -D MAX_NEIGHBOURS=8 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 -build_src_filter = ${ikoka_stick_nrf.build_src_filter} +build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter} + +<../examples/simple_repeater/*.cpp> -[env:ikoka_stick_nrf_room_server] -extends = ikoka_stick_nrf +[ikoka_stick_nrf_room_server] +extends = ikoka_stick_nrf_baseboard build_flags = - ${ikoka_stick_nrf.build_flags} + ${ikoka_stick_nrf_baseboard.build_flags} -D ADVERT_NAME='"Ikoka Stick Room"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 -build_src_filter = ${ikoka_stick_nrf.build_src_filter} +build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter} +<../examples/simple_room_server/*.cpp> + +;;; hardware + firmware variants + +;;; 22dBm EBYTE E22-900M22 variants + +[env:ikoka_stick_nrf_22dbm_companion_radio_usb] +extends = + ikoka_stick_nrf_e22_22dbm + ikoka_stick_nrf_companion_radio_usb +build_flags = + ${ikoka_stick_nrf_companion_radio_usb.build_flags} + ${ikoka_stick_nrf_e22_22dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_usb.build_src_filter} + ${ikoka_stick_nrf_e22_22dbm.build_src_filter} + +[env:ikoka_stick_nrf_22dbm_companion_radio_ble] +extends = + ikoka_stick_nrf_e22_22dbm + ikoka_stick_nrf_companion_radio_ble +build_flags = + ${ikoka_stick_nrf_companion_radio_ble.build_flags} + ${ikoka_stick_nrf_e22_22dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_ble.build_src_filter} + ${ikoka_stick_nrf_e22_22dbm.build_src_filter} + +[env:ikoka_stick_nrf_22dbm_repeater] +extends = + ikoka_stick_nrf_e22_22dbm + ikoka_stick_nrf_repeater +build_flags = + ${ikoka_stick_nrf_repeater.build_flags} + ${ikoka_stick_nrf_e22_22dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_repeater.build_src_filter} + ${ikoka_stick_nrf_e22_22dbm.build_src_filter} + +[env:ikoka_stick_nrf_22dbm_room_server] +extends = + ikoka_stick_nrf_e22_22dbm + ikoka_stick_nrf_room_server +build_flags = + ${ikoka_stick_nrf_room_server.build_flags} + ${ikoka_stick_nrf_e22_22dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_room_server.build_src_filter} + ${ikoka_stick_nrf_e22_22dbm.build_src_filter} + + +;;; 30dBm EBYTE E22-900M30 variants + +[env:ikoka_stick_nrf_30dbm_companion_radio_usb] +extends = + ikoka_stick_nrf_e22_30dbm + ikoka_stick_nrf_companion_radio_usb +build_flags = + ${ikoka_stick_nrf_companion_radio_usb.build_flags} + ${ikoka_stick_nrf_e22_30dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_usb.build_src_filter} + ${ikoka_stick_nrf_e22_30dbm.build_src_filter} + +[env:ikoka_stick_nrf_30dbm_companion_radio_ble] +extends = + ikoka_stick_nrf_e22_30dbm + ikoka_stick_nrf_companion_radio_ble +build_flags = + ${ikoka_stick_nrf_companion_radio_ble.build_flags} + ${ikoka_stick_nrf_e22_30dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_ble.build_src_filter} + ${ikoka_stick_nrf_e22_30dbm.build_src_filter} + +[env:ikoka_stick_nrf_30dbm_repeater] +extends = + ikoka_stick_nrf_e22_30dbm + ikoka_stick_nrf_repeater +build_flags = + ${ikoka_stick_nrf_repeater.build_flags} + ${ikoka_stick_nrf_e22_30dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_repeater.build_src_filter} + ${ikoka_stick_nrf_e22_30dbm.build_src_filter} + +[env:ikoka_stick_nrf_30dbm_room_server] +extends = + ikoka_stick_nrf_e22_30dbm + ikoka_stick_nrf_room_server +build_flags = + ${ikoka_stick_nrf_room_server.build_flags} + ${ikoka_stick_nrf_e22_30dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_room_server.build_src_filter} + ${ikoka_stick_nrf_e22_30dbm.build_src_filter} + + +;;; 33dBm EBYTE E22-900M33 variants + +[env:ikoka_stick_nrf_33dbm_companion_radio_usb] +extends = + ikoka_stick_nrf_e22_33dbm + ikoka_stick_nrf_companion_radio_usb +build_flags = + ${ikoka_stick_nrf_companion_radio_usb.build_flags} + ${ikoka_stick_nrf_e22_33dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_usb.build_src_filter} + ${ikoka_stick_nrf_e22_33dbm.build_src_filter} + +[env:ikoka_stick_nrf_33dbm_companion_radio_ble] +extends = + ikoka_stick_nrf_e22_33dbm + ikoka_stick_nrf_companion_radio_ble +build_flags = + ${ikoka_stick_nrf_companion_radio_ble.build_flags} + ${ikoka_stick_nrf_e22_33dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_companion_radio_ble.build_src_filter} + ${ikoka_stick_nrf_e22_33dbm.build_src_filter} + +[env:ikoka_stick_nrf_33dbm_repeater] +extends = + ikoka_stick_nrf_e22_33dbm + ikoka_stick_nrf_repeater +build_flags = + ${ikoka_stick_nrf_repeater.build_flags} + ${ikoka_stick_nrf_e22_33dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_repeater.build_src_filter} + ${ikoka_stick_nrf_e22_33dbm.build_src_filter} + +[env:ikoka_stick_nrf_33dbm_room_server] +extends = + ikoka_stick_nrf_e22_33dbm + ikoka_stick_nrf_room_server +build_flags = + ${ikoka_stick_nrf_room_server.build_flags} + ${ikoka_stick_nrf_e22_33dbm.build_flags} +build_src_filter = + ${ikoka_stick_nrf_room_server.build_src_filter} + ${ikoka_stick_nrf_e22_33dbm.build_src_filter} diff --git a/variants/nano_g2_ultra/nano-g2.h b/variants/nano_g2_ultra/nano-g2.h index 884ed7f8..69df0c65 100644 --- a/variants/nano_g2_ultra/nano-g2.h +++ b/variants/nano_g2_ultra/nano-g2.h @@ -1,39 +1,40 @@ #pragma once -#include +#include "variant.h" + #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 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 +#define SX126X_POWER_EN 37 // buttons -#define PIN_BUTTON1 (32 + 6) -#define BUTTON_PIN PIN_BUTTON1 -#define PIN_USER_BTN BUTTON_PIN +#define PIN_BUTTON1 (32 + 6) +#define BUTTON_PIN PIN_BUTTON1 +#define PIN_USER_BTN BUTTON_PIN // GPS -#define GPS_EN PIN_GPS_STANDBY +#define GPS_EN PIN_GPS_STANDBY // built-ins -#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096 +#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 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) +#define PIN_VBAT_READ (0 + 2) +#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) -class NanoG2Ultra : public mesh::MainBoard -{ +class NanoG2Ultra : public mesh::MainBoard { protected: uint8_t startup_reason; @@ -42,18 +43,21 @@ public: uint16_t getBattMilliVolts() override; bool startOTAUpdate(const char *id, char reply[]) override; - uint8_t getStartupReason() const override - { - return startup_reason; - } + uint8_t getStartupReason() const override { return startup_reason; } - const char *getManufacturerName() const override - { - return "Nano G2 Ultra"; - } + const char *getManufacturerName() const override { return "Nano G2 Ultra"; } - void reboot() override - { - NVIC_SystemReset(); + void reboot() override { NVIC_SystemReset(); } + + void powerOff() override { + // put GPS chip to sleep + digitalWrite(PIN_GPS_STANDBY, LOW); +// unset buzzer to prevent notification circuit activating on hibernate +#undef PIN_BUZZER + + nrf_gpio_cfg_sense_input(digitalPinToInterrupt(PIN_USER_BTN), NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_SENSE_LOW); + + sd_power_system_off(); } }; diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index f0dea837..c9091878 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -22,6 +22,8 @@ build_flags = ${nrf52_base.build_flags} build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + + + lib_deps = ${nrf52_base.lib_deps} ${sensor_base.lib_deps} @@ -73,8 +75,6 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + - + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = @@ -97,9 +97,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + + - + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index 71d4e88c..618c9fc5 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -4,6 +4,10 @@ RAK4631Board board; +#ifndef PIN_USER_BTN + #define PIN_USER_BTN (-1) +#endif + #ifdef DISPLAY_CLASS DISPLAY_CLASS display; MomentaryButton user_btn(PIN_USER_BTN, 1000, true); diff --git a/variants/station_g2/platformio.ini b/variants/station_g2/platformio.ini index 5d9a6823..756ff5f3 100644 --- a/variants/station_g2/platformio.ini +++ b/variants/station_g2/platformio.ini @@ -22,6 +22,7 @@ build_flags = build_src_filter = ${esp32_base.build_src_filter} +<../variants/station_g2> + + + lib_deps = ${esp32_base.lib_deps} adafruit/Adafruit SH110X @ ~2.1.13 @@ -44,6 +45,25 @@ lib_deps = ${Station_G2.lib_deps} ${esp32_ota.lib_deps} +[env:Station_G2_logging_repeater] +extends = Station_G2 +build_flags = + ${Station_G2.build_flags} + -D ADVERT_NAME='"Station G2 Logging 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 SX126X_RX_BOOSTED_GAIN=1 +; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance +; -D MESH_DEBUG=1 +build_src_filter = ${Station_G2.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${Station_G2.lib_deps} + ${esp32_ota.lib_deps} + [env:Station_G2_room_server] extends = Station_G2 build_src_filter = ${Station_G2.build_src_filter} @@ -65,14 +85,16 @@ lib_deps = extends = Station_G2 build_flags = ${Station_G2.build_flags} + -I examples/companion_radio/ui-new -D DISPLAY_CLASS=SH1106Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${Station_G2.build_src_filter} - + - +<../examples/companion_radio> + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> lib_deps = ${Station_G2.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -81,6 +103,7 @@ lib_deps = extends = Station_G2 build_flags = ${Station_G2.build_flags} + -I examples/companion_radio/ui-new -D DISPLAY_CLASS=SH1106Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -91,8 +114,8 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Station_G2.build_src_filter} + - + - +<../examples/companion_radio> + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> lib_deps = ${Station_G2.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/station_g2/target.cpp b/variants/station_g2/target.cpp index 2b19f5f0..5423af68 100644 --- a/variants/station_g2/target.cpp +++ b/variants/station_g2/target.cpp @@ -18,10 +18,7 @@ SensorManager sensors; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; -#endif - -#ifndef LORA_CR - #define LORA_CR 5 + MomentaryButton user_btn(PIN_USER_BTN, 1000, true); #endif bool radio_init() { diff --git a/variants/station_g2/target.h b/variants/station_g2/target.h index 6d80f098..3f67af3a 100644 --- a/variants/station_g2/target.h +++ b/variants/station_g2/target.h @@ -10,6 +10,7 @@ #ifdef DISPLAY_CLASS #include + #include #endif extern StationG2Board board; @@ -19,6 +20,7 @@ extern SensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; + extern MomentaryButton user_btn; #endif bool radio_init(); diff --git a/variants/t1000-e/T1000eBoard.h b/variants/t1000-e/T1000eBoard.h index 24584757..f87d71e0 100644 --- a/variants/t1000-e/T1000eBoard.h +++ b/variants/t1000-e/T1000eBoard.h @@ -84,12 +84,21 @@ public: digitalWrite(PIN_3V3_EN, LOW); #endif + // set led on and wait for button release before poweroff + #ifdef LED_PIN + digitalWrite(LED_PIN, HIGH); + #endif + #ifdef BUTTON_PIN + while(digitalRead(BUTTON_PIN)); + #endif #ifdef LED_PIN digitalWrite(LED_PIN, LOW); #endif + #ifdef BUTTON_PIN nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); #endif + sd_power_system_off(); } diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index 2811e243..b1826139 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -34,6 +34,65 @@ build_src_filter = ${nrf52840_t1000e.build_src_filter} debug_tool = jlink upload_protocol = nrfutil +[env:t1000e_repeater] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D ADVERT_NAME='"t1000-e 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 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE +build_src_filter = ${t1000-e.build_src_filter} + +<../examples/simple_repeater> +lib_deps = ${t1000-e.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + +[env:t1000e_room_server] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D ADVERT_NAME='"t1000-e 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 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE +build_src_filter = ${t1000-e.build_src_filter} + +<../examples/simple_room_server> +lib_deps = ${t1000-e.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + +[env:t1000e_companion_radio_usb] +extends = t1000-e +build_flags = ${t1000-e.build_flags} + -I examples/companion_radio/ui-orig + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -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> + +<../examples/companion_radio/ui-orig/*.cpp> +lib_deps = ${t1000-e.lib_deps} + densaugeo/base64 @ ~1.4.0 + stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 + [env:t1000e_companion_radio_ble] extends = t1000-e build_flags = ${t1000-e.build_flags} @@ -58,4 +117,4 @@ build_src_filter = ${t1000-e.build_src_filter} 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 + end2endzone/NonBlockingRTTTL@^1.3.0 diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index 2e6ad3b0..76712178 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -21,6 +21,7 @@ build_flags = ${nrf52840_techo.build_flags} -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D P_LORA_TX_LED=LED_GREEN build_src_filter = ${nrf52840_techo.build_src_filter} + + diff --git a/variants/techo/variant.cpp b/variants/techo/variant.cpp index ad1fd560..0bad7829 100644 --- a/variants/techo/variant.cpp +++ b/variants/techo/variant.cpp @@ -24,6 +24,8 @@ void initVariant() { pinMode(LED_GREEN, OUTPUT); pinMode(LED_BLUE, OUTPUT); digitalWrite(LED_BLUE, HIGH); + digitalWrite(LED_GREEN, HIGH); + digitalWrite(LED_RED, HIGH); pinMode(PIN_TXCO, OUTPUT); digitalWrite(PIN_TXCO, HIGH); diff --git a/variants/techo/variant.h b/variants/techo/variant.h index 6aebf82f..da8d81d4 100644 --- a/variants/techo/variant.h +++ b/variants/techo/variant.h @@ -61,19 +61,15 @@ //////////////////////////////////////////////////////////////////////////////// // Builtin LEDs -#define LED_RED (34) -#define LED_GREEN (33) +#define LED_RED (13) #define LED_BLUE (14) +#define LED_GREEN (15) -#define PIN_STATUS_LED LED_GREEN -#define LED_BUILTIN LED_GREEN -#define PIN_LED LED_BUILTIN +//#define PIN_STATUS_LED LED_BLUE +#define LED_BUILTIN (-1) #define LED_PIN LED_BUILTIN #define LED_STATE_ON LOW -#define PIN_NEOPIXEL (14) -#define NEOPIXEL_NUM (2) - //////////////////////////////////////////////////////////////////////////////// // Builtin buttons diff --git a/variants/wio-tracker-l1/WioTrackerL1Board.h b/variants/wio-tracker-l1/WioTrackerL1Board.h index 03aef79c..f04b673f 100644 --- a/variants/wio-tracker-l1/WioTrackerL1Board.h +++ b/variants/wio-tracker-l1/WioTrackerL1Board.h @@ -38,5 +38,9 @@ public: NVIC_SystemReset(); } + void powerOff() override { + sd_power_system_off(); + } + bool startOTAUpdate(const char* id, char reply[]) override; }; diff --git a/variants/wio-tracker-l1/target.cpp b/variants/wio-tracker-l1/target.cpp index dc484546..349d73b4 100644 --- a/variants/wio-tracker-l1/target.cpp +++ b/variants/wio-tracker-l1/target.cpp @@ -17,6 +17,8 @@ WioTrackerL1SensorManager sensors = WioTrackerL1SensorManager(nmea); #ifdef DISPLAY_CLASS DISPLAY_CLASS display; MomentaryButton user_btn(PIN_USER_BTN, 1000, true); + MomentaryButton joystick_left(JOYSTICK_LEFT, 1000, true); + MomentaryButton joystick_right(JOYSTICK_RIGHT, 1000, true); #endif bool radio_init() { diff --git a/variants/wio-tracker-l1/target.h b/variants/wio-tracker-l1/target.h index d5fe4d70..6f5da7c6 100644 --- a/variants/wio-tracker-l1/target.h +++ b/variants/wio-tracker-l1/target.h @@ -40,6 +40,8 @@ extern WioTrackerL1SensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; extern MomentaryButton user_btn; + extern MomentaryButton joystick_left; + extern MomentaryButton joystick_right; #endif bool radio_init(); diff --git a/variants/xiao_c6/platformio.ini b/variants/xiao_c6/platformio.ini index fdf0f337..602bd6ae 100644 --- a/variants/xiao_c6/platformio.ini +++ b/variants/xiao_c6/platformio.ini @@ -121,3 +121,65 @@ build_src_filter = ${Meshimi.build_src_filter} lib_deps = ${Meshimi.lib_deps} densaugeo/base64 @ ~1.4.0 + +; WHY2025 badge variant +; requires soldering 2 pins between the esp32-C6 and the lora chip as shown here: https://wiki.why2025.org/Project:Meshtastic_on_the_WHY2025_badge +; also requires wiping the esp32-P4 +[WHY2025_badge] +extends = Xiao_C6 +board_build.partitions = default_8MB.csv +board_upload.flash_size = 8MB +board_upload.maximum_size = 8388608 +build_flags = + ${Xiao_C6.build_flags} + -D P_LORA_SCLK=6 + -D P_LORA_MISO=2 + -D P_LORA_MOSI=7 + -D P_LORA_NSS=4 + -D P_LORA_DIO_1=5 + -D P_LORA_BUSY=11 + -D P_LORA_RESET=1 + -D SX126X_TXEN=3 + -UPIN_BOARD_SDA + -UPIN_BOARD_SCL + -UP_LORA_TX_LED + -USX126X_RXEN + -USX126X_DIO2_AS_RF_SWITCH + -USX126X_DIO3_TCXO_VOLTAGE + +[env:WHY2025_badge_Repeater] +extends = WHY2025_badge +build_src_filter = ${WHY2025_badge.build_src_filter} + +<../examples/simple_repeater/main.cpp> +build_flags = + ${WHY2025_badge.build_flags} + -D ADVERT_NAME='"WHY2025 Badge 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 +lib_deps = + ${WHY2025_badge.lib_deps} +; ${esp32_ota.lib_deps} + +[env:WHY2025_badge_companion_radio_ble] +extends = WHY2025_badge +build_flags = ${WHY2025_badge.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D ENABLE_PRIVATE_KEY_IMPORT=1 + -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${WHY2025_badge.build_src_filter} + + + - + +<../examples/companion_radio/*.cpp> +lib_deps = + ${WHY2025_badge.lib_deps} + densaugeo/base64 @ ~1.4.0