mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-07-16 18:52:00 +00:00
Merge remote-tracking branch 'upstream/dev' into rak-ethernet
# Conflicts: # examples/companion_radio/main.cpp
This commit is contained in:
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"pioarduino.pioarduino-ide",
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A","0x4405"],
|
||||
["0x239A","0x0029"],
|
||||
["0x239A","0x002A"],
|
||||
["0x239A","0x0071"]
|
||||
],
|
||||
"usb_product": "HT-n5262",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "heltec_tower_v2",
|
||||
"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",
|
||||
"openocd_target": "nrf52.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Heltec Tower V2 Board",
|
||||
"upload": {
|
||||
"maximum_ram_size": 235520,
|
||||
"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://heltec.org/",
|
||||
"vendor": "Heltec"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-D BOARD_HAS_PSRAM",
|
||||
"-D ARDUINO_USB_CDC_ON_BOOT=0",
|
||||
"-D ARDUINO_USB_MODE=0",
|
||||
"-D ARDUINO_RUNNING_CORE=1",
|
||||
"-D ARDUINO_EVENT_RUNNING_CORE=0"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "qio_opi",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "ELECROW-ThinkNode-M7"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "ELECROW ThinkNode M7",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 524288,
|
||||
"maximum_size": 8388608,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.elecrow.com",
|
||||
"vendor": "ELECROW"
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi",
|
||||
"partitions": "default_16MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=0",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "qio_opi",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "ELECROW-ThinkNode-M9"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"bluetooth",
|
||||
"lora"
|
||||
],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": [
|
||||
"esp-builtin"
|
||||
],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "elecrow-thinknode-m9",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 524288,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.elecrow.com/thinknode-m1-meshtastic-lora-signal-transceiver-powered-by-nrf52840-with-154-screen-support-gps.html",
|
||||
"vendor": "ELECROW"
|
||||
}
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
{pkgs ? import <nixpkgs> {}}: let
|
||||
in
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.platformio
|
||||
pkgs.python3
|
||||
pkgs.gcc
|
||||
pkgs.gtest
|
||||
# optional: needed as a programmer i.e. for esp32
|
||||
pkgs.avrdude
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ Once you have a working app/project, you need to be able to demonstrate it exist
|
||||
| 0000 - 00FF | -reserved for internal use- | |
|
||||
| 0100 | MeshCore Open | zsylvester@monitormx.com — https://github.com/zjs81/meshcore-open |
|
||||
| 0110 - 011F | Ripple | ripple_biz@protonmail.com — https://buymeacoffee.com/ripplebiz |
|
||||
| 0120 | MCO Advanced | most.original.address@gmail.com — https://hdden.ru/MCOa/ |
|
||||
| 0130 - 013F | StreamSensor | william@housedillon.com - https://housedillon.com/blog/lora-e5-with-seeed-fusion |
|
||||
| FF00 - FFFF | -reserved for testing/dev- | |
|
||||
|
||||
(add rows, inside the range 0100 - FEFF for custom apps)
|
||||
|
||||
@@ -545,7 +545,7 @@ bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src
|
||||
uint32_t pos = 0, found_pos = 0;
|
||||
uint32_t min_timestamp = 0xFFFFFFFF;
|
||||
|
||||
// search for matching key OR evict by oldest timestmap
|
||||
// search for matching key OR evict by oldest timestamp
|
||||
BlobRec tmp;
|
||||
file.seek(0);
|
||||
while (file.read((uint8_t *) &tmp, sizeof(tmp)) == sizeof(tmp)) {
|
||||
|
||||
@@ -118,6 +118,10 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
board.begin();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DisplayDriver* disp = NULL;
|
||||
if (display.begin()) {
|
||||
@@ -264,6 +268,9 @@ void loop() {
|
||||
ui_task.loop();
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
|
||||
#ifdef ETHERNET_ENABLED
|
||||
serial_interface.loop();
|
||||
|
||||
@@ -697,8 +697,10 @@ void UITask::shutdown(bool restart){
|
||||
if (restart) {
|
||||
_board->reboot();
|
||||
} else {
|
||||
// still necessary until all boards are refactored to use poweroff
|
||||
_display->turnOff();
|
||||
radio_driver.powerOff();
|
||||
// Power off board including radio, display, GPS and components
|
||||
_board->powerOff();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +307,9 @@ void UITask::shutdown(bool restart){
|
||||
if (restart) {
|
||||
_board->reboot();
|
||||
} else {
|
||||
_display->turnOff();
|
||||
radio_driver.powerOff();
|
||||
// Power off board including radio, display, GPS and components
|
||||
_board->powerOff();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,6 +568,7 @@ void UITask::shutdown(bool restart){
|
||||
} else {
|
||||
_display->turnOff();
|
||||
radio_driver.powerOff();
|
||||
// Power off board including radio, display, GPS and components
|
||||
_board->powerOff();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,8 +549,7 @@ uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
|
||||
return getRNG()->nextInt(0, 5*t + 1);
|
||||
}
|
||||
|
||||
bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
||||
// just try to determine region for packet (apply later in allowPacketForward())
|
||||
mesh::DispatcherAction MyMesh::onRecvPacket(mesh::Packet* pkt) {
|
||||
if (pkt->getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
recv_pkt_region = region_map.findMatch(pkt, REGION_DENY_FLOOD);
|
||||
} else if (pkt->getRouteType() == ROUTE_TYPE_FLOOD) {
|
||||
@@ -562,8 +561,7 @@ bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
||||
} else {
|
||||
recv_pkt_region = NULL;
|
||||
}
|
||||
// do normal processing
|
||||
return false;
|
||||
return Mesh::onRecvPacket(pkt);
|
||||
}
|
||||
|
||||
void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const mesh::Identity &sender,
|
||||
@@ -867,6 +865,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
set_radio_at = revert_radio_at = 0;
|
||||
_logging = false;
|
||||
region_load_active = false;
|
||||
recv_pkt_region = NULL;
|
||||
|
||||
#if MAX_NEIGHBOURS
|
||||
memset(neighbours, 0, sizeof(neighbours));
|
||||
@@ -1062,11 +1061,9 @@ void MyMesh::setTxPower(int8_t power_dbm) {
|
||||
radio_driver.setTxPower(power_dbm);
|
||||
}
|
||||
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||
void MyMesh::setRxBoostedGain(bool enable) {
|
||||
radio_driver.setRxBoostedGainMode(enable);
|
||||
bool MyMesh::setRxBoostedGain(bool enable) {
|
||||
return radio_driver.setRxBoostedGainMode(enable);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MyMesh::formatNeighborsReply(char *reply) {
|
||||
char *dp = reply;
|
||||
|
||||
@@ -166,7 +166,7 @@ protected:
|
||||
}
|
||||
#endif
|
||||
|
||||
bool filterRecvFloodPacket(mesh::Packet* pkt) override;
|
||||
mesh::DispatcherAction onRecvPacket(mesh::Packet* pkt) override;
|
||||
|
||||
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
|
||||
int searchPeersByHash(const uint8_t* hash) override;
|
||||
@@ -252,7 +252,6 @@ public:
|
||||
// To check if there is pending work
|
||||
bool hasPendingWork() const;
|
||||
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||
void setRxBoostedGain(bool enable) override;
|
||||
#endif
|
||||
bool setRxBoostedGain(bool enable) override;
|
||||
|
||||
};
|
||||
|
||||
@@ -41,6 +41,10 @@ void setup() {
|
||||
|
||||
board.begin();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
#if defined(MESH_DEBUG) && defined(NRF52_PLATFORM)
|
||||
// give some extra time for serial to settle so
|
||||
// boot debug messages can be seen on terminal
|
||||
@@ -188,7 +192,13 @@ void loop() {
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.feed();
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM)
|
||||
board.sleep(0); // nrf ignores seconds param, sleeps whenever possible
|
||||
#else
|
||||
|
||||
@@ -290,8 +290,7 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
||||
// just try to determine region for packet (apply later in allowPacketForward())
|
||||
mesh::DispatcherAction MyMesh::onRecvPacket(mesh::Packet* pkt) {
|
||||
if (pkt->getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
recv_pkt_region = region_map.findMatch(pkt, REGION_DENY_FLOOD);
|
||||
} else if (pkt->getRouteType() == ROUTE_TYPE_FLOOD) {
|
||||
@@ -303,8 +302,7 @@ bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
||||
} else {
|
||||
recv_pkt_region = NULL;
|
||||
}
|
||||
// do normal processing
|
||||
return false;
|
||||
return Mesh::onRecvPacket(pkt);
|
||||
}
|
||||
|
||||
void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const mesh::Identity &sender,
|
||||
@@ -627,6 +625,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
_logging = false;
|
||||
region_load_active = false;
|
||||
set_radio_at = revert_radio_at = 0;
|
||||
recv_pkt_region = NULL;
|
||||
|
||||
// defaults
|
||||
memset(&_prefs, 0, sizeof(_prefs));
|
||||
|
||||
@@ -154,7 +154,7 @@ protected:
|
||||
return _prefs.multi_acks;
|
||||
}
|
||||
|
||||
bool filterRecvFloodPacket(mesh::Packet* pkt) override;
|
||||
mesh::DispatcherAction onRecvPacket(mesh::Packet* pkt) override;
|
||||
|
||||
bool allowPacketForward(const mesh::Packet* packet) override;
|
||||
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
|
||||
|
||||
@@ -32,6 +32,10 @@ void setup() {
|
||||
|
||||
board.begin();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (display.begin()) {
|
||||
display.startFrame();
|
||||
@@ -150,4 +154,7 @@ void loop() {
|
||||
ui_task.loop();
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -560,6 +560,10 @@ void setup() {
|
||||
|
||||
board.begin();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
@@ -591,4 +595,7 @@ void setup() {
|
||||
void loop() {
|
||||
the_mesh.loop();
|
||||
rtc_clock.tick();
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ void setup() {
|
||||
|
||||
board.begin();
|
||||
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (display.begin()) {
|
||||
display.startFrame();
|
||||
@@ -147,4 +151,7 @@ void loop() {
|
||||
ui_task.loop();
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
#ifdef HAS_EXTERNAL_WATCHDOG
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
+4
-1
@@ -19,7 +19,8 @@ monitor_speed = 115200
|
||||
lib_deps =
|
||||
SPI
|
||||
Wire
|
||||
jgromes/RadioLib @ ^7.6.0
|
||||
;jgromes/RadioLib @ ^7.7.1
|
||||
https://github.com/jgromes/RadioLib.git#6d8934836678d8894e3d556550475b37dce3e2b6
|
||||
rweather/Crypto @ ^0.4.0
|
||||
adafruit/RTClib @ ^2.1.3
|
||||
melopero/Melopero RV3028 @ ^1.1.0
|
||||
@@ -157,6 +158,7 @@ lib_deps =
|
||||
|
||||
[env:native]
|
||||
platform = native
|
||||
test_framework = googletest
|
||||
build_flags = -std=c++17
|
||||
-I src
|
||||
-I test/mocks
|
||||
@@ -164,5 +166,6 @@ test_build_src = yes
|
||||
build_src_filter =
|
||||
-<*>
|
||||
+<../src/Utils.cpp>
|
||||
+<../src/Packet.cpp>
|
||||
lib_deps =
|
||||
google/googletest @ 1.17.0
|
||||
|
||||
+27
-16
@@ -55,7 +55,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
uint16_t offset = (uint16_t)pkt->path_len << path_sz;
|
||||
if (offset >= len) { // TRACE has reached end of given path
|
||||
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
||||
} else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
|
||||
} else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
// append SNR (Not hash!)
|
||||
pkt->path[pkt->path_len++] = (int8_t) (pkt->getSNR()*4);
|
||||
|
||||
@@ -89,14 +90,16 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
|
||||
return forwardMultipartDirect(pkt);
|
||||
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
|
||||
if (!_tables->hasSeen(pkt)) { // don't retransmit!
|
||||
if (!_tables->wasSeen(pkt)) { // don't retransmit!
|
||||
_tables->markSeen(pkt);
|
||||
removeSelfFromPath(pkt);
|
||||
routeDirectRecvAcks(pkt, 0);
|
||||
}
|
||||
return ACTION_RELEASE;
|
||||
}
|
||||
|
||||
if (!_tables->hasSeen(pkt)) {
|
||||
if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
removeSelfFromPath(pkt);
|
||||
|
||||
uint32_t d = getDirectRetransmitDelay(pkt);
|
||||
@@ -117,7 +120,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
memcpy(&ack_crc, &pkt->payload[i], 4); i += 4;
|
||||
if (i > pkt->payload_len) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete ACK packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
} else if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
onAckRecv(pkt, ack_crc);
|
||||
action = routeRecvPacket(pkt);
|
||||
}
|
||||
@@ -134,7 +138,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||
if (i + CIPHER_MAC_SIZE >= pkt->payload_len) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
} else if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
|
||||
// For flood mode, the path may not be the 'best' in terms of hops.
|
||||
// FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?)
|
||||
@@ -197,7 +202,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||
if (i + 2 >= pkt->payload_len) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
} else if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
if (self_id.isHashMatch(&dest_hash)) {
|
||||
Identity sender(sender_pub_key);
|
||||
|
||||
@@ -224,7 +230,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
|
||||
if (i + 2 >= pkt->payload_len) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
} else if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
// scan channels DB, for all matching hashes of 'channel_hash' (max 4 matches supported ATM)
|
||||
GroupChannel channels[4];
|
||||
int num = searchChannelsByHash(&channel_hash, channels, 4);
|
||||
@@ -255,7 +262,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete advertisement packet", getLogDateTime());
|
||||
} else if (self_id.matches(id.pub_key)) {
|
||||
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): receiving SELF advert packet", getLogDateTime());
|
||||
} else if (!_tables->hasSeen(pkt)) {
|
||||
} else if (!_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
uint8_t* app_data = &pkt->payload[i];
|
||||
int app_data_len = pkt->payload_len - i;
|
||||
if (app_data_len > MAX_ADVERT_DATA_SIZE) { app_data_len = MAX_ADVERT_DATA_SIZE; }
|
||||
@@ -282,7 +290,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
break;
|
||||
}
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM: {
|
||||
if (pkt->isRouteDirect() && !_tables->hasSeen(pkt)) {
|
||||
if (pkt->isRouteDirect() && !_tables->wasSeen(pkt)) {
|
||||
_tables->markSeen(pkt);
|
||||
onRawDataRecv(pkt);
|
||||
//action = routeRecvPacket(pkt); don't flood route these (yet)
|
||||
}
|
||||
@@ -300,7 +309,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||
tmp.payload_len = pkt->payload_len - 1;
|
||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||
|
||||
if (!_tables->hasSeen(&tmp)) {
|
||||
if (!_tables->wasSeen(&tmp)) {
|
||||
_tables->markSeen(&tmp);
|
||||
uint32_t ack_crc;
|
||||
memcpy(&ack_crc, tmp.payload, 4);
|
||||
|
||||
@@ -357,7 +367,8 @@ DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
|
||||
tmp.payload_len = pkt->payload_len - 1;
|
||||
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
|
||||
|
||||
if (!_tables->hasSeen(&tmp)) { // don't retransmit!
|
||||
if (!_tables->wasSeen(&tmp)) { // don't retransmit!
|
||||
_tables->markSeen(&tmp);
|
||||
removeSelfFromPath(&tmp);
|
||||
routeDirectRecvAcks(&tmp, ((uint32_t)remaining + 1) * 300); // expect multipart ACKs 300ms apart (x2)
|
||||
}
|
||||
@@ -637,7 +648,7 @@ void Mesh::sendFlood(Packet* packet, uint32_t delay_millis, uint8_t path_hash_si
|
||||
packet->header |= ROUTE_TYPE_FLOOD;
|
||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
uint8_t pri;
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||
@@ -666,7 +677,7 @@ void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_m
|
||||
packet->transport_codes[1] = transport_codes[1];
|
||||
packet->setPathHashSizeAndCount(path_hash_size, 0);
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
uint8_t pri;
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
|
||||
@@ -699,7 +710,7 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
|
||||
pri = 0;
|
||||
}
|
||||
}
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
sendPacket(packet, pri, delay_millis);
|
||||
}
|
||||
|
||||
@@ -709,7 +720,7 @@ void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) {
|
||||
|
||||
packet->path_len = 0; // path_len of zero means Zero Hop
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
sendPacket(packet, 0, delay_millis);
|
||||
}
|
||||
@@ -722,7 +733,7 @@ void Mesh::sendZeroHop(Packet* packet, uint16_t* transport_codes, uint32_t delay
|
||||
|
||||
packet->path_len = 0; // path_len of zero means Zero Hop
|
||||
|
||||
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
_tables->markSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
|
||||
|
||||
sendPacket(packet, 0, delay_millis);
|
||||
}
|
||||
|
||||
+4
-3
@@ -15,8 +15,9 @@ public:
|
||||
*/
|
||||
class MeshTables {
|
||||
public:
|
||||
virtual bool hasSeen(const Packet* packet) = 0;
|
||||
virtual void clear(const Packet* packet) = 0; // remove this packet hash from table
|
||||
virtual bool wasSeen(const Packet* packet) = 0;
|
||||
virtual void markSeen(const Packet* packet) = 0;
|
||||
virtual void clear(const Packet* packet) = 0; // remove this packet hash from table
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -100,7 +101,7 @@ protected:
|
||||
* \param auth_code a code to authenticate the packet
|
||||
* \param flags zero for now
|
||||
* \param path_snrs single byte SNR*4 for each hop in the path
|
||||
* \param path_hashes hashes if each repeater in the path
|
||||
* \param path_hashes hashes of each repeater in the path
|
||||
* \param path_len length of the path_snrs[] and path_hashes[] arrays
|
||||
*/
|
||||
virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { }
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ namespace mesh {
|
||||
#define PAYLOAD_TYPE_GRP_DATA 0x06 // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: data_type(uint16), data_len, blob)
|
||||
#define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
|
||||
#define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
|
||||
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNI for each hop
|
||||
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNR for each hop
|
||||
#define PAYLOAD_TYPE_MULTIPART 0x0A // packet is one of a set of packets
|
||||
#define PAYLOAD_TYPE_CONTROL 0x0B // a control/discovery packet
|
||||
//...
|
||||
|
||||
@@ -42,6 +42,7 @@ void AutoDiscoverRTCClock::begin(TwoWire& wire) {
|
||||
}
|
||||
|
||||
if (i2c_probe(wire, PCF8563_ADDRESS)) {
|
||||
MESH_DEBUG_PRINTLN("PCF8563: Found");
|
||||
rtc_8563_success = rtc_8563.begin(&wire);
|
||||
}
|
||||
|
||||
|
||||
@@ -571,13 +571,15 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0;
|
||||
savePrefs();
|
||||
strcpy(reply, _prefs->disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON");
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110)
|
||||
} else if (memcmp(config, "radio.rxgain ", 13) == 0) {
|
||||
_prefs->rx_boosted_gain = memcmp(&config[13], "on", 2) == 0;
|
||||
strcpy(reply, "OK");
|
||||
bool enabled = memcmp(&config[13], "on", 2) == 0;
|
||||
_prefs->rx_boosted_gain = enabled;
|
||||
savePrefs();
|
||||
_callbacks->setRxBoostedGain(_prefs->rx_boosted_gain);
|
||||
#endif
|
||||
if (_callbacks->setRxBoostedGain(enabled)) {
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
}
|
||||
} else if (memcmp(config, "radio.fem.rxgain ", 17) == 0) {
|
||||
if (!_board->canControlLoRaFemLna()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
@@ -835,10 +837,8 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lat));
|
||||
} else if (memcmp(config, "lon", 3) == 0) {
|
||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->node_lon));
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110)
|
||||
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off");
|
||||
#endif
|
||||
} else if (memcmp(config, "radio.fem.rxgain", 16) == 0) {
|
||||
if (!_board->canControlLoRaFemLna()) {
|
||||
strcpy(reply, "Error: unsupported");
|
||||
@@ -953,13 +953,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
strcpy(reply, "ERROR: Power management not supported");
|
||||
#endif
|
||||
} else if (memcmp(config, "pwrmgt.bootreason", 17) == 0) {
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
sprintf(reply, "> Reset: %s; Shutdown: %s",
|
||||
_board->getResetReasonString(_board->getResetReason()),
|
||||
_board->getShutdownReasonString(_board->getShutdownReason()));
|
||||
#else
|
||||
strcpy(reply, "ERROR: Power management not supported");
|
||||
#endif
|
||||
} else if (memcmp(config, "pwrmgt.bootmv", 13) == 0) {
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
sprintf(reply, "> %u mV", _board->getBootVoltage());
|
||||
|
||||
@@ -111,8 +111,8 @@ public:
|
||||
// no op by default
|
||||
};
|
||||
|
||||
virtual void setRxBoostedGain(bool enable) {
|
||||
// no op by default
|
||||
virtual bool setRxBoostedGain(bool enable) {
|
||||
return false; // CommonCLI reports unsupported if not overridden by wrapper
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "ESP32Board.h"
|
||||
#include <target.h>
|
||||
|
||||
#if defined(ADMIN_PASSWORD) && !defined(DISABLE_WIFI_OTA) // Repeater or Room Server only
|
||||
#include <WiFi.h>
|
||||
@@ -44,4 +45,45 @@ bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void ESP32Board::powerOff() {
|
||||
enterDeepSleep(0); // Do not wakeup
|
||||
}
|
||||
|
||||
void ESP32Board::enterDeepSleep(uint32_t secs) {
|
||||
// Power off the display if any
|
||||
#ifdef DISPLAY_CLASS
|
||||
display.turnOff();
|
||||
#endif
|
||||
|
||||
// Power off LoRa
|
||||
radio_driver.powerOff();
|
||||
|
||||
// Keep LoRa inactive during deepsleep
|
||||
digitalWrite(P_LORA_NSS, HIGH);
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
#else
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
#endif
|
||||
|
||||
// Power off GPS if any
|
||||
if (sensors.getLocationProvider() != NULL) {
|
||||
sensors.getLocationProvider()->stop();
|
||||
}
|
||||
|
||||
// Flush serial buffers
|
||||
Serial.flush();
|
||||
delay(100);
|
||||
|
||||
// Clear stale wakeup sources to avoid ghost wakeup
|
||||
// This is required when Power Management and automatic lightsleep are enabled
|
||||
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000ULL);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into deepsleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <Wire.h>
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_system.h"
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class ESP32Board : public mesh::MainBoard {
|
||||
protected:
|
||||
@@ -62,6 +63,9 @@ public:
|
||||
return raw / 4;
|
||||
}
|
||||
|
||||
virtual void powerOff() override;
|
||||
void enterDeepSleep(uint32_t secs);
|
||||
|
||||
uint32_t getIRQGpio() override {
|
||||
return P_LORA_DIO_1; // default for SX1262
|
||||
}
|
||||
@@ -155,6 +159,42 @@ public:
|
||||
void setInhibitSleep(bool inhibit) {
|
||||
inhibit_sleep = inhibit;
|
||||
}
|
||||
|
||||
uint32_t getResetReason() const override {
|
||||
return esp_reset_reason();
|
||||
}
|
||||
|
||||
// https://docs.espressif.com/projects/esp-idf/en/v4.4.7/esp32/api-reference/system/system.html
|
||||
const char* getResetReasonString(uint32_t reason) {
|
||||
switch (reason) {
|
||||
case ESP_RST_UNKNOWN:
|
||||
return "Unknown or first boot";
|
||||
case ESP_RST_POWERON:
|
||||
return "Power-on reset";
|
||||
case ESP_RST_EXT:
|
||||
return "External reset";
|
||||
case ESP_RST_SW:
|
||||
return "Software reset";
|
||||
case ESP_RST_PANIC:
|
||||
return "Panic / exception reset";
|
||||
case ESP_RST_INT_WDT:
|
||||
return "Interrupt watchdog reset";
|
||||
case ESP_RST_TASK_WDT:
|
||||
return "Task watchdog reset";
|
||||
case ESP_RST_WDT:
|
||||
return "Other watchdog reset";
|
||||
case ESP_RST_DEEPSLEEP:
|
||||
return "Wake from deep sleep";
|
||||
case ESP_RST_BROWNOUT:
|
||||
return "Brownout (low voltage)";
|
||||
case ESP_RST_SDIO:
|
||||
return "SDIO reset";
|
||||
default:
|
||||
static char buf[40];
|
||||
snprintf(buf, sizeof(buf), "Unknown reset reason (%d)", reason);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ESP32RTCClock : public mesh::RTCClock {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
class ExternalWatchdogManager {
|
||||
protected:
|
||||
unsigned long last_feed_watchdog;
|
||||
public:
|
||||
ExternalWatchdogManager() { last_feed_watchdog = 0; }
|
||||
virtual bool begin() { return false; }
|
||||
virtual void loop() { }
|
||||
virtual unsigned long getIntervalMs() const { return 0; }
|
||||
virtual void feed() { }
|
||||
};
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
#include "ESP32Board.h"
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class MeshadventurerBoard : public ESP32Board {
|
||||
|
||||
public:
|
||||
@@ -35,34 +33,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are held on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
// TODO: re-enable this when there is a definite wake-up source pin:
|
||||
// enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
analogReadResolution(12);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#if defined(NRF52_PLATFORM)
|
||||
#include "NRF52Board.h"
|
||||
#include <target.h>
|
||||
|
||||
#include <bluefruit.h>
|
||||
#include <nrf_soc.h>
|
||||
@@ -297,6 +298,37 @@ float NRF52Board::getMCUTemperature() {
|
||||
return temp * 0.25f; // Convert to *C
|
||||
}
|
||||
|
||||
void NRF52Board::powerOff() {
|
||||
// Power off the display if any
|
||||
#ifdef DISPLAY_CLASS
|
||||
display.turnOff();
|
||||
#endif
|
||||
|
||||
// Power off LoRa
|
||||
radio_driver.powerOff();
|
||||
|
||||
// Keep LoRa inactive during deepsleep
|
||||
digitalWrite(P_LORA_NSS, HIGH);
|
||||
|
||||
// Power off GPS if any
|
||||
if(sensors.getLocationProvider() != NULL) {
|
||||
sensors.getLocationProvider()->stop();
|
||||
}
|
||||
|
||||
// Flush serial buffers
|
||||
Serial.flush();
|
||||
delay(100);
|
||||
|
||||
// Enter SYSTEMOFF
|
||||
uint8_t sd_enabled = 0;
|
||||
sd_softdevice_is_enabled(&sd_enabled);
|
||||
if (sd_enabled) { // SoftDevice is enabled
|
||||
sd_power_system_off();
|
||||
} else { // SoftDevice is not enable
|
||||
NRF_POWER->SYSTEMOFF = POWER_SYSTEMOFF_SYSTEMOFF_Enter;
|
||||
}
|
||||
}
|
||||
|
||||
bool NRF52Board::getBootloaderVersion(char* out, size_t max_len) {
|
||||
static const char BOOTLOADER_MARKER[] = "UF2 Bootloader ";
|
||||
const uint8_t* flash = (const uint8_t*)0x000FB000; // earliest known info.txt location is 0xFB90B, latest is 0xFCC4B
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
virtual uint8_t getStartupReason() const override { return startup_reason; }
|
||||
virtual float getMCUTemperature() override;
|
||||
virtual void reboot() override { NVIC_SystemReset(); }
|
||||
virtual void powerOff() override;
|
||||
virtual bool getBootloaderVersion(char* version, size_t max_len) override;
|
||||
virtual bool startOTAUpdate(const char *id, char reply[]) override;
|
||||
virtual void sleep(uint32_t secs) override;
|
||||
|
||||
@@ -93,13 +93,15 @@ bool RegionMap::load(FILESYSTEM* _fs, const char* path) {
|
||||
while (num_regions < MAX_REGION_ENTRIES) {
|
||||
auto r = ®ions[num_regions];
|
||||
|
||||
success = file.read((uint8_t *) &r->id, sizeof(r->id)) == sizeof(r->id);
|
||||
int n = file.read((uint8_t *) &r->id, sizeof(r->id));
|
||||
if (n == 0) break; // clean EOF
|
||||
success = (n == sizeof(r->id));
|
||||
success = success && file.read((uint8_t *) &r->parent, sizeof(r->parent)) == sizeof(r->parent);
|
||||
success = success && file.read((uint8_t *) r->name, sizeof(r->name)) == sizeof(r->name);
|
||||
success = success && file.read((uint8_t *) &r->flags, sizeof(r->flags)) == sizeof(r->flags);
|
||||
success = success && file.read(pad, sizeof(pad)) == sizeof(pad);
|
||||
|
||||
if (!success) break; // EOF
|
||||
if (!success) break; // partial read or corruption
|
||||
|
||||
if (r->id >= next_id) { // make sure next_id is valid
|
||||
next_id = r->id + 1;
|
||||
@@ -108,7 +110,7 @@ bool RegionMap::load(FILESYSTEM* _fs, const char* path) {
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
return false; // failed
|
||||
@@ -139,7 +141,7 @@ bool RegionMap::save(FILESYSTEM* _fs, const char* path) {
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
return success;
|
||||
}
|
||||
return false; // failed
|
||||
}
|
||||
|
||||
@@ -31,27 +31,31 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasSeen(const mesh::Packet* packet) override {
|
||||
bool wasSeen(const mesh::Packet* packet) override {
|
||||
uint8_t hash[MAX_HASH_SIZE];
|
||||
packet->calculatePacketHash(hash);
|
||||
|
||||
const uint8_t* sp = _hashes;
|
||||
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
|
||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) {
|
||||
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) {
|
||||
if (packet->isRouteDirect()) {
|
||||
_direct_dups++; // keep some stats
|
||||
_direct_dups++;
|
||||
} else {
|
||||
_flood_dups++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&_hashes[_next_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
|
||||
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES; // cyclic table
|
||||
return false;
|
||||
}
|
||||
|
||||
void markSeen(const mesh::Packet* packet) override {
|
||||
uint8_t hash[MAX_HASH_SIZE];
|
||||
packet->calculatePacketHash(hash);
|
||||
memcpy(&_hashes[_next_idx * MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
|
||||
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES;
|
||||
}
|
||||
|
||||
void clear(const mesh::Packet* packet) override {
|
||||
uint8_t hash[MAX_HASH_SIZE];
|
||||
packet->calculatePacketHash(hash);
|
||||
|
||||
@@ -39,7 +39,8 @@ void BridgeBase::handleReceivedPacket(mesh::Packet *packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_seen_packets.hasSeen(packet)) {
|
||||
if (!_seen_packets.wasSeen(packet)) {
|
||||
_seen_packets.markSeen(packet);
|
||||
// bridge_delay provides a buffer to prevent immediate processing conflicts in the mesh network.
|
||||
_mgr->queueInbound(packet, millis() + _prefs->bridge_delay);
|
||||
} else {
|
||||
|
||||
@@ -110,7 +110,7 @@ protected:
|
||||
* @brief Common packet handling for received packets
|
||||
*
|
||||
* Implements the standard pattern used by all bridges:
|
||||
* - Check if packet was seen before using _seen_packets.hasSeen()
|
||||
* - Check if packet was seen before using _seen_packets.wasSeen()
|
||||
* - Queue packet for mesh processing if not seen before
|
||||
* - Free packet if already seen to prevent duplicates
|
||||
*
|
||||
|
||||
@@ -32,7 +32,7 @@ void ESPNowBridge::begin() {
|
||||
// Initialize WiFi in station mode
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Set wifi channel
|
||||
// Set Wi-Fi channel
|
||||
if (esp_wifi_set_channel(_prefs->bridge_channel, WIFI_SECOND_CHAN_NONE) != ESP_OK) {
|
||||
BRIDGE_DEBUG_PRINTLN("Error setting WIFI channel to %d\n", _prefs->bridge_channel);
|
||||
return;
|
||||
@@ -167,7 +167,8 @@ void ESPNowBridge::sendPacket(mesh::Packet *packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_seen_packets.hasSeen(packet)) {
|
||||
if (!_seen_packets.wasSeen(packet)) {
|
||||
_seen_packets.markSeen(packet);
|
||||
// Create a temporary buffer just for size calculation and reuse for actual writing
|
||||
uint8_t sizingBuffer[MAX_PAYLOAD_SIZE];
|
||||
uint16_t meshPacketLen = packet->writeTo(sizingBuffer);
|
||||
|
||||
@@ -115,7 +115,8 @@ void RS232Bridge::sendPacket(mesh::Packet *packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_seen_packets.hasSeen(packet)) {
|
||||
if (!_seen_packets.wasSeen(packet)) {
|
||||
_seen_packets.markSeen(packet);
|
||||
|
||||
uint8_t buffer[MAX_SERIAL_PACKET_SIZE];
|
||||
uint16_t len = packet->writeTo(buffer + 4);
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
* These two functions do nothing for ESP-NOW, but are needed for the
|
||||
* Radio interface.
|
||||
*/
|
||||
virtual void setRxBoostedGainMode(bool) { }
|
||||
virtual bool setRxBoostedGainMode(bool) { }
|
||||
virtual bool getRxBoostedGainMode() const { return false; }
|
||||
|
||||
uint32_t intID();
|
||||
|
||||
@@ -66,11 +66,11 @@ class CustomLLCC68 : public LLCC68 {
|
||||
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
|
||||
#ifndef SX1262X_RXEN
|
||||
#define SX1262X_RXEN RADIOLIB_NC
|
||||
#ifndef SX126X_RXEN
|
||||
#define SX126X_RXEN RADIOLIB_NC
|
||||
#endif
|
||||
#ifndef SX1262X_TXEN
|
||||
#define SX1262X_TXEN RADIOLIB_NC
|
||||
#ifndef SX126X_TXEN
|
||||
#define SX126X_TXEN RADIOLIB_NC
|
||||
#endif
|
||||
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
|
||||
#endif
|
||||
|
||||
@@ -33,8 +33,8 @@ public:
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
|
||||
void setRxBoostedGainMode(bool en) override {
|
||||
((CustomLLCC68 *)_radio)->setRxBoostedGainMode(en);
|
||||
bool setRxBoostedGainMode(bool en) override {
|
||||
return ((CustomLLCC68 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomLLCC68 *)_radio)->getRxBoostedGainMode();
|
||||
|
||||
@@ -26,6 +26,11 @@ public:
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint32_t getEstAirtimeFor(int len_bytes) override {
|
||||
auto airtime = RadioLibWrapper::getEstAirtimeFor(len_bytes);
|
||||
return airtime < 200 ? 200 : airtime; // at least 200 millis
|
||||
}
|
||||
|
||||
void onSendFinished() override {
|
||||
RadioLibWrapper::onSendFinished();
|
||||
_radio->setPreambleLength(preambleLengthForSF(getSpreadingFactor())); // overcomes weird issues with small and big pkts
|
||||
@@ -36,8 +41,8 @@ public:
|
||||
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomLR1110 *)_radio)->getSpreadingFactor(); }
|
||||
|
||||
void setRxBoostedGainMode(bool en) override {
|
||||
((CustomLR1110 *)_radio)->setRxBoostedGainMode(en);
|
||||
bool setRxBoostedGainMode(bool en) override {
|
||||
return ((CustomLR1110 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomLR1110 *)_radio)->getRxBoostedGainMode();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <RadioLib.h>
|
||||
#include "MeshCore.h"
|
||||
|
||||
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
|
||||
#define SX126X_IRQ_PREAMBLE_DETECTED 0x04
|
||||
@@ -27,6 +28,14 @@ class CustomSX1262 : public SX1262 {
|
||||
uint8_t cr = 5;
|
||||
#endif
|
||||
|
||||
#ifdef SX126X_USE_REGULATOR_LDO
|
||||
constexpr bool useRegulatorLDO = SX126X_USE_REGULATOR_LDO;
|
||||
#else
|
||||
constexpr bool useRegulatorLDO = false;
|
||||
#endif
|
||||
|
||||
MESH_DEBUG_PRINTLN("SX1262 regulator requested: %s", useRegulatorLDO ? "LDO" : "DC-DC");
|
||||
|
||||
#if defined(P_LORA_SCLK)
|
||||
#ifdef NRF52_PLATFORM
|
||||
if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); }
|
||||
@@ -42,11 +51,12 @@ class CustomSX1262 : public SX1262 {
|
||||
if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
|
||||
#endif
|
||||
#endif
|
||||
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
|
||||
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo, useRegulatorLDO);
|
||||
// if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
|
||||
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
|
||||
MESH_DEBUG_PRINTLN("SX1262 init failed with error %d, retrying with TCXO at 0.0V", status);
|
||||
tcxo = 0.0f;
|
||||
status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
|
||||
status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo, useRegulatorLDO);
|
||||
}
|
||||
if (status != RADIOLIB_ERR_NONE) {
|
||||
Serial.print("ERROR: radio init failed: ");
|
||||
@@ -83,6 +93,8 @@ class CustomSX1262 : public SX1262 {
|
||||
writeRegister(0x8B5, &r_data, 1);
|
||||
#endif
|
||||
|
||||
MESH_DEBUG_PRINTLN("SX1262 status=0x%02X device_errors=0x%04X", getStatus(), getDeviceErrors());
|
||||
|
||||
return true; // success
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ public:
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
|
||||
void setRxBoostedGainMode(bool en) override {
|
||||
((CustomSX1262 *)_radio)->setRxBoostedGainMode(en);
|
||||
bool setRxBoostedGainMode(bool en) override {
|
||||
return ((CustomSX1262 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomSX1262 *)_radio)->getRxBoostedGainMode();
|
||||
|
||||
@@ -66,11 +66,11 @@ class CustomSX1268 : public SX1268 {
|
||||
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
|
||||
#ifndef SX1262X_RXEN
|
||||
#define SX1262X_RXEN RADIOLIB_NC
|
||||
#ifndef SX126X_RXEN
|
||||
#define SX126X_RXEN RADIOLIB_NC
|
||||
#endif
|
||||
#ifndef SX1262X_TXEN
|
||||
#define SX1262X_TXEN RADIOLIB_NC
|
||||
#ifndef SX126X_TXEN
|
||||
#define SX126X_TXEN RADIOLIB_NC
|
||||
#endif
|
||||
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
|
||||
#endif
|
||||
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
|
||||
void doResetAGC() override { sx126xResetAGC((SX126x *)_radio); }
|
||||
|
||||
void setRxBoostedGainMode(bool en) override {
|
||||
((CustomSX1268 *)_radio)->setRxBoostedGainMode(en);
|
||||
bool setRxBoostedGainMode(bool en) override {
|
||||
return ((CustomSX1268 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
bool getRxBoostedGainMode() const override {
|
||||
return ((CustomSX1268 *)_radio)->getRxBoostedGainMode();
|
||||
|
||||
@@ -50,14 +50,14 @@ class CustomSX1276 : public SX1276 {
|
||||
setCurrentLimit(SX127X_CURRENT_LIMIT);
|
||||
#endif
|
||||
|
||||
#if defined(SX176X_RXEN) || defined(SX176X_TXEN)
|
||||
#ifndef SX176X_RXEN
|
||||
#define SX176X_RXEN RADIOLIB_NC
|
||||
#if defined(SX127X_RXEN) || defined(SX127X_TXEN)
|
||||
#ifndef SX127X_RXEN
|
||||
#define SX127X_RXEN RADIOLIB_NC
|
||||
#endif
|
||||
#ifndef SX176X_TXEN
|
||||
#define SX176X_TXEN RADIOLIB_NC
|
||||
#ifndef SX127X_TXEN
|
||||
#define SX127X_TXEN RADIOLIB_NC
|
||||
#endif
|
||||
setRfSwitchPins(SX176X_RXEN, SX176X_TXEN);
|
||||
setRfSwitchPins(SX127X_RXEN, SX127X_TXEN);
|
||||
#endif
|
||||
|
||||
setCRC(1);
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
float packetScore(float snr, int packet_len) override { return packetScoreInt(snr, 10, packet_len); } // assume sf=10
|
||||
|
||||
virtual void setRxBoostedGainMode(bool) { }
|
||||
virtual bool setRxBoostedGainMode(bool) { return false; }
|
||||
virtual bool getRxBoostedGainMode() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -896,11 +896,11 @@ void EnvironmentSensorManager::stop_gps() {
|
||||
void EnvironmentSensorManager::loop() {
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
static long next_gps_update = 0;
|
||||
static unsigned long next_gps_update = 0;
|
||||
if (gps_active) {
|
||||
_location->loop();
|
||||
}
|
||||
if (millis() > next_gps_update) {
|
||||
if ((long)(millis() - next_gps_update) > 0) {
|
||||
|
||||
if(gps_active){
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
case LPP_GPS:
|
||||
_pos += 9; break;
|
||||
case LPP_POLYLINE:
|
||||
_pos += 8; break; // TODO: this is MINIMIUM
|
||||
_pos += 8; break; // TODO: this is MINIMUM
|
||||
case LPP_GYROMETER:
|
||||
case LPP_ACCELEROMETER:
|
||||
_pos += 6; break;
|
||||
|
||||
@@ -42,14 +42,14 @@ class MicroNMEALocationProvider : public LocationProvider {
|
||||
int8_t _claims = 0;
|
||||
int _pin_reset;
|
||||
int _pin_en;
|
||||
long next_check = 0;
|
||||
unsigned long next_check = 0;
|
||||
long time_valid = 0;
|
||||
unsigned long _last_time_sync = 0;
|
||||
static const unsigned long TIME_SYNC_INTERVAL = 1800000; // Re-sync every 30 minutes
|
||||
|
||||
public :
|
||||
MicroNMEALocationProvider(Stream& ser, mesh::RTCClock* clock = NULL, int pin_reset = GPS_RESET, int pin_en = GPS_EN,RefCountedDigitalPin* peripher_power=NULL) :
|
||||
_gps_serial(&ser), nmea(_nmeaBuffer, sizeof(_nmeaBuffer)), _pin_reset(pin_reset), _pin_en(pin_en), _clock(clock), _peripher_power(peripher_power) {
|
||||
nmea(_nmeaBuffer, sizeof(_nmeaBuffer)), _clock(clock), _gps_serial(&ser), _peripher_power(peripher_power), _pin_reset(pin_reset), _pin_en(pin_en) {
|
||||
if (_pin_reset != -1) {
|
||||
pinMode(_pin_reset, OUTPUT);
|
||||
digitalWrite(_pin_reset, GPS_RESET_FORCE);
|
||||
@@ -62,9 +62,7 @@ public :
|
||||
|
||||
void claim() {
|
||||
_claims++;
|
||||
if (_claims > 0) {
|
||||
if (_peripher_power) _peripher_power->claim();
|
||||
}
|
||||
if (_peripher_power) _peripher_power->claim();
|
||||
}
|
||||
|
||||
void release() {
|
||||
@@ -143,7 +141,7 @@ public :
|
||||
|
||||
if (!isValid()) time_valid = 0;
|
||||
|
||||
if (millis() > next_check) {
|
||||
if ((long)(millis() - next_check) > 0) {
|
||||
next_check = millis() + 1000;
|
||||
// Re-enable time sync periodically when GPS has valid fix
|
||||
if (!_time_sync_needed && _clock != NULL && (millis() - _last_time_sync) > TIME_SYNC_INTERVAL) {
|
||||
|
||||
@@ -37,7 +37,7 @@ static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, l
|
||||
}
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// been erased. Negative error codes are propagated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, l
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
||||
}
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
static int _internal_flash_sync(const struct lfs_config *c)
|
||||
{
|
||||
return LFS_ERR_OK; // don't need sync
|
||||
|
||||
@@ -1166,7 +1166,7 @@ char DefaultFontTableLookup(const uint8_t ch) {
|
||||
uint8_t last = LASTCHAR; // get last char
|
||||
LASTCHAR = ch;
|
||||
|
||||
switch (last) { // conversion depnding on first UTF8-character
|
||||
switch (last) { // conversion depending on first UTF8-character
|
||||
case 0xC2: return (uint8_t) ch;
|
||||
case 0xC3: return (uint8_t) (ch | 0xC0);
|
||||
case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol
|
||||
|
||||
@@ -1,12 +1,405 @@
|
||||
#include "ST7735Display.h"
|
||||
|
||||
#ifndef DISPLAY_ROTATION
|
||||
#define DISPLAY_ROTATION 2
|
||||
//#include <Fonts/GFXFF/FreeSans9pt7b.h>
|
||||
|
||||
// Optimised ST7735 display driver, derived from Adafruit_ST7735 library.
|
||||
|
||||
#define ST_CMD_DELAY 0x80 // special signifier for command lists
|
||||
|
||||
#define ST77XX_NOP 0x00
|
||||
#define ST77XX_SWRESET 0x01
|
||||
#define ST77XX_RDDID 0x04
|
||||
#define ST77XX_RDDST 0x09
|
||||
|
||||
#define ST77XX_SLPIN 0x10
|
||||
#define ST77XX_SLPOUT 0x11
|
||||
#define ST77XX_PTLON 0x12
|
||||
#define ST77XX_NORON 0x13
|
||||
|
||||
#define ST77XX_INVOFF 0x20
|
||||
#define ST77XX_INVON 0x21
|
||||
#define ST77XX_DISPOFF 0x28
|
||||
#define ST77XX_DISPON 0x29
|
||||
#define ST77XX_CASET 0x2A
|
||||
#define ST77XX_RASET 0x2B
|
||||
#define ST77XX_RAMWR 0x2C
|
||||
#define ST77XX_RAMRD 0x2E
|
||||
|
||||
#define ST77XX_PTLAR 0x30
|
||||
#define ST77XX_TEOFF 0x34
|
||||
#define ST77XX_TEON 0x35
|
||||
#define ST77XX_MADCTL 0x36
|
||||
#define ST77XX_COLMOD 0x3A
|
||||
|
||||
#define ST77XX_MADCTL_MY 0x80
|
||||
#define ST77XX_MADCTL_MX 0x40
|
||||
#define ST77XX_MADCTL_MV 0x20
|
||||
#define ST77XX_MADCTL_ML 0x10
|
||||
#define ST77XX_MADCTL_RGB 0x00
|
||||
|
||||
#define ST77XX_RDID1 0xDA
|
||||
#define ST77XX_RDID2 0xDB
|
||||
#define ST77XX_RDID3 0xDC
|
||||
#define ST77XX_RDID4 0xDD
|
||||
|
||||
// Some ready-made 16-bit ('565') color settings:
|
||||
#define ST77XX_BLACK 0x0000
|
||||
#define ST77XX_WHITE 0xFFFF
|
||||
#define ST77XX_RED 0xF800
|
||||
#define ST77XX_GREEN 0x07E0
|
||||
#define ST77XX_BLUE 0x001F
|
||||
#define ST77XX_CYAN 0x07FF
|
||||
#define ST77XX_MAGENTA 0xF81F
|
||||
#define ST77XX_YELLOW 0xFFE0
|
||||
#define ST77XX_ORANGE 0xFC00
|
||||
|
||||
|
||||
// some flags for initR() :(
|
||||
#define INITR_GREENTAB 0x00
|
||||
#define INITR_REDTAB 0x01
|
||||
#define INITR_BLACKTAB 0x02
|
||||
#define INITR_18GREENTAB INITR_GREENTAB
|
||||
#define INITR_18REDTAB INITR_REDTAB
|
||||
#define INITR_18BLACKTAB INITR_BLACKTAB
|
||||
#define INITR_144GREENTAB 0x01
|
||||
#define INITR_MINI160x80 0x04
|
||||
#define INITR_HALLOWING 0x05
|
||||
#define INITR_MINI160x80_PLUGIN 0x06
|
||||
|
||||
// Some register settings
|
||||
#define ST7735_MADCTL_BGR 0x08
|
||||
#define ST7735_MADCTL_MH 0x04
|
||||
|
||||
#define ST7735_FRMCTR1 0xB1
|
||||
#define ST7735_FRMCTR2 0xB2
|
||||
#define ST7735_FRMCTR3 0xB3
|
||||
#define ST7735_INVCTR 0xB4
|
||||
#define ST7735_DISSET5 0xB6
|
||||
|
||||
#define ST7735_PWCTR1 0xC0
|
||||
#define ST7735_PWCTR2 0xC1
|
||||
#define ST7735_PWCTR3 0xC2
|
||||
#define ST7735_PWCTR4 0xC3
|
||||
#define ST7735_PWCTR5 0xC4
|
||||
#define ST7735_VMCTR1 0xC5
|
||||
|
||||
#define ST7735_PWCTR6 0xFC
|
||||
|
||||
#define ST7735_GMCTRP1 0xE0
|
||||
#define ST7735_GMCTRN1 0xE1
|
||||
|
||||
// Some ready-made 16-bit ('565') color settings:
|
||||
#define ST7735_BLACK ST77XX_BLACK
|
||||
#define ST7735_WHITE ST77XX_WHITE
|
||||
#define ST7735_RED ST77XX_RED
|
||||
#define ST7735_GREEN ST77XX_GREEN
|
||||
#define ST7735_BLUE ST77XX_BLUE
|
||||
#define ST7735_CYAN ST77XX_CYAN
|
||||
#define ST7735_MAGENTA ST77XX_MAGENTA
|
||||
#define ST7735_YELLOW ST77XX_YELLOW
|
||||
#define ST7735_ORANGE ST77XX_ORANGE
|
||||
|
||||
static TFT_eSPI lcd = TFT_eSPI(160, 80);
|
||||
static uint32_t curr_color;
|
||||
|
||||
#if defined(HELTEC_LORA_V3) || defined(HELTEC_TRACKER_V2)
|
||||
static SPIClass tft_spi(HSPI);
|
||||
#define _spi (&tft_spi)
|
||||
#else
|
||||
#define _spi (&SPI1)
|
||||
#endif
|
||||
|
||||
SPISettings _spiSettings = SPISettings(40000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t PROGMEM
|
||||
Bcmd[] = { // Init commands for 7735B screens
|
||||
18, // 18 commands in list:
|
||||
ST77XX_SWRESET, ST_CMD_DELAY, // 1: Software reset, no args, w/delay
|
||||
50, // 50 ms delay
|
||||
ST77XX_SLPOUT, ST_CMD_DELAY, // 2: Out of sleep mode, no args, w/delay
|
||||
255, // 255 = max (500 ms) delay
|
||||
ST77XX_COLMOD, 1+ST_CMD_DELAY, // 3: Set color mode, 1 arg + delay:
|
||||
0x05, // 16-bit color
|
||||
10, // 10 ms delay
|
||||
ST7735_FRMCTR1, 3+ST_CMD_DELAY, // 4: Frame rate control, 3 args + delay:
|
||||
0x00, // fastest refresh
|
||||
0x06, // 6 lines front porch
|
||||
0x03, // 3 lines back porch
|
||||
10, // 10 ms delay
|
||||
ST77XX_MADCTL, 1, // 5: Mem access ctl (directions), 1 arg:
|
||||
0x08, // Row/col addr, bottom-top refresh
|
||||
ST7735_DISSET5, 2, // 6: Display settings #5, 2 args:
|
||||
0x15, // 1 clk cycle nonoverlap, 2 cycle gate
|
||||
// rise, 3 cycle osc equalize
|
||||
0x02, // Fix on VTL
|
||||
ST7735_INVCTR, 1, // 7: Display inversion control, 1 arg:
|
||||
0x0, // Line inversion
|
||||
ST7735_PWCTR1, 2+ST_CMD_DELAY, // 8: Power control, 2 args + delay:
|
||||
0x02, // GVDD = 4.7V
|
||||
0x70, // 1.0uA
|
||||
10, // 10 ms delay
|
||||
ST7735_PWCTR2, 1, // 9: Power control, 1 arg, no delay:
|
||||
0x05, // VGH = 14.7V, VGL = -7.35V
|
||||
ST7735_PWCTR3, 2, // 10: Power control, 2 args, no delay:
|
||||
0x01, // Opamp current small
|
||||
0x02, // Boost frequency
|
||||
ST7735_VMCTR1, 2+ST_CMD_DELAY, // 11: Power control, 2 args + delay:
|
||||
0x3C, // VCOMH = 4V
|
||||
0x38, // VCOML = -1.1V
|
||||
10, // 10 ms delay
|
||||
ST7735_PWCTR6, 2, // 12: Power control, 2 args, no delay:
|
||||
0x11, 0x15,
|
||||
ST7735_GMCTRP1,16, // 13: Gamma Adjustments (pos. polarity), 16 args + delay:
|
||||
0x09, 0x16, 0x09, 0x20, // (Not entirely necessary, but provides
|
||||
0x21, 0x1B, 0x13, 0x19, // accurate colors)
|
||||
0x17, 0x15, 0x1E, 0x2B,
|
||||
0x04, 0x05, 0x02, 0x0E,
|
||||
ST7735_GMCTRN1,16+ST_CMD_DELAY, // 14: Gamma Adjustments (neg. polarity), 16 args + delay:
|
||||
0x0B, 0x14, 0x08, 0x1E, // (Not entirely necessary, but provides
|
||||
0x22, 0x1D, 0x18, 0x1E, // accurate colors)
|
||||
0x1B, 0x1A, 0x24, 0x2B,
|
||||
0x06, 0x06, 0x02, 0x0F,
|
||||
10, // 10 ms delay
|
||||
ST77XX_CASET, 4, // 15: Column addr set, 4 args, no delay:
|
||||
0x00, 0x02, // XSTART = 2
|
||||
0x00, 0x81, // XEND = 129
|
||||
ST77XX_RASET, 4, // 16: Row addr set, 4 args, no delay:
|
||||
0x00, 0x02, // XSTART = 1
|
||||
0x00, 0x81, // XEND = 160
|
||||
ST77XX_NORON, ST_CMD_DELAY, // 17: Normal display on, no args, w/delay
|
||||
10, // 10 ms delay
|
||||
ST77XX_DISPON, ST_CMD_DELAY, // 18: Main screen turn on, no args, delay
|
||||
255 }, // 255 = max (500 ms) delay
|
||||
|
||||
Rcmd1[] = { // 7735R init, part 1 (red or green tab)
|
||||
14, // 14 commands in list:
|
||||
/*ST77XX_SWRESET, ST_CMD_DELAY, // 1: Software reset, 0 args, w/delay
|
||||
150, */ // 150 ms delay
|
||||
ST77XX_SLPOUT, ST_CMD_DELAY, // 2: Out of sleep mode, 0 args, w/delay
|
||||
120, // 120 ms delay
|
||||
ST7735_FRMCTR1, 3, // 3: Framerate ctrl - normal mode, 3 arg:
|
||||
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR2, 3, // 4: Framerate ctrl - idle mode, 3 args:
|
||||
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR3, 6, // 5: Framerate - partial mode, 6 args:
|
||||
0x01, 0x2C, 0x2D, // Dot inversion mode
|
||||
0x01, 0x2C, 0x2D, // Line inversion mode
|
||||
ST7735_INVCTR, 1, // 6: Display inversion ctrl, 1 arg:
|
||||
0x07, // No inversion
|
||||
ST7735_PWCTR1, 3, // 7: Power control, 3 args, no delay:
|
||||
0xA2,
|
||||
0x02, // -4.6V
|
||||
0x84, // AUTO mode
|
||||
ST7735_PWCTR2, 1, // 8: Power control, 1 arg, no delay:
|
||||
0xC5, // VGH25=2.4C VGSEL=-10 VGH=3 * AVDD
|
||||
ST7735_PWCTR3, 2, // 9: Power control, 2 args, no delay:
|
||||
0x0A, // Opamp current small
|
||||
0x00, // Boost frequency
|
||||
ST7735_PWCTR4, 2, // 10: Power control, 2 args, no delay:
|
||||
0x8A, // BCLK/2,
|
||||
0x2A, // opamp current small & medium low
|
||||
ST7735_PWCTR5, 2, // 11: Power control, 2 args, no delay:
|
||||
0x8A, 0xEE,
|
||||
ST7735_VMCTR1, 1, // 12: Power control, 1 arg, no delay:
|
||||
0x0E,
|
||||
ST77XX_INVOFF, 0, // 13: Don't invert display, no args
|
||||
ST77XX_MADCTL, 1, // 14: Mem access ctl (directions), 1 arg:
|
||||
0xC8, // row/col addr, bottom-top refresh
|
||||
ST77XX_COLMOD, 1, // 15: set color mode, 1 arg, no delay:
|
||||
0x05 }, // 16-bit color
|
||||
|
||||
Rcmd2green[] = { // 7735R init, part 2 (green tab only)
|
||||
2, // 2 commands in list:
|
||||
ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x02, // XSTART = 0
|
||||
0x00, 0x7F+0x02, // XEND = 127
|
||||
ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x01, // XSTART = 0
|
||||
0x00, 0x9F+0x01 }, // XEND = 159
|
||||
|
||||
Rcmd2red[] = { // 7735R init, part 2 (red tab only)
|
||||
2, // 2 commands in list:
|
||||
ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x7F, // XEND = 127
|
||||
ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x9F }, // XEND = 159
|
||||
|
||||
Rcmd2green144[] = { // 7735R init, part 2 (green 1.44 tab)
|
||||
2, // 2 commands in list:
|
||||
ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x7F, // XEND = 127
|
||||
ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x7F }, // XEND = 127
|
||||
|
||||
Rcmd2green160x80[] = { // 7735R init, part 2 (mini 160x80)
|
||||
2, // 2 commands in list:
|
||||
ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x4F, // XEND = 79
|
||||
ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x9F }, // XEND = 159
|
||||
|
||||
Rcmd2green160x80plugin[] = { // 7735R init, part 2 (mini 160x80 with plugin FPC)
|
||||
3, // 3 commands in list:
|
||||
ST77XX_INVON, 0, // 1: Display is inverted
|
||||
ST77XX_CASET, 4, // 2: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x4F, // XEND = 79
|
||||
ST77XX_RASET, 4, // 3: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x9F }, // XEND = 159
|
||||
|
||||
Rcmd3[] = { // 7735R init, part 3 (red or green tab)
|
||||
2, // 2 commands in list:
|
||||
ST7735_GMCTRP1, 16 , // 1: Gamma Adjustments (pos. polarity), 16 args + delay:
|
||||
0x02, 0x1c, 0x07, 0x12, // (Not entirely necessary, but provides
|
||||
0x37, 0x32, 0x29, 0x2d, // accurate colors)
|
||||
0x29, 0x25, 0x2B, 0x39,
|
||||
0x00, 0x01, 0x03, 0x10,
|
||||
ST7735_GMCTRN1, 16 , // 2: Gamma Adjustments (neg. polarity), 16 args + delay:
|
||||
0x03, 0x1d, 0x07, 0x06, // (Not entirely necessary, but provides
|
||||
0x2E, 0x2C, 0x29, 0x2D, // accurate colors)
|
||||
0x2E, 0x2E, 0x37, 0x3F,
|
||||
0x00, 0x00, 0x02, 0x10 }; // 100 ms delay
|
||||
|
||||
static int16_t _xstart = 0; ///< Internal framebuffer X offset
|
||||
static int16_t _ystart = 0; ///< Internal framebuffer Y offset
|
||||
static uint8_t _colstart = 0; ///< Some displays need this changed to offset
|
||||
static uint8_t _rowstart = 0; ///< Some displays need this changed to offset
|
||||
static uint8_t rotation = 0;
|
||||
static int16_t _width = 0; ///< Display width as modified by current rotation
|
||||
static int16_t _height = 0; ///< Display height as modified by current rotation
|
||||
|
||||
static void set_CS(uint8_t level) {
|
||||
//if (_cs != (uint8_t) -1) {
|
||||
digitalWrite(PIN_TFT_CS, level);
|
||||
//}
|
||||
}
|
||||
static void sendCommand(uint8_t com) {
|
||||
set_CS(HIGH);
|
||||
digitalWrite(PIN_TFT_DC, LOW);
|
||||
set_CS(LOW);
|
||||
_spi->beginTransaction(_spiSettings);
|
||||
_spi->transfer(com);
|
||||
_spi->endTransaction();
|
||||
set_CS(HIGH);
|
||||
digitalWrite(PIN_TFT_DC, HIGH);
|
||||
}
|
||||
|
||||
static void WriteData(uint8_t data) {
|
||||
digitalWrite(PIN_TFT_CS, LOW);
|
||||
_spi->beginTransaction(_spiSettings);
|
||||
_spi->transfer(data);
|
||||
_spi->endTransaction();
|
||||
digitalWrite(PIN_TFT_CS, HIGH);
|
||||
}
|
||||
static void SPI_WRITE32(uint32_t l) {
|
||||
_spi->transfer(l >> 24);
|
||||
_spi->transfer(l >> 16);
|
||||
_spi->transfer(l >> 8);
|
||||
_spi->transfer(l);
|
||||
}
|
||||
static void writeCommand(uint8_t cmd) {
|
||||
digitalWrite(PIN_TFT_DC, LOW);
|
||||
_spi->transfer(cmd);
|
||||
digitalWrite(PIN_TFT_DC, HIGH);
|
||||
}
|
||||
|
||||
static void displayInit(const uint8_t *addr) {
|
||||
uint8_t numCommands, cmd, numArgs;
|
||||
uint16_t ms;
|
||||
|
||||
numCommands = pgm_read_byte(addr++); // Number of commands to follow
|
||||
while (numCommands--) { // For each command...
|
||||
cmd = pgm_read_byte(addr++); // Read command
|
||||
numArgs = pgm_read_byte(addr++); // Number of args to follow
|
||||
ms = numArgs & ST_CMD_DELAY; // If hibit set, delay follows args
|
||||
numArgs &= ~ST_CMD_DELAY; // Mask out delay bit
|
||||
sendCommand(cmd);
|
||||
for (int k = 0; k < numArgs; k++) {
|
||||
WriteData(addr[k]);
|
||||
}
|
||||
addr += numArgs;
|
||||
|
||||
if (ms) {
|
||||
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
|
||||
if (ms == 255)
|
||||
ms = 500; // If 255, delay for 500 ms
|
||||
delay(ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setRotation(uint8_t m) {
|
||||
uint8_t madctl = 0;
|
||||
|
||||
rotation = m & 3; // can't be higher than 3
|
||||
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST7735_MADCTL_BGR;
|
||||
|
||||
_height = 160;
|
||||
_width = 80;
|
||||
_xstart = _colstart;
|
||||
_ystart = _rowstart;
|
||||
break;
|
||||
case 1:
|
||||
madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR;
|
||||
|
||||
_width = 160;
|
||||
_height = 80;
|
||||
_ystart = _colstart;
|
||||
_xstart = _rowstart;
|
||||
break;
|
||||
case 2:
|
||||
madctl = ST7735_MADCTL_BGR;
|
||||
|
||||
_height = 160;
|
||||
_width = 80;
|
||||
_xstart = _colstart;
|
||||
_ystart = _rowstart;
|
||||
break;
|
||||
case 3:
|
||||
madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR;
|
||||
|
||||
_width = 160;
|
||||
_height = 80;
|
||||
_ystart = _colstart;
|
||||
_xstart = _rowstart;
|
||||
break;
|
||||
}
|
||||
|
||||
sendCommand(ST77XX_MADCTL);
|
||||
WriteData(madctl);
|
||||
}
|
||||
|
||||
static void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||||
x += _xstart;
|
||||
y += _ystart;
|
||||
uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
|
||||
uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);
|
||||
|
||||
writeCommand(ST77XX_CASET); // Column addr set
|
||||
SPI_WRITE32(xa);
|
||||
|
||||
writeCommand(ST77XX_RASET); // Row addr set
|
||||
SPI_WRITE32(ya);
|
||||
|
||||
writeCommand(ST77XX_RAMWR); // write to RAM
|
||||
}
|
||||
|
||||
#define SCALE_X 1.25f // 160 / 128
|
||||
#define SCALE_Y 1.25f // 80 / 64
|
||||
|
||||
static TFT_eSprite *sprite = NULL;
|
||||
|
||||
bool ST7735Display::i2c_probe(TwoWire& wire, uint8_t addr) {
|
||||
return true;
|
||||
/*
|
||||
@@ -16,53 +409,103 @@ bool ST7735Display::i2c_probe(TwoWire& wire, uint8_t addr) {
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef PIN_TFT_LEDA_CTL_ACTIVE
|
||||
#define PIN_TFT_LEDA_CTL_ACTIVE HIGH
|
||||
#endif
|
||||
|
||||
bool ST7735Display::begin() {
|
||||
if (!sprite) {
|
||||
// alloc offscreen canvas
|
||||
sprite = new TFT_eSprite(&lcd);
|
||||
if (sprite) {
|
||||
if (sprite->createSprite(160, 80)) {
|
||||
sprite->fillScreen(ST77XX_BLACK);
|
||||
sprite->setTextColor(curr_color = ST77XX_WHITE);
|
||||
} else {
|
||||
Serial.printf("ST7735Display: failed to alloc canvas pixels");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("ST7735Display: failed to alloc canvas");
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isOn) {
|
||||
if (_peripher_power) _peripher_power->claim();
|
||||
|
||||
delay(100); // TEMP!!
|
||||
pinMode(PIN_TFT_RST, OUTPUT);
|
||||
pinMode(PIN_TFT_CS, OUTPUT);
|
||||
pinMode(PIN_TFT_DC, OUTPUT);
|
||||
pinMode(PIN_TFT_LEDA_CTL, OUTPUT);
|
||||
#if defined(PIN_TFT_LEDA_CTL_ACTIVE)
|
||||
digitalWrite(PIN_TFT_LEDA_CTL, PIN_TFT_LEDA_CTL_ACTIVE);
|
||||
#else
|
||||
digitalWrite(PIN_TFT_LEDA_CTL, HIGH);
|
||||
#endif
|
||||
digitalWrite(PIN_TFT_RST, HIGH);
|
||||
|
||||
#if defined(HELTEC_T1)
|
||||
display.initR(INITR_MINI160x80);
|
||||
display.setRotation(DISPLAY_ROTATION);
|
||||
#elif defined(HELTEC_TRACKER_V2) || defined(HELTEC_T096)
|
||||
display.initR(INITR_MINI160x80);
|
||||
display.setRotation(DISPLAY_ROTATION);
|
||||
uint8_t madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST7735_MADCTL_BGR;//Adjust color to BGR
|
||||
display.sendCommand(ST77XX_MADCTL, &madctl, 1);
|
||||
#ifdef ESP_PLATFORM
|
||||
_spi->begin(PIN_TFT_SCL, -1 /* _miso */, PIN_TFT_SDA /* _mosi */, -1);
|
||||
#else
|
||||
display.initR(INITR_MINI160x80_PLUGIN);
|
||||
display.setRotation(DISPLAY_ROTATION);
|
||||
_spi->begin();
|
||||
#endif
|
||||
display.setSPISpeed(40000000);
|
||||
display.fillScreen(ST77XX_BLACK);
|
||||
display.setTextColor(ST77XX_WHITE);
|
||||
display.setTextSize(2);
|
||||
display.cp437(true); // Use full 256 char 'Code Page 437' font
|
||||
_spi->setClockDivider(SPI_CLOCK_DIV2);
|
||||
|
||||
_height = 80;
|
||||
_width = 160;
|
||||
_colstart = 24;
|
||||
_rowstart = 0;
|
||||
|
||||
_resetAndInit();
|
||||
|
||||
sendCommand(ST77XX_DISPON);
|
||||
|
||||
_isOn = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ST7735Display::_resetAndInit() {
|
||||
// Pulse Reset low for 10ms
|
||||
digitalWrite(PIN_TFT_RST, HIGH);
|
||||
delay(2);
|
||||
digitalWrite(PIN_TFT_RST, LOW);
|
||||
delay(10);
|
||||
digitalWrite(PIN_TFT_RST, HIGH);
|
||||
delay(2);
|
||||
|
||||
// run init commands
|
||||
displayInit(Rcmd1);
|
||||
#if defined(HELTEC_TRACKER_V2) || defined(HELTEC_T096)
|
||||
displayInit(Rcmd2green160x80);
|
||||
//uint8_t madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST7735_MADCTL_BGR;//Adjust color to BGR
|
||||
//display.sendCommand(ST77XX_MADCTL, &madctl, 1);
|
||||
#endif
|
||||
displayInit(Rcmd3);
|
||||
setRotation(DISPLAY_ROTATION);
|
||||
|
||||
// clear the buffer before display on
|
||||
sprite->fillScreen(ST77XX_BLACK);
|
||||
endFrame();
|
||||
|
||||
// turn on backlight
|
||||
digitalWrite(PIN_TFT_LEDA_CTL, PIN_TFT_LEDA_CTL_ACTIVE);
|
||||
|
||||
}
|
||||
|
||||
void ST7735Display::turnOn() {
|
||||
ST7735Display::begin();
|
||||
if (!_isOn) {
|
||||
if (_peripher_power) _peripher_power->claim();
|
||||
_resetAndInit();
|
||||
sendCommand(ST77XX_DISPON);
|
||||
|
||||
// Now turn on the backlight
|
||||
// digitalWrite(PIN_TFT_LEDA_CTL, PIN_TFT_LEDA_CTL_ACTIVE);
|
||||
_isOn = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ST7735Display::turnOff() {
|
||||
if (_isOn) {
|
||||
digitalWrite(PIN_TFT_RST, LOW);
|
||||
#if defined(PIN_TFT_LEDA_CTL_ACTIVE)
|
||||
sendCommand(ST77XX_DISPOFF);
|
||||
|
||||
//digitalWrite(PIN_TFT_RST, LOW);
|
||||
// Now turn off the backlight
|
||||
digitalWrite(PIN_TFT_LEDA_CTL, !PIN_TFT_LEDA_CTL_ACTIVE);
|
||||
#else
|
||||
digitalWrite(PIN_TFT_LEDA_CTL, LOW);
|
||||
#endif
|
||||
_isOn = false;
|
||||
|
||||
if (_peripher_power) _peripher_power->release();
|
||||
@@ -70,78 +513,90 @@ void ST7735Display::turnOff() {
|
||||
}
|
||||
|
||||
void ST7735Display::clear() {
|
||||
//Serial.println("DBG: display.Clear");
|
||||
display.fillScreen(ST77XX_BLACK);
|
||||
sprite->fillScreen(ST77XX_BLACK);
|
||||
}
|
||||
|
||||
void ST7735Display::startFrame(Color bkg) {
|
||||
display.fillScreen(0x00);
|
||||
display.setTextColor(ST77XX_WHITE);
|
||||
display.setTextSize(1); // This one affects size of Please wait... message
|
||||
display.cp437(true); // Use full 256 char 'Code Page 437' font
|
||||
sprite->fillScreen(ST77XX_BLACK);
|
||||
sprite->setTextColor(curr_color = ST77XX_WHITE);
|
||||
sprite->setFreeFont();
|
||||
sprite->setTextSize(1); // This one affects size of Please wait... message
|
||||
//sprite->cp437(true); // Use full 256 char 'Code Page 437' font
|
||||
}
|
||||
|
||||
void ST7735Display::setTextSize(int sz) {
|
||||
display.setTextSize(sz);
|
||||
sprite->setTextSize(sz);
|
||||
}
|
||||
|
||||
void ST7735Display::setColor(Color c) {
|
||||
switch (c) {
|
||||
case DisplayDriver::DARK :
|
||||
_color = ST77XX_BLACK;
|
||||
curr_color = ST77XX_BLACK;
|
||||
break;
|
||||
case DisplayDriver::LIGHT :
|
||||
_color = ST77XX_WHITE;
|
||||
curr_color = ST77XX_WHITE;
|
||||
break;
|
||||
case DisplayDriver::RED :
|
||||
_color = ST77XX_RED;
|
||||
curr_color = ST77XX_RED;
|
||||
break;
|
||||
case DisplayDriver::GREEN :
|
||||
_color = ST77XX_GREEN;
|
||||
curr_color = ST77XX_GREEN;
|
||||
break;
|
||||
case DisplayDriver::BLUE :
|
||||
_color = ST77XX_BLUE;
|
||||
curr_color = ST77XX_BLUE;
|
||||
break;
|
||||
case DisplayDriver::YELLOW :
|
||||
_color = ST77XX_YELLOW;
|
||||
curr_color = ST77XX_YELLOW;
|
||||
break;
|
||||
case DisplayDriver::ORANGE :
|
||||
_color = ST77XX_ORANGE;
|
||||
curr_color = ST77XX_ORANGE;
|
||||
break;
|
||||
default:
|
||||
_color = ST77XX_WHITE;
|
||||
curr_color = ST77XX_WHITE;
|
||||
break;
|
||||
}
|
||||
display.setTextColor(_color);
|
||||
sprite->setTextColor(curr_color);
|
||||
}
|
||||
|
||||
void ST7735Display::setCursor(int x, int y) {
|
||||
display.setCursor(x*SCALE_X, y*SCALE_Y);
|
||||
sprite->setCursor(x*SCALE_X, y*SCALE_Y);
|
||||
}
|
||||
|
||||
void ST7735Display::print(const char* str) {
|
||||
display.print(str);
|
||||
sprite->print(str);
|
||||
}
|
||||
|
||||
void ST7735Display::fillRect(int x, int y, int w, int h) {
|
||||
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _color);
|
||||
sprite->fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, curr_color);
|
||||
}
|
||||
|
||||
void ST7735Display::drawRect(int x, int y, int w, int h) {
|
||||
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _color);
|
||||
sprite->drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, curr_color);
|
||||
}
|
||||
|
||||
void ST7735Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
||||
display.drawBitmap(x*SCALE_X, y*SCALE_Y, bits, w, h, _color);
|
||||
sprite->drawBitmap(x*SCALE_X, y*SCALE_Y, bits, w, h, curr_color);
|
||||
}
|
||||
|
||||
uint16_t ST7735Display::getTextWidth(const char* str) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
|
||||
return w / SCALE_X;
|
||||
return sprite->textWidth(str) / SCALE_X;
|
||||
}
|
||||
|
||||
void ST7735Display::endFrame() {
|
||||
// display.display();
|
||||
// blit the canvas buffer to LCD
|
||||
set_CS(LOW);
|
||||
_spi->beginTransaction(_spiSettings);
|
||||
uint16_t x, y;
|
||||
uint16_t* pixels = (uint16_t *) ((TFT_eSprite *) sprite)->getPointer();
|
||||
for (y = 0; y < 80; y++, pixels += 160) {
|
||||
setAddrWindow(0, y, 160, 1);
|
||||
#ifdef ESP_PLATFORM
|
||||
_spi->transferBytes((uint8_t *)pixels, NULL, 2 * 160);
|
||||
#else
|
||||
_spi->transfer(pixels, NULL, 2 * 160);
|
||||
#endif
|
||||
}
|
||||
|
||||
_spi->endTransaction();
|
||||
set_CS(HIGH);
|
||||
}
|
||||
|
||||
@@ -3,28 +3,25 @@
|
||||
#include "DisplayDriver.h"
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_ST7735.h>
|
||||
#include "TFT_eSPI.h"
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
|
||||
class ST7735Display : public DisplayDriver {
|
||||
Adafruit_ST7735 display;
|
||||
bool _isOn;
|
||||
uint16_t _color;
|
||||
RefCountedDigitalPin* _peripher_power;
|
||||
|
||||
bool i2c_probe(TwoWire& wire, uint8_t addr);
|
||||
public:
|
||||
#ifdef USE_PIN_TFT
|
||||
ST7735Display(RefCountedDigitalPin* peripher_power=NULL) : DisplayDriver(128, 64),
|
||||
display(PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_SDA, PIN_TFT_SCL, PIN_TFT_RST),
|
||||
// display(PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_SDA, PIN_TFT_SCL, PIN_TFT_RST),
|
||||
_peripher_power(peripher_power)
|
||||
{
|
||||
_isOn = false;
|
||||
}
|
||||
#else
|
||||
ST7735Display(RefCountedDigitalPin* peripher_power=NULL) : DisplayDriver(128, 64),
|
||||
display(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST),
|
||||
// display(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST),
|
||||
_peripher_power(peripher_power)
|
||||
{
|
||||
_isOn = false;
|
||||
@@ -46,4 +43,7 @@ public:
|
||||
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
|
||||
uint16_t getTextWidth(const char* str) override;
|
||||
void endFrame() override;
|
||||
|
||||
protected:
|
||||
void _resetAndInit();
|
||||
};
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
#define SCALE_Y 2.109375f // 135 / 64
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_SCALE_X
|
||||
#define SCALE_X DISPLAY_SCALE_X
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_SCALE_Y
|
||||
#define SCALE_Y DISPLAY_SCALE_Y
|
||||
#endif
|
||||
|
||||
bool ST7789Display::begin() {
|
||||
if(!_isOn) {
|
||||
pinMode(PIN_TFT_VDD_CTL, OUTPUT);
|
||||
@@ -32,6 +40,9 @@ bool ST7789Display::begin() {
|
||||
|
||||
display.init();
|
||||
display.landscapeScreen();
|
||||
#ifdef DISPLAY_FLIP_VERTICALLY
|
||||
display.flipScreenVertically();
|
||||
#endif
|
||||
display.displayOn();
|
||||
setCursor(0,0);
|
||||
|
||||
@@ -49,6 +60,9 @@ void ST7789Display::turnOn() {
|
||||
// Re-initialize the display
|
||||
display.init();
|
||||
display.displayOn();
|
||||
#ifdef DISPLAY_FLIP_VERTICALLY
|
||||
display.flipScreenVertically();
|
||||
#endif
|
||||
delay(20);
|
||||
|
||||
// Now turn on the backlight
|
||||
|
||||
@@ -14,8 +14,10 @@ class ST7789Display : public DisplayDriver {
|
||||
|
||||
bool i2c_probe(TwoWire& wire, uint8_t addr);
|
||||
public:
|
||||
#ifdef HELTEC_VISION_MASTER_T190
|
||||
#if defined(HELTEC_VISION_MASTER_T190)
|
||||
ST7789Display() : DisplayDriver(128, 64), display(&SPI, PIN_TFT_RST, PIN_TFT_DC, PIN_TFT_CS, GEOMETRY_RAWMODE, 320, 170,PIN_TFT_SDA,-1,PIN_TFT_SCL) {_isOn = false;}
|
||||
#elif defined(THINKNODE_M9)
|
||||
ST7789Display() : DisplayDriver(128, 64), display(&SPI, ST7789_RESET, ST7789_RS, ST7789_CS, GEOMETRY_RAWMODE, 320, 240, ST7789_SDA, ST7789_MISO, ST7789_SCK) {_isOn = false;}
|
||||
#else
|
||||
ST7789Display() : DisplayDriver(128, 64), display(&SPI1, PIN_TFT_RST, PIN_TFT_DC, PIN_TFT_CS, GEOMETRY_RAWMODE, 240, 135) {_isOn = false;}
|
||||
#endif
|
||||
|
||||
+25
-4
@@ -3,12 +3,33 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Mock SHA256 class for testing
|
||||
// Provides minimal interface to allow Utils.cpp to compile
|
||||
// Mock SHA256 for native testing — deterministic but not cryptographic.
|
||||
// finalize() writes real (non-garbage) output so calculatePacketHash() produces
|
||||
// distinguishable results for packets with different payloads.
|
||||
#include <string.h>
|
||||
|
||||
class SHA256 {
|
||||
uint8_t _state[32];
|
||||
size_t _len;
|
||||
public:
|
||||
void update(const uint8_t* data, size_t len) {}
|
||||
void finalize(uint8_t* hash, size_t hashLen) {}
|
||||
SHA256() : _len(0) { memset(_state, 0, sizeof(_state)); }
|
||||
|
||||
void update(const void* data, size_t len) {
|
||||
const uint8_t* bytes = static_cast<const uint8_t*>(data);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t b = bytes[i];
|
||||
_state[_len % 32] ^= b;
|
||||
_state[(_len + 1) % 32] += (uint8_t)((b >> 1) | (b << 7));
|
||||
_len++;
|
||||
}
|
||||
}
|
||||
|
||||
void finalize(uint8_t* hash, size_t hashLen) {
|
||||
for (size_t i = 0; i < hashLen; i++) {
|
||||
hash[i] = _state[i % 32];
|
||||
}
|
||||
}
|
||||
|
||||
void resetHMAC(const uint8_t* key, size_t keyLen) {}
|
||||
void finalizeHMAC(const uint8_t* key, size_t keyLen, uint8_t* hash, size_t hashLen) {}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "helpers/SimpleMeshTables.h"
|
||||
|
||||
using namespace mesh;
|
||||
|
||||
// Build a packet that calculatePacketHash() distinguishes by payload content.
|
||||
// header selects ROUTE_TYPE_FLOOD so isRouteDirect() returns false.
|
||||
static Packet makeFloodPacket(uint8_t seed) {
|
||||
Packet p;
|
||||
p.header = ROUTE_TYPE_FLOOD | (PAYLOAD_TYPE_ACK << PH_TYPE_SHIFT);
|
||||
p.payload[0] = seed;
|
||||
p.payload_len = 1;
|
||||
p.path_len = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static Packet makeDirectPacket(uint8_t seed) {
|
||||
Packet p;
|
||||
p.header = ROUTE_TYPE_DIRECT | (PAYLOAD_TYPE_ACK << PH_TYPE_SHIFT);
|
||||
p.payload[0] = seed;
|
||||
p.payload_len = 1;
|
||||
p.path_len = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
// ── wasSeen: pure query ───────────────────────────────────────────────────────
|
||||
|
||||
TEST(SimpleMeshTables, WasSeen_ReturnsFalseForUnseen) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
EXPECT_FALSE(t.wasSeen(&p));
|
||||
}
|
||||
|
||||
// wasSeen shouldn't change state
|
||||
TEST(SimpleMeshTables, WasSeen_IsPureQuery_DoesNotInsert) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
EXPECT_FALSE(t.wasSeen(&p));
|
||||
EXPECT_FALSE(t.wasSeen(&p));
|
||||
}
|
||||
|
||||
// ── markSeen + wasSeen ───────────────────────────────────────────────────────
|
||||
|
||||
TEST(SimpleMeshTables, MarkSeen_MakesWasSeenReturnTrue) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
t.markSeen(&p);
|
||||
EXPECT_TRUE(t.wasSeen(&p));
|
||||
}
|
||||
|
||||
TEST(SimpleMeshTables, MarkSeen_DoesNotAffectOtherPackets) {
|
||||
SimpleMeshTables t;
|
||||
Packet p1 = makeFloodPacket(0x01);
|
||||
Packet p2 = makeFloodPacket(0x02);
|
||||
t.markSeen(&p1);
|
||||
EXPECT_FALSE(t.wasSeen(&p2));
|
||||
}
|
||||
|
||||
// Canonical pattern used at every onRecvPacket call site:
|
||||
// if (!wasSeen(pkt)) { markSeen(pkt); process(pkt); }
|
||||
TEST(SimpleMeshTables, QueryThenMark_WorksCorrectly) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
EXPECT_FALSE(t.wasSeen(&p));
|
||||
t.markSeen(&p);
|
||||
EXPECT_TRUE(t.wasSeen(&p));
|
||||
}
|
||||
|
||||
// ── dup stats ────────────────────────────────────────────────────────────────
|
||||
|
||||
TEST(SimpleMeshTables, WasSeen_IncrementsFloodDupStat) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
t.markSeen(&p);
|
||||
t.wasSeen(&p);
|
||||
EXPECT_EQ(1u, t.getNumFloodDups());
|
||||
EXPECT_EQ(0u, t.getNumDirectDups());
|
||||
}
|
||||
|
||||
TEST(SimpleMeshTables, WasSeen_IncrementsDirectDupStat) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeDirectPacket(0x01);
|
||||
t.markSeen(&p);
|
||||
t.wasSeen(&p);
|
||||
EXPECT_EQ(0u, t.getNumFloodDups());
|
||||
EXPECT_EQ(1u, t.getNumDirectDups());
|
||||
}
|
||||
|
||||
// ── clear ────────────────────────────────────────────────────────────────────
|
||||
|
||||
TEST(SimpleMeshTables, Clear_RemovesSeenPacket) {
|
||||
SimpleMeshTables t;
|
||||
Packet p = makeFloodPacket(0x01);
|
||||
t.markSeen(&p);
|
||||
ASSERT_TRUE(t.wasSeen(&p));
|
||||
t.clear(&p);
|
||||
EXPECT_FALSE(t.wasSeen(&p));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
uint32_t button_pin = PIN_BUTTON1;
|
||||
nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW);
|
||||
sd_power_system_off();
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
uint32_t button_pin = PIN_BUTTON1;
|
||||
nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW);
|
||||
sd_power_system_off();
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
uint32_t button_pin = PIN_BUTTON1;
|
||||
nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW);
|
||||
sd_power_system_off();
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
uint32_t button_pin = PIN_BUTTON1;
|
||||
nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW);
|
||||
sd_power_system_off();
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -20,33 +20,6 @@ void HeltecE213Board::begin() {
|
||||
}
|
||||
}
|
||||
|
||||
void HeltecE213Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void HeltecE213Board::powerOff() {
|
||||
enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t HeltecE213Board::getBattMilliVolts() {
|
||||
analogReadResolution(10);
|
||||
digitalWrite(PIN_ADC_CTRL, HIGH);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecE213Board : public ESP32Board {
|
||||
|
||||
@@ -13,8 +12,6 @@ public:
|
||||
HeltecE213Board() : periph_power(PIN_VEXT_EN,PIN_VEXT_EN_ACTIVE) { }
|
||||
|
||||
void begin();
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||
void powerOff() override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
const char* getManufacturerName() const override ;
|
||||
};
|
||||
|
||||
@@ -20,33 +20,6 @@ void HeltecE290Board::begin() {
|
||||
}
|
||||
}
|
||||
|
||||
void HeltecE290Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void HeltecE290Board::powerOff() {
|
||||
enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t HeltecE290Board::getBattMilliVolts() {
|
||||
analogReadResolution(10);
|
||||
digitalWrite(PIN_ADC_CTRL, HIGH);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecE290Board : public ESP32Board {
|
||||
|
||||
@@ -13,8 +12,6 @@ public:
|
||||
HeltecE290Board() : periph_power(PIN_VEXT_EN, PIN_VEXT_EN_ACTIVE) { }
|
||||
|
||||
void begin();
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||
void powerOff() override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
const char* getManufacturerName() const override ;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[Heltec_mesh_solar]
|
||||
extends = nrf52_base
|
||||
board = heltec_mesh_solar
|
||||
platform_packages = framework-arduinoadafruitnrf52
|
||||
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
-I src/helpers/nrf52
|
||||
@@ -14,6 +13,11 @@ build_flags = ${nrf52_base.build_flags}
|
||||
-D LORA_TX_POWER=22
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
-D HAS_EXTERNAL_WATCHDOG
|
||||
-D EXTERNAL_WATCHDOG_DONE_PIN=9
|
||||
-D EXTERNAL_WATCHDOG_WAKE_PIN=10
|
||||
-D EXTERNAL_WATCHDOG_FEED_INTERVAL_MS=480000 ; 8 minute feed interval, safely inside the hardware watchdog timeout
|
||||
|
||||
build_src_filter = ${nrf52_base.build_src_filter}
|
||||
+<helpers/*.cpp>
|
||||
+<../variants/heltec_mesh_solar>
|
||||
|
||||
@@ -13,6 +13,7 @@ VolatileRTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
|
||||
SolarSensorManager sensors = SolarSensorManager(nmea);
|
||||
SolarExternalWatchdog external_watchdog;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
@@ -106,3 +107,34 @@ bool SolarSensorManager::setSettingValue(const char* name, const char* value) {
|
||||
}
|
||||
return false; // not supported
|
||||
}
|
||||
|
||||
bool SolarExternalWatchdog::begin() {
|
||||
last_feed_watchdog = 0;
|
||||
pinMode(EXTERNAL_WATCHDOG_WAKE_PIN, INPUT);
|
||||
pinMode(EXTERNAL_WATCHDOG_DONE_PIN, OUTPUT);
|
||||
delay(1);
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW);
|
||||
delay(1);
|
||||
feed();
|
||||
return true;
|
||||
}
|
||||
void SolarExternalWatchdog::loop() {
|
||||
if (millis() - last_feed_watchdog >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) {
|
||||
feed();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long SolarExternalWatchdog::getIntervalMs() const {
|
||||
unsigned long elapsed_ms = millis() - last_feed_watchdog;
|
||||
if (elapsed_ms >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) {
|
||||
return 0;
|
||||
}
|
||||
return EXTERNAL_WATCHDOG_FEED_INTERVAL_MS - elapsed_ms;
|
||||
}
|
||||
|
||||
void SolarExternalWatchdog::feed() {
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, HIGH);
|
||||
delay(1);
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW);
|
||||
last_feed_watchdog = millis();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
#include <helpers/sensors/LocationProvider.h>
|
||||
#include <helpers/ExternalWatchdogManager.h>
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/ST7789Display.h>
|
||||
#endif
|
||||
@@ -30,10 +31,20 @@ public:
|
||||
bool setSettingValue(const char* name, const char* value) override;
|
||||
};
|
||||
|
||||
class SolarExternalWatchdog : public ExternalWatchdogManager {
|
||||
public:
|
||||
SolarExternalWatchdog() {}
|
||||
bool begin() override;
|
||||
void loop() override;
|
||||
unsigned long getIntervalMs() const override;
|
||||
void feed() override;
|
||||
};
|
||||
|
||||
extern MeshSolarBoard board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern SolarSensorManager sensors;
|
||||
extern SolarExternalWatchdog external_watchdog;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
extern DISPLAY_CLASS display;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#define PIN_SERIAL1_RX (37)
|
||||
#define PIN_SERIAL1_TX (39)
|
||||
|
||||
#define PIN_SERIAL2_RX (9)
|
||||
#define PIN_SERIAL2_TX (10)
|
||||
#define PIN_SERIAL2_RX (-1)
|
||||
#define PIN_SERIAL2_TX (-1)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// I2C pin definition
|
||||
|
||||
@@ -112,13 +112,9 @@ void T096Board::variant_shutdown() {
|
||||
}
|
||||
|
||||
void T096Board::powerOff() {
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||
#endif
|
||||
loRaFEMControl.setSleepModeEnable();
|
||||
variant_shutdown();
|
||||
sd_power_system_off();
|
||||
loRaFEMControl.setSleepModeEnable();
|
||||
nrf_gpio_cfg_default(PIN_GPS_EN); // 363uA down to 39uA
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
const char* T096Board::getManufacturerName() const {
|
||||
|
||||
@@ -51,7 +51,7 @@ build_src_filter = ${nrf52_base.build_src_filter}
|
||||
lib_deps =
|
||||
${nrf52_base.lib_deps}
|
||||
${sensor_base.lib_deps}
|
||||
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
|
||||
bodmer/TFT_eSPI @ ^2.4.31
|
||||
debug_tool = jlink
|
||||
upload_protocol = nrfutil
|
||||
|
||||
|
||||
@@ -81,34 +81,6 @@ uint16_t T1Board::getBattMilliVolts() {
|
||||
}
|
||||
|
||||
void T1Board::variant_shutdown() {
|
||||
nrf_gpio_cfg_default(PIN_TFT_CS);
|
||||
nrf_gpio_cfg_default(PIN_TFT_DC);
|
||||
nrf_gpio_cfg_default(PIN_TFT_SDA);
|
||||
nrf_gpio_cfg_default(PIN_TFT_SCL);
|
||||
nrf_gpio_cfg_default(PIN_TFT_RST);
|
||||
nrf_gpio_cfg_default(PIN_TFT_LEDA_CTL);
|
||||
nrf_gpio_cfg_default(PIN_TFT_VDD_CTL);
|
||||
|
||||
nrf_gpio_cfg_default(PIN_WIRE_SDA);
|
||||
nrf_gpio_cfg_default(PIN_WIRE_SCL);
|
||||
|
||||
nrf_gpio_cfg_default(LORA_CS);
|
||||
nrf_gpio_cfg_default(SX126X_DIO1);
|
||||
nrf_gpio_cfg_default(SX126X_BUSY);
|
||||
nrf_gpio_cfg_default(SX126X_RESET);
|
||||
nrf_gpio_cfg_default(PIN_SPI_MISO);
|
||||
nrf_gpio_cfg_default(PIN_SPI_MOSI);
|
||||
nrf_gpio_cfg_default(PIN_SPI_SCK);
|
||||
|
||||
nrf_gpio_cfg_default(PIN_SPI1_MOSI);
|
||||
nrf_gpio_cfg_default(PIN_SPI1_SCK);
|
||||
|
||||
nrf_gpio_cfg_default(PIN_GPS_RESET);
|
||||
nrf_gpio_cfg_default(PIN_GPS_EN);
|
||||
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||
nrf_gpio_cfg_default(PIN_GPS_RX);
|
||||
nrf_gpio_cfg_default(PIN_GPS_TX);
|
||||
|
||||
nrf_gpio_cfg_default(PIN_BUZZER_VOLTAGE_MULTIPLIER_1);
|
||||
nrf_gpio_cfg_default(PIN_BUZZER_VOLTAGE_MULTIPLIER_2);
|
||||
|
||||
@@ -127,7 +99,7 @@ void T1Board::variant_shutdown() {
|
||||
|
||||
void T1Board::powerOff() {
|
||||
variant_shutdown();
|
||||
sd_power_system_off();
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
|
||||
const char* T1Board::getManufacturerName() const {
|
||||
|
||||
@@ -33,7 +33,7 @@ void T114Board::initiateShutdown(uint8_t reason) {
|
||||
#endif // NRF52_POWER_MANAGEMENT
|
||||
|
||||
void T114Board::begin() {
|
||||
NRF52Board::begin();
|
||||
NRF52BoardDCDC::begin();
|
||||
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
|
||||
|
||||
@@ -50,10 +50,7 @@ public:
|
||||
#ifdef LED_PIN
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
#endif
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
pinMode(GPS_EN, OUTPUT);
|
||||
digitalWrite(GPS_EN, LOW);
|
||||
#endif
|
||||
sd_power_system_off();
|
||||
|
||||
NRF52Board::powerOff();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
|
||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
|
||||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||
#else
|
||||
EnvironmentSensorManager sensors;
|
||||
|
||||
@@ -20,33 +20,6 @@ void HeltecT190Board::begin() {
|
||||
}
|
||||
}
|
||||
|
||||
void HeltecT190Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void HeltecT190Board::powerOff() {
|
||||
enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t HeltecT190Board::getBattMilliVolts() {
|
||||
analogReadResolution(10);
|
||||
digitalWrite(PIN_ADC_CTRL, HIGH);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecT190Board : public ESP32Board {
|
||||
|
||||
@@ -13,8 +12,6 @@ public:
|
||||
HeltecT190Board() : periph_power(PIN_VEXT_EN,PIN_VEXT_EN_ACTIVE) { }
|
||||
|
||||
void begin();
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||
void powerOff() override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
const char* getManufacturerName() const override ;
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "HeltecTowerV2Board.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
extern void variant_shutdown();
|
||||
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
const PowerMgtConfig power_config = {
|
||||
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
|
||||
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
|
||||
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
|
||||
};
|
||||
|
||||
void HeltecTowerV2Board::initiateShutdown(uint8_t reason) {
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||
loRaFEMControl.setSleepModeEnable();
|
||||
|
||||
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
|
||||
reason == SHUTDOWN_REASON_BOOT_PROTECT);
|
||||
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||
digitalWrite(PIN_BAT_CTL, enable_lpcomp ? HIGH : LOW);
|
||||
|
||||
if (enable_lpcomp) {
|
||||
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
|
||||
}
|
||||
|
||||
variant_shutdown();
|
||||
enterSystemOff(reason);
|
||||
}
|
||||
#endif
|
||||
|
||||
void HeltecTowerV2Board::begin() {
|
||||
NRF52Board::begin();
|
||||
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
|
||||
|
||||
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||
digitalWrite(PIN_BAT_CTL, LOW);
|
||||
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
checkBootVoltage(&power_config);
|
||||
#endif
|
||||
|
||||
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||
Wire.begin();
|
||||
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
digitalWrite(PIN_GPS_STANDBY, HIGH);
|
||||
loRaFEMControl.init();
|
||||
}
|
||||
|
||||
void HeltecTowerV2Board::onBeforeTransmit() {
|
||||
digitalWrite(P_LORA_TX_LED, LED_STATE_ON);
|
||||
loRaFEMControl.setTxModeEnable();
|
||||
}
|
||||
|
||||
void HeltecTowerV2Board::onAfterTransmit() {
|
||||
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
|
||||
loRaFEMControl.setRxModeEnable();
|
||||
}
|
||||
|
||||
uint16_t HeltecTowerV2Board::getBattMilliVolts() {
|
||||
analogReadResolution(12);
|
||||
analogReference(VBAT_AR_INTERNAL);
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||
digitalWrite(PIN_BAT_CTL, HIGH);
|
||||
|
||||
delay(10);
|
||||
int adcvalue = analogRead(PIN_VBAT_READ);
|
||||
digitalWrite(PIN_BAT_CTL, LOW);
|
||||
|
||||
return (uint16_t)((float)adcvalue * MV_LSB * ADC_MULTIPLIER);
|
||||
}
|
||||
|
||||
const char* HeltecTowerV2Board::getManufacturerName() const {
|
||||
return "Heltec Tower V2";
|
||||
}
|
||||
|
||||
void HeltecTowerV2Board::powerOff() {
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
|
||||
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
|
||||
loRaFEMControl.setSleepModeEnable();
|
||||
pinMode(PIN_BAT_CTL, OUTPUT);
|
||||
digitalWrite(PIN_BAT_CTL, LOW);
|
||||
variant_shutdown();
|
||||
sd_power_system_off();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MeshCore.h>
|
||||
#include <helpers/NRF52Board.h>
|
||||
#include "LoRaFEMControl.h"
|
||||
|
||||
class HeltecTowerV2Board : public NRF52BoardDCDC {
|
||||
protected:
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
void initiateShutdown(uint8_t reason) override;
|
||||
#endif
|
||||
|
||||
public:
|
||||
LoRaFEMControl loRaFEMControl;
|
||||
|
||||
HeltecTowerV2Board() : NRF52Board("TOWER_V2_OTA") {}
|
||||
void begin();
|
||||
void onBeforeTransmit() override;
|
||||
void onAfterTransmit() override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
const char* getManufacturerName() const override;
|
||||
void powerOff() override;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "LoRaFEMControl.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "variant.h"
|
||||
|
||||
static void enableFEMPower() {
|
||||
bool wasOff = digitalRead(LORA_KCT8103L_EN) != HIGH;
|
||||
digitalWrite(LORA_KCT8103L_EN, HIGH);
|
||||
if (wasOff) {
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaFEMControl::init() {
|
||||
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||
digitalWrite(LORA_KCT8103L_EN, HIGH);
|
||||
delay(1);
|
||||
pinMode(LORA_KCT8103L_TX_RX, OUTPUT);
|
||||
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||
}
|
||||
|
||||
void LoRaFEMControl::setSleepModeEnable() {
|
||||
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||
digitalWrite(LORA_KCT8103L_EN, LOW);
|
||||
}
|
||||
|
||||
void LoRaFEMControl::setTxModeEnable() {
|
||||
enableFEMPower();
|
||||
digitalWrite(LORA_KCT8103L_TX_RX, HIGH);
|
||||
}
|
||||
|
||||
void LoRaFEMControl::setRxModeEnable() {
|
||||
enableFEMPower();
|
||||
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||
}
|
||||
|
||||
void LoRaFEMControl::setRxModeEnableWhenMCUSleep() {
|
||||
enableFEMPower();
|
||||
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
class LoRaFEMControl {
|
||||
public:
|
||||
LoRaFEMControl() {}
|
||||
virtual ~LoRaFEMControl() {}
|
||||
|
||||
void init();
|
||||
void setSleepModeEnable();
|
||||
void setTxModeEnable();
|
||||
void setRxModeEnable();
|
||||
void setRxModeEnableWhenMCUSleep();
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
[Heltec_tower_v2]
|
||||
extends = nrf52_base
|
||||
board = heltec_tower_v2
|
||||
board_build.ldscript = boards/nrf52840_s140_v6.ld
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
-D ENV_INCLUDE_GPS=1
|
||||
-I lib/nrf52/s140_nrf52_6.1.1_API/include
|
||||
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
|
||||
-I variants/heltec_tower_v2
|
||||
-D HELTEC_TOWER_V2
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||
-D LORA_TX_POWER=12
|
||||
-D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~29dBm at antenna
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
build_src_filter = ${nrf52_base.build_src_filter}
|
||||
+<helpers/*.cpp>
|
||||
+<helpers/sensors>
|
||||
+<../variants/heltec_tower_v2>
|
||||
lib_deps =
|
||||
${nrf52_base.lib_deps}
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
debug_tool = jlink
|
||||
upload_protocol = nrfutil
|
||||
|
||||
[env:Heltec_tower_v2_repeater]
|
||||
extends = Heltec_tower_v2
|
||||
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
build_flags =
|
||||
${Heltec_tower_v2.build_flags}
|
||||
-D ADVERT_NAME='"Heltec_Tower_V2 Repeater"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
|
||||
[env:Heltec_tower_v2_room_server]
|
||||
extends = Heltec_tower_v2
|
||||
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
build_flags =
|
||||
${Heltec_tower_v2.build_flags}
|
||||
-D ADVERT_NAME='"Heltec_Tower_V2 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
|
||||
|
||||
[env:Heltec_tower_v2_companion_radio_ble]
|
||||
extends = Heltec_tower_v2
|
||||
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
|
||||
board_upload.maximum_size = 712704
|
||||
build_flags =
|
||||
${Heltec_tower_v2.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D DISPLAY_CLASS=NullDisplayDriver
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
; -D BLE_DEBUG_LOGGING=1
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${Heltec_tower_v2.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:Heltec_tower_v2_companion_radio_usb]
|
||||
extends = Heltec_tower_v2
|
||||
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
|
||||
board_upload.maximum_size = 712704
|
||||
build_flags =
|
||||
${Heltec_tower_v2.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D DISPLAY_CLASS=NullDisplayDriver
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
; -D BLE_PIN_CODE=123456
|
||||
; -D BLE_DEBUG_LOGGING=1
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||
+<helpers/nrf52/*.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${Heltec_tower_v2.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:Heltec_tower_v2_kiss_modem]
|
||||
extends = Heltec_tower_v2
|
||||
build_src_filter = ${Heltec_tower_v2.build_src_filter}
|
||||
+<../examples/kiss_modem/>
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "target.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <helpers/ArduinoHelpers.h>
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
|
||||
HeltecTowerV2Board 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, &rtc_clock);
|
||||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||
TowerV2ExternalWatchdog external_watchdog;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
||||
#endif
|
||||
|
||||
bool radio_init() {
|
||||
rtc_clock.begin(Wire);
|
||||
return radio.std_init(&SPI);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
RadioNoiseListener rng(radio);
|
||||
return mesh::LocalIdentity(&rng);
|
||||
}
|
||||
|
||||
bool TowerV2ExternalWatchdog::begin() {
|
||||
last_feed_watchdog = 0;
|
||||
pinMode(EXTERNAL_WATCHDOG_WAKE_PIN, INPUT);
|
||||
pinMode(EXTERNAL_WATCHDOG_DONE_PIN, OUTPUT);
|
||||
delay(1);
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW);
|
||||
delay(1);
|
||||
feed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TowerV2ExternalWatchdog::loop() {
|
||||
if (millis() - last_feed_watchdog >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) {
|
||||
feed();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long TowerV2ExternalWatchdog::getIntervalMs() const {
|
||||
unsigned long elapsed_ms = millis() - last_feed_watchdog;
|
||||
if (elapsed_ms >= EXTERNAL_WATCHDOG_FEED_INTERVAL_MS) {
|
||||
return 0;
|
||||
}
|
||||
return EXTERNAL_WATCHDOG_FEED_INTERVAL_MS - elapsed_ms;
|
||||
}
|
||||
|
||||
void TowerV2ExternalWatchdog::feed() {
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, HIGH);
|
||||
delay(1);
|
||||
digitalWrite(EXTERNAL_WATCHDOG_DONE_PIN, LOW);
|
||||
last_feed_watchdog = millis();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include <RadioLib.h>
|
||||
#include <HeltecTowerV2Board.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||
#include <helpers/sensors/LocationProvider.h>
|
||||
#include <helpers/ExternalWatchdogManager.h>
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/MomentaryButton.h>
|
||||
#include "helpers/ui/NullDisplayDriver.h"
|
||||
#endif
|
||||
|
||||
class TowerV2ExternalWatchdog : public ExternalWatchdogManager {
|
||||
public:
|
||||
TowerV2ExternalWatchdog() {}
|
||||
bool begin() override;
|
||||
void loop() override;
|
||||
unsigned long getIntervalMs() const override;
|
||||
void feed() override;
|
||||
};
|
||||
|
||||
extern HeltecTowerV2Board board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern EnvironmentSensorManager sensors;
|
||||
extern TowerV2ExternalWatchdog external_watchdog;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
extern DISPLAY_CLASS display;
|
||||
extern MomentaryButton user_btn;
|
||||
#endif
|
||||
|
||||
bool radio_init();
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "variant.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
|
||||
const uint32_t g_ADigitalPinMap[] = {
|
||||
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, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47
|
||||
};
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void variant_shutdown()
|
||||
{
|
||||
nrf_gpio_cfg_default(PIN_GPS_EN);
|
||||
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||
nrf_gpio_cfg_default(PIN_GPS_RESET);
|
||||
nrf_gpio_cfg_default(PIN_GPS_STANDBY);
|
||||
nrf_gpio_cfg_default(GPS_RX_PIN);
|
||||
nrf_gpio_cfg_default(GPS_TX_PIN);
|
||||
pinMode(LORA_KCT8103L_EN, OUTPUT);
|
||||
digitalWrite(LORA_KCT8103L_EN, LOW);
|
||||
nrf_gpio_cfg_default(LORA_KCT8103L_TX_RX);
|
||||
nrf_gpio_cfg_default(RF_PA_DETECT_PIN);
|
||||
nrf_gpio_cfg_default(SX126X_CS);
|
||||
nrf_gpio_cfg_default(SX126X_DIO1);
|
||||
nrf_gpio_cfg_default(SX126X_BUSY);
|
||||
nrf_gpio_cfg_default(SX126X_RESET);
|
||||
nrf_gpio_cfg_default(PIN_SPI_MISO);
|
||||
nrf_gpio_cfg_default(PIN_SPI_MOSI);
|
||||
nrf_gpio_cfg_default(PIN_SPI_SCK);
|
||||
nrf_gpio_cfg_default(PIN_LED);
|
||||
detachInterrupt(PIN_GPS_PPS);
|
||||
detachInterrupt(PIN_BUTTON1);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#define USE_LFXO
|
||||
#define VARIANT_MCK (64000000ul)
|
||||
|
||||
#define PINS_COUNT (48)
|
||||
#define NUM_DIGITAL_PINS (48)
|
||||
#define NUM_ANALOG_INPUTS (1)
|
||||
#define NUM_ANALOG_OUTPUTS (0)
|
||||
|
||||
#define WIRE_INTERFACES_COUNT (1)
|
||||
#define PIN_WIRE_SDA (0 + 30)
|
||||
#define PIN_WIRE_SCL (0 + 5)
|
||||
#define PIN_BOARD_SDA PIN_WIRE_SDA
|
||||
#define PIN_BOARD_SCL PIN_WIRE_SCL
|
||||
|
||||
#define SPI_INTERFACES_COUNT (1)
|
||||
#define PIN_SPI_MISO (0 + 23)
|
||||
#define PIN_SPI_MOSI (0 + 22)
|
||||
#define PIN_SPI_SCK (0 + 19)
|
||||
#define PIN_SPI_NSS LORA_CS
|
||||
|
||||
#define LED_BUILTIN (32 + 15)
|
||||
#define PIN_LED LED_BUILTIN
|
||||
#define LED_RED (-1)
|
||||
#define LED_GREEN (-1)
|
||||
#define LED_BLUE (-1)
|
||||
#define LED_PIN (-1)
|
||||
#define P_LORA_TX_LED LED_BUILTIN
|
||||
#define LED_STATE_ON LOW
|
||||
|
||||
#define PIN_BUTTON1 (32 + 10)
|
||||
#define BUTTON_PIN PIN_BUTTON1
|
||||
#define PIN_USER_BTN BUTTON_PIN
|
||||
|
||||
#define USE_SX1262
|
||||
#define SX126X_CS (0 + 24)
|
||||
#define LORA_CS SX126X_CS
|
||||
#define SX126X_DIO1 (0 + 20)
|
||||
#define SX126X_BUSY (0 + 17)
|
||||
#define SX126X_RESET (0 + 25)
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
#define P_LORA_NSS LORA_CS
|
||||
#define P_LORA_DIO_1 SX126X_DIO1
|
||||
#define P_LORA_BUSY SX126X_BUSY
|
||||
#define P_LORA_RESET SX126X_RESET
|
||||
#define P_LORA_MISO PIN_SPI_MISO
|
||||
#define P_LORA_MOSI PIN_SPI_MOSI
|
||||
#define P_LORA_SCLK PIN_SPI_SCK
|
||||
|
||||
#define USE_KCT8103L_PA_ONLY
|
||||
#define LORA_KCT8103L_EN (0 + 15)
|
||||
#define LORA_KCT8103L_TX_RX (0 + 16)
|
||||
#define LORA_PA_POWER LORA_KCT8103L_EN
|
||||
#define RF_PA_DETECT_PIN (0 + 13)
|
||||
#define RF_PA_HIGH_POWER_VALUE HIGH
|
||||
|
||||
#define GPS_L76K
|
||||
#define GPS_RESET_MODE LOW
|
||||
#define PIN_GPS_RESET (32 + 6)
|
||||
#define PIN_GPS_RESET_ACTIVE GPS_RESET_MODE
|
||||
#define PIN_GPS_EN (0 + 7)
|
||||
#define PIN_GPS_EN_ACTIVE LOW
|
||||
#define GPS_EN_ACTIVE PIN_GPS_EN_ACTIVE
|
||||
#define PIN_GPS_STANDBY (32 + 2)
|
||||
#define PIN_GPS_PPS (32 + 4)
|
||||
#define GPS_BAUD_RATE 9600
|
||||
|
||||
// Upstream names are from the GPS perspective. MeshCore's PIN_GPS_TX is the
|
||||
// CPU RX pin because EnvironmentSensorManager passes it as Serial1 RX.
|
||||
#define GPS_TX_PIN (32 + 7)
|
||||
#define GPS_RX_PIN (32 + 5)
|
||||
#define PIN_GPS_TX GPS_RX_PIN
|
||||
#define PIN_GPS_RX GPS_TX_PIN
|
||||
|
||||
#define PIN_SERIAL1_RX PIN_GPS_TX
|
||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||
#define PIN_SERIAL2_RX (-1)
|
||||
#define PIN_SERIAL2_TX (-1)
|
||||
|
||||
#define HAS_EXTERNAL_WATCHDOG
|
||||
#define EXTERNAL_WATCHDOG_DONE_PIN (0 + 9)
|
||||
#define EXTERNAL_WATCHDOG_WAKE_PIN (0 + 10)
|
||||
#define EXTERNAL_WATCHDOG_FEED_INTERVAL_MS (8 * 60 * 1000)
|
||||
|
||||
#define SERIAL_PRINT_PORT 0
|
||||
|
||||
#define PIN_BAT_CTL (0 + 21)
|
||||
#define ADC_CTRL PIN_BAT_CTL
|
||||
#define ADC_CTRL_ENABLED HIGH
|
||||
#define BATTERY_PIN (0 + 4)
|
||||
#define PIN_VBAT_READ BATTERY_PIN
|
||||
#define ADC_RESOLUTION 14
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||
#define AREF_VOLTAGE 3.0
|
||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||
#define ADC_MULTIPLIER (4.916F)
|
||||
#define MV_LSB (3000.0F / 4096.0F)
|
||||
|
||||
#define NRF52_POWER_MANAGEMENT
|
||||
#define PWRMGT_VOLTAGE_BOOTLOCK 3100
|
||||
#define PWRMGT_LPCOMP_AIN 2
|
||||
#define PWRMGT_LPCOMP_REFSEL 1
|
||||
@@ -47,7 +47,7 @@ build_src_filter = ${esp32_base.build_src_filter}
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
|
||||
bodmer/TFT_eSPI @ ^2.4.31
|
||||
|
||||
[env:Heltec_Wireless_Tracker_companion_radio_usb]
|
||||
extends = Heltec_tracker_base
|
||||
|
||||
@@ -35,33 +35,12 @@ void HeltecTrackerV2Board::begin() {
|
||||
loRaFEMControl.setRxModeEnable();
|
||||
}
|
||||
|
||||
void HeltecTrackerV2Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
void HeltecTrackerV2Board::powerOff() {
|
||||
// Turn off PA
|
||||
digitalWrite(P_LORA_PA_POWER, LOW);
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
loRaFEMControl.setRxModeEnableWhenMCUSleep();//It also needs to be enabled in receive mode
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void HeltecTrackerV2Board::powerOff() {
|
||||
enterDeepSleep(0);
|
||||
ESP32Board::powerOff();
|
||||
}
|
||||
|
||||
uint16_t HeltecTrackerV2Board::getBattMilliVolts() {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <driver/rtc_io.h>
|
||||
#include "LoRaFEMControl.h"
|
||||
|
||||
class HeltecTrackerV2Board : public ESP32Board {
|
||||
@@ -17,7 +16,6 @@ public:
|
||||
void begin();
|
||||
void onBeforeTransmit(void) override;
|
||||
void onAfterTransmit(void) override;
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||
void powerOff() override;
|
||||
uint16_t getBattMilliVolts() override;
|
||||
const char* getManufacturerName() const override ;
|
||||
|
||||
@@ -55,7 +55,7 @@ build_src_filter = ${esp32_base.build_src_filter}
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
${sensor_base.lib_deps}
|
||||
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
|
||||
bodmer/TFT_eSPI @ ^2.4.31
|
||||
|
||||
[env:heltec_tracker_v2_repeater]
|
||||
extends = Heltec_tracker_v2
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#define PIN_VBAT_READ 37
|
||||
#define PIN_LED_BUILTIN 25
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecV2Board : public ESP32Board {
|
||||
public:
|
||||
void begin() {
|
||||
@@ -26,29 +24,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_0, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_0);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_0), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_0) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
analogReadResolution(10);
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#define PIN_ADC_CTRL_ACTIVE LOW
|
||||
#define PIN_ADC_CTRL_INACTIVE HIGH
|
||||
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class HeltecV3Board : public ESP32Board {
|
||||
private:
|
||||
bool adc_active_state;
|
||||
@@ -52,33 +50,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
analogReadResolution(10);
|
||||
digitalWrite(PIN_ADC_CTRL, adc_active_state);
|
||||
|
||||
@@ -32,33 +32,12 @@ void HeltecV4Board::begin() {
|
||||
loRaFEMControl.setRxModeEnable();
|
||||
}
|
||||
|
||||
void HeltecV4Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
void HeltecV4Board::powerOff() {
|
||||
// Turn off PA
|
||||
digitalWrite(P_LORA_PA_POWER, LOW);
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
loRaFEMControl.setRxModeEnableWhenMCUSleep();//It also needs to be enabled in receive mode
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
void HeltecV4Board::powerOff() {
|
||||
enterDeepSleep(0);
|
||||
ESP32Board::powerOff();
|
||||
}
|
||||
|
||||
uint16_t HeltecV4Board::getBattMilliVolts() {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <helpers/RefCountedDigitalPin.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <driver/rtc_io.h>
|
||||
#include "LoRaFEMControl.h"
|
||||
|
||||
#ifndef ADC_MULTIPLIER
|
||||
@@ -23,7 +22,6 @@ public:
|
||||
void begin();
|
||||
void onBeforeTransmit(void) override;
|
||||
void onAfterTransmit(void) override;
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
|
||||
void powerOff() override;
|
||||
bool setLoRaFemLnaEnabled(bool enable) override;
|
||||
bool canControlLoRaFemLna() const override;
|
||||
|
||||
@@ -37,8 +37,4 @@ public:
|
||||
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
void powerOff() override {
|
||||
sd_power_system_off();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,8 +21,8 @@ build_flags =
|
||||
-D RADIO_CLASS=CustomSX1276
|
||||
-D WRAPPER_CLASS=CustomSX1276Wrapper
|
||||
-D SX127X_CURRENT_LIMIT=120
|
||||
-D SX176X_RXEN=21
|
||||
-D SX176X_TXEN=10
|
||||
-D SX127X_RXEN=21
|
||||
-D SX127X_TXEN=10
|
||||
-D LORA_TX_POWER=20
|
||||
build_src_filter = ${esp32_base.build_src_filter}
|
||||
+<../variants/lilygo_t3s3_sx1276>
|
||||
|
||||
@@ -48,12 +48,10 @@ public:
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
// power off system
|
||||
NRF52Board::powerOff();
|
||||
|
||||
// turn off 3.3v
|
||||
digitalWrite(RT9080_EN, LOW);
|
||||
|
||||
// power off system
|
||||
sd_power_system_off();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <Wire.h>
|
||||
#include <Arduino.h>
|
||||
#include "helpers/ESP32Board.h"
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
#define PIN_VBAT_READ 4
|
||||
#define BATTERY_SAMPLES 8
|
||||
@@ -23,29 +22,6 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
|
||||
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
if (pin_wake_btn < 0) {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
|
||||
} else {
|
||||
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
|
||||
}
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
// Finally set ESP32 into sleep
|
||||
esp_deep_sleep_start(); // CPU halts here and never returns!
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() {
|
||||
#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER)
|
||||
analogReadResolution(12);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user