mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-30 22:50:57 +00:00
Compare commits
23 Commits
v2.6.12.98
...
v2.6.13.05
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12680ad9cd | ||
|
|
0561f2ca4b | ||
|
|
58743021c8 | ||
|
|
2fb46ce5d5 | ||
|
|
8be76a56c7 | ||
|
|
2c206febab | ||
|
|
db1eac12af | ||
|
|
56e67cb434 | ||
|
|
e9d5e36738 | ||
|
|
f71fdef3fd | ||
|
|
5e92145324 | ||
|
|
89a4589b68 | ||
|
|
20991d8b53 | ||
|
|
3ab9005b2f | ||
|
|
aabc5b7cf2 | ||
|
|
afcd97c154 | ||
|
|
cbdd7eae70 | ||
|
|
6374ffea35 | ||
|
|
1a6bb97f16 | ||
|
|
4f0b95e910 | ||
|
|
a81b41cbfb | ||
|
|
465fe18a89 | ||
|
|
bd0e25f3f5 |
2
.github/workflows/daily_packaging.yml
vendored
2
.github/workflows/daily_packaging.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Daily Packaging
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 9 * * *
|
||||
- cron: 0 2 * * *
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
|
||||
@@ -8,15 +8,15 @@ plugins:
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.440
|
||||
- renovate@40.51.0
|
||||
- checkov@3.2.442
|
||||
- renovate@40.60.3
|
||||
- prettier@3.5.3
|
||||
- trufflehog@3.89.1
|
||||
- trufflehog@3.89.2
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.8.3
|
||||
- bandit@1.8.5
|
||||
- trivy@0.63.0
|
||||
- taplo@0.9.3
|
||||
- ruff@0.11.13
|
||||
- ruff@0.12.0
|
||||
- isort@6.0.1
|
||||
- markdownlint@0.45.0
|
||||
- oxipng@9.1.5
|
||||
|
||||
@@ -37,3 +37,4 @@ Join our community and help improve Meshtastic! 🚀
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="2.6.13" date="2025-06-16">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.13</url>
|
||||
</release>
|
||||
<release version="2.6.12" date="2025-06-15">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.12</url>
|
||||
</release>
|
||||
|
||||
7
debian/changelog
vendored
7
debian/changelog
vendored
@@ -1,4 +1,4 @@
|
||||
meshtasticd (2.6.11.0) UNRELEASED; urgency=medium
|
||||
meshtasticd (2.6.13.0) UNRELEASED; urgency=medium
|
||||
|
||||
[ Austin Lane ]
|
||||
* Initial packaging
|
||||
@@ -19,4 +19,7 @@ meshtasticd (2.6.11.0) UNRELEASED; urgency=medium
|
||||
[ ]
|
||||
* GitHub Actions Automatic version bump
|
||||
|
||||
-- <github-actions[bot]@users.noreply.github.com> Mon, 02 Jun 2025 20:00:55 +0000
|
||||
[ ]
|
||||
* GitHub Actions Automatic version bump
|
||||
|
||||
-- <github-actions[bot]@users.noreply.github.com> Mon, 16 Jun 2025 02:10:49 +0000
|
||||
|
||||
Submodule protobufs updated: c758376d04...b818a000ef
@@ -81,7 +81,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// #define REGULATORY_LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923
|
||||
|
||||
// Total system gain in dBm to subtract from Tx power to remain within regulatory and Tx PA limits
|
||||
// This value should be set in variant.h and is PA gain + antenna gain (if variant has a non-removable antenna)
|
||||
// The value consists of PA gain + antenna gain (if variant has a non-removable antenna)
|
||||
// TX_GAIN_LORA should be set with definitions below for common modules, or in variant.h.
|
||||
|
||||
// Gain for common modules with transmit PAs
|
||||
#ifdef EBYTE_E22_900M30S
|
||||
// 10dB PA gain and 30dB rated output; based on measurements from
|
||||
// https://github.com/S5NC/EBYTE_ESP32-S3/blob/main/E22-900M30S%20power%20output%20testing.txt
|
||||
#define TX_GAIN_LORA 7
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
#ifdef EBYTE_E22_900M33S
|
||||
// 25dB PA gain and 33dB rated output; based on TX Power Curve from E22-900M33S_UserManual_EN_v1.0.pdf
|
||||
#define TX_GAIN_LORA 25
|
||||
#define SX126X_MAX_POWER 8
|
||||
#endif
|
||||
|
||||
#ifdef NICERF_MINIF27
|
||||
// Note that datasheet power level of 9 corresponds with SX1262 at 22dBm
|
||||
// Maximum output power of 29dBm with VCC_PA = 5V
|
||||
#define TX_GAIN_LORA 7
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
#ifdef NICERF_F30_HF
|
||||
// Maximum output power of 29.6dBm with VCC = 5V and SX1262 at 22dBm
|
||||
#define TX_GAIN_LORA 8
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
#ifdef NICERF_F30_LF
|
||||
// Maximum output power of 32.0dBm with VCC = 5V and SX1262 at 22dBm
|
||||
#define TX_GAIN_LORA 10
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
// Default system gain to 0 if not defined
|
||||
#ifndef TX_GAIN_LORA
|
||||
#define TX_GAIN_LORA 0
|
||||
#endif
|
||||
@@ -193,6 +229,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// -----------------------------------------------------------------------------
|
||||
#define FT6336U_ADDR 0x48
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
|
||||
// - the default i2c address for this sensor is 0x20, and users are instructed to
|
||||
// set 0x21 and 0x22 for the second and third sensor if present.
|
||||
// -----------------------------------------------------------------------------
|
||||
#define RAK120351_ADDR 0x20
|
||||
#define RAK120352_ADDR 0x21
|
||||
#define RAK120353_ADDR 0x22
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BIAS-T Generator
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -70,6 +70,7 @@ class ScanI2C
|
||||
DFROBOT_RAIN,
|
||||
DPS310,
|
||||
LTR390UV,
|
||||
RAK12035,
|
||||
TCA8418KB,
|
||||
PCT2075,
|
||||
} DeviceType;
|
||||
|
||||
@@ -358,7 +358,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
||||
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
|
||||
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c) {
|
||||
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c || registerValue == 0xc8d) {
|
||||
type = SHT4X;
|
||||
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
||||
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
||||
@@ -423,9 +423,21 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
logFoundDevice("BMA423", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
case TCA9535_ADDR:
|
||||
case RAK120352_ADDR:
|
||||
case RAK120353_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1);
|
||||
if (registerValue == addr.address) { // RAK12035 returns its I2C address at 0x02 (eg 0x20)
|
||||
type = RAK12035;
|
||||
logFoundDevice("RAK12035", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = TCA9535;
|
||||
logFoundDevice("TCA9535", (uint8_t)addr.address);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "RTC.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#include "sleep.h"
|
||||
|
||||
@@ -37,6 +38,10 @@ void InkHUD::Events::begin()
|
||||
|
||||
void InkHUD::Events::onButtonShort()
|
||||
{
|
||||
// Cancel any beeping, buzzing, blinking
|
||||
// Some button handling suppressed if we are dismissing an external notification (see below)
|
||||
bool dismissedExt = dismissExternalNotification();
|
||||
|
||||
// Check which system applet wants to handle the button press (if any)
|
||||
SystemApplet *consumer = nullptr;
|
||||
for (SystemApplet *sa : inkhud->systemApplets) {
|
||||
@@ -49,7 +54,7 @@ void InkHUD::Events::onButtonShort()
|
||||
// If no system applet is handling input, default behavior instead is to cycle applets
|
||||
if (consumer)
|
||||
consumer->onButtonShortPress();
|
||||
else
|
||||
else if (!dismissedExt) // Don't change applet if this button press silenced the external notification module
|
||||
inkhud->nextApplet();
|
||||
}
|
||||
|
||||
@@ -204,4 +209,24 @@ int InkHUD::Events::beforeLightSleep(void *unused)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Silence all ongoing beeping, blinking, buzzing, coming from the external notification module
|
||||
// Returns true if an external notification was active, and we dismissed it
|
||||
// Button handling changes depending on our result
|
||||
bool InkHUD::Events::dismissExternalNotification()
|
||||
{
|
||||
// Abort if not using external notifications
|
||||
if (!moduleConfig.external_notification.enabled)
|
||||
return false;
|
||||
|
||||
// Abort if nothing to dismiss
|
||||
if (!externalNotificationModule->nagging())
|
||||
return false;
|
||||
|
||||
// Stop the beep buzz blink
|
||||
externalNotificationModule->stopNow();
|
||||
|
||||
// Inform that we did indeed dismiss an external notification
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -62,6 +62,9 @@ class Events
|
||||
CallbackObserver<Events, void *> lightSleepObserver = CallbackObserver<Events, void *>(this, &Events::beforeLightSleep);
|
||||
#endif
|
||||
|
||||
// End any externalNotification beeping, buzzing, blinking etc
|
||||
bool dismissExternalNotification();
|
||||
|
||||
// If set, InkHUD's data will be erased during onReboot
|
||||
bool eraseOnReboot = false;
|
||||
};
|
||||
|
||||
@@ -729,6 +729,7 @@ void setup()
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN, meshtastic_TelemetrySensorType_DFROBOT_RAIN);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LTR390UV, meshtastic_TelemetrySensorType_LTR390UV);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DPS310, meshtastic_TelemetrySensorType_DPS310);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||
|
||||
i2cScanner.reset();
|
||||
|
||||
@@ -7,152 +7,377 @@
|
||||
#endif
|
||||
#include "Throttle.h"
|
||||
|
||||
PacketHistory::PacketHistory()
|
||||
#define PACKETHISTORY_MAX \
|
||||
max((int)(MAX_NUM_NODES * 2.0), 100) // x2..3 Should suffice. Empirical setup. 16B per record malloc'ed, but no less than 100
|
||||
|
||||
#define RECENT_WARN_AGE (10 * 60 * 1000L) // Warn if the packet that gets removed was more recent than 10 min
|
||||
|
||||
#define VERBOSE_PACKET_HISTORY 0 // Set to 1 for verbose logging, 2 for heavy debugging
|
||||
#define PACKET_HISTORY_TRACE_AGING 1 // Set to 1 to enable logging of the age of re/used history slots
|
||||
|
||||
PacketHistory::PacketHistory(uint32_t size) : recentPacketsCapacity(0), recentPackets(NULL) // Initialize members
|
||||
{
|
||||
recentPackets.reserve(MAX_NUM_NODES); // Prealloc the worst case # of records - to prevent heap fragmentation
|
||||
// setup our periodic task
|
||||
if (size < 4 || size > PACKETHISTORY_MAX) { // Copilot suggested - makes sense
|
||||
LOG_WARN("Packet History - Invalid size %d, using default %d", size, PACKETHISTORY_MAX);
|
||||
size = PACKETHISTORY_MAX; // Use default size if invalid
|
||||
}
|
||||
|
||||
// Allocate memory for the recent packets array
|
||||
recentPacketsCapacity = size;
|
||||
recentPackets = new PacketRecord[recentPacketsCapacity];
|
||||
if (!recentPackets) { // No logging here, console/log probably uninitialized yet.
|
||||
LOG_ERROR("Packet History - Memory allocation failed for size=%d entries / %d Bytes", size,
|
||||
sizeof(PacketRecord) * recentPacketsCapacity);
|
||||
recentPacketsCapacity = 0; // mark allocation fail
|
||||
return; // return early
|
||||
}
|
||||
|
||||
// Initialize the recent packets array to zero
|
||||
memset(recentPackets, 0, sizeof(PacketRecord) * recentPacketsCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update recentBroadcasts and return true if we have already seen this packet
|
||||
*/
|
||||
PacketHistory::~PacketHistory()
|
||||
{
|
||||
recentPacketsCapacity = 0;
|
||||
delete[] recentPackets;
|
||||
recentPackets = NULL;
|
||||
}
|
||||
|
||||
/** Update recentPackets and return true if we have already seen this packet */
|
||||
bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate, bool *wasFallback, bool *weWereNextHop)
|
||||
{
|
||||
if (!initOk()) {
|
||||
LOG_ERROR("Packet History - Was Seen Recently: NOT INITIALIZED!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p->id == 0) {
|
||||
LOG_DEBUG("Ignore message with zero id");
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: ID is 0, not a floodable message");
|
||||
#endif
|
||||
return false; // Not a floodable message ID, so we don't care
|
||||
}
|
||||
|
||||
PacketRecord r;
|
||||
memset(&r, 0, sizeof(PacketRecord)); // Initialize the record to zero
|
||||
|
||||
// Save basic info from checked packet
|
||||
r.id = p->id;
|
||||
r.sender = getFrom(p);
|
||||
r.rxTimeMsec = millis();
|
||||
r.sender = getFrom(p); // If 0 then use our ID
|
||||
r.next_hop = p->next_hop;
|
||||
r.relayed_by[0] = p->relay_node;
|
||||
// LOG_INFO("Add relayed_by 0x%x for id=0x%x", p->relay_node, r.id);
|
||||
|
||||
auto found = recentPackets.find(r);
|
||||
bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently
|
||||
r.rxTimeMsec = millis(); //
|
||||
if (r.rxTimeMsec == 0) // =0 every 49.7 days? 0 is special
|
||||
r.rxTimeMsec = 1;
|
||||
|
||||
if (seenRecently &&
|
||||
!Throttle::isWithinTimespanMs(found->rxTimeMsec, FLOOD_EXPIRE_TIME)) { // Check whether found packet has already expired
|
||||
recentPackets.erase(found); // Erase and pretend packet has not been seen recently
|
||||
found = recentPackets.end();
|
||||
seenRecently = false;
|
||||
}
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: @start s=%08x id=%08x / to=%08x nh=%02x rn=%02x / wUpd=%s / wasFb?%d wWNH?%d",
|
||||
r.sender, r.id, p->to, p->next_hop, p->relay_node, withUpdate ? "YES" : "NO", wasFallback ? *wasFallback : -1,
|
||||
weWereNextHop ? *weWereNextHop : -1);
|
||||
#endif
|
||||
|
||||
PacketRecord *found = find(r.sender, r.id); // Find the packet record in the recentPackets array
|
||||
bool seenRecently = (found != NULL); // If found -> the packet was seen recently
|
||||
|
||||
if (seenRecently) {
|
||||
LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x", p->from, p->to, p->id);
|
||||
uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum());
|
||||
uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); // Get our relay ID from our node number
|
||||
|
||||
if (wasFallback) {
|
||||
// If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already
|
||||
// before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, we might need to handle
|
||||
// it now.
|
||||
if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE &&
|
||||
found->next_hop != ourRelayID && p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, found) &&
|
||||
!wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) {
|
||||
found->next_hop != ourRelayID && p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, *found) &&
|
||||
!wasRelayer(ourRelayID, *found) &&
|
||||
!wasRelayer(
|
||||
found->next_hop,
|
||||
*found)) { // If we were not the next hop and the next hop is not us, and we are not relaying this packet
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: f=%08x id=%08x nh=%02x rn=%02x oID=%02x, wasFbk=%d-set TRUE",
|
||||
p->from, p->id, p->next_hop, p->relay_node, ourRelayID, wasFallback ? *wasFallback : -1);
|
||||
#endif
|
||||
*wasFallback = true;
|
||||
} else {
|
||||
// debug log only
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: f=%08x id=%08x nh=%02x rn=%02x oID=%02x, wasFbk=%d-no change",
|
||||
p->from, p->id, p->next_hop, p->relay_node, ourRelayID, wasFallback ? *wasFallback : -1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we were the next hop for this packet
|
||||
if (weWereNextHop) {
|
||||
*weWereNextHop = found->next_hop == ourRelayID;
|
||||
*weWereNextHop = (found->next_hop == ourRelayID);
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: f=%08x id=%08x nh=%02x rn=%02x foundnh=%02x oID=%02x -> wWNH=%s",
|
||||
p->from, p->id, p->next_hop, p->relay_node, found->next_hop, ourRelayID, (*weWereNextHop) ? "YES" : "NO");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (withUpdate) {
|
||||
if (found != recentPackets.end()) { // delete existing to updated timestamp and relayed_by (re-insert)
|
||||
if (found != NULL) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: s=%08x id=%08x nh=%02x rby=%02x %02x %02x age=%d wUpd BEFORE",
|
||||
found->sender, found->id, found->next_hop, found->relayed_by[0], found->relayed_by[1], found->relayed_by[2],
|
||||
millis() - found->rxTimeMsec);
|
||||
#endif
|
||||
|
||||
// Add the existing relayed_by to the new record
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS - 1; i++) {
|
||||
if (found->relayed_by[i])
|
||||
for (uint8_t i = 0; i < (NUM_RELAYERS - 1); i++) {
|
||||
if (found->relayed_by[i] != 0)
|
||||
r.relayed_by[i + 1] = found->relayed_by[i];
|
||||
}
|
||||
r.next_hop = found->next_hop; // keep the original next_hop (such that we check whether we were originally asked)
|
||||
recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..)
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: s=%08x id=%08x nh=%02x rby=%02x %02x %02x age=%d wUpd AFTER", r.sender,
|
||||
r.id, r.next_hop, r.relayed_by[0], r.relayed_by[1], r.relayed_by[2], millis() - r.rxTimeMsec);
|
||||
#endif
|
||||
// TODO: have direct *found entry - can modify directly without local copy _vs_ not convolute the code by this
|
||||
}
|
||||
recentPackets.insert(r);
|
||||
LOG_DEBUG("Add packet record fr=0x%x, id=0x%x", p->from, p->id);
|
||||
}
|
||||
|
||||
// Capacity is reerved, so only purge expired packets if recentPackets fills past 90% capacity
|
||||
// Expiry is normally dealt with after having searched/found a packet (above)
|
||||
if (recentPackets.size() > (MAX_NUM_NODES * 0.9)) {
|
||||
clearExpiredRecentPackets();
|
||||
insert(r); // Insert or update the packet record in the history
|
||||
}
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - Was Seen Recently: @exit s=%08x id=%08x (to=%08x) relby=%02x %02x %02x nxthop=%02x rxT=%d "
|
||||
"found?%s seenRecently?%s wUpd?%s",
|
||||
r.sender, r.id, p->to, r.relayed_by[0], r.relayed_by[1], r.relayed_by[2], r.next_hop, r.rxTimeMsec,
|
||||
found ? "YES" : "NO ", seenRecently ? "YES" : "NO ", withUpdate ? "YES" : "NO ");
|
||||
#endif
|
||||
|
||||
return seenRecently;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all recent packets, and remove all older than FLOOD_EXPIRE_TIME
|
||||
*/
|
||||
void PacketHistory::clearExpiredRecentPackets()
|
||||
/** Find a packet record in history.
|
||||
* @return pointer to PacketRecord if found, NULL if not found */
|
||||
PacketHistory::PacketRecord *PacketHistory::find(NodeNum sender, PacketId id)
|
||||
{
|
||||
LOG_DEBUG("recentPackets size=%ld", recentPackets.size());
|
||||
if (sender == 0 || id == 0) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - find: s=%08x id=%08x sender/id=0->NOT FOUND", sender, id);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (auto it = recentPackets.begin(); it != recentPackets.end();) {
|
||||
if (!Throttle::isWithinTimespanMs(it->rxTimeMsec, FLOOD_EXPIRE_TIME)) {
|
||||
it = recentPackets.erase(it); // erase returns iterator pointing to element immediately following the one erased
|
||||
} else {
|
||||
++it;
|
||||
PacketRecord *it = NULL;
|
||||
for (it = recentPackets; it < (recentPackets + recentPacketsCapacity); ++it) {
|
||||
if (it->id == id && it->sender == sender) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - find: s=%08x id=%08x FOUND nh=%02x rby=%02x %02x %02x age=%d slot=%d/%d", it->sender,
|
||||
it->id, it->next_hop, it->relayed_by[0], it->relayed_by[1], it->relayed_by[2], millis() - (it->rxTimeMsec),
|
||||
it - recentPackets, recentPacketsCapacity);
|
||||
#endif
|
||||
// only the first match is returned, so be careful not to create duplicate entries
|
||||
return it; // Return pointer to the found record
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("recentPackets size=%ld (after clearing expired packets)", recentPackets.size());
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - find: s=%08x id=%08x NOT FOUND", sender, id);
|
||||
#endif
|
||||
return NULL; // Not found
|
||||
}
|
||||
|
||||
/** Insert/Replace oldest PacketRecord in recentPackets. */
|
||||
void PacketHistory::insert(PacketRecord &r)
|
||||
{
|
||||
uint32_t now_millis = millis(); // Should not jump with time changes
|
||||
uint32_t OldtrxTimeMsec = 0;
|
||||
PacketRecord *tu = NULL; // Will insert here.
|
||||
PacketRecord *it = NULL;
|
||||
|
||||
// Find a free, matching or oldest used slot in the recentPackets array
|
||||
for (it = recentPackets; it < (recentPackets + recentPacketsCapacity); ++it) {
|
||||
if (it->id == 0 && it->sender == 0 /*&& rxTimeMsec == 0*/) { // Record is empty
|
||||
tu = it; // Remember the free slot
|
||||
#if VERBOSE_PACKET_HISTORY >= 2
|
||||
LOG_DEBUG("Packet History - insert: Free slot@ %d/%d", tu - recentPackets, recentPacketsCapacity);
|
||||
#endif
|
||||
// We have that, Exit the loop
|
||||
it = (recentPackets + recentPacketsCapacity);
|
||||
} else if (it->id == r.id && it->sender == r.sender) { // Record matches the packet we want to insert
|
||||
tu = it; // Remember the matching slot
|
||||
OldtrxTimeMsec = now_millis - it->rxTimeMsec; // ..and save current entry's age
|
||||
#if VERBOSE_PACKET_HISTORY >= 2
|
||||
LOG_DEBUG("Packet History - insert: Matched slot@ %d/%d age=%d", tu - recentPackets, recentPacketsCapacity,
|
||||
OldtrxTimeMsec);
|
||||
#endif
|
||||
// We have that, Exit the loop
|
||||
it = (recentPackets + recentPacketsCapacity);
|
||||
} else {
|
||||
if (it->rxTimeMsec == 0) {
|
||||
LOG_WARN(
|
||||
"Packet History - insert: Found packet s=%08x id=%08x with rxTimeMsec = 0, slot %d/%d. Should never happen!",
|
||||
it->sender, it->id, it - recentPackets, recentPacketsCapacity);
|
||||
}
|
||||
if ((now_millis - it->rxTimeMsec) > OldtrxTimeMsec) { // 49.7 days rollover friendly
|
||||
OldtrxTimeMsec = now_millis - it->rxTimeMsec;
|
||||
tu = it; // remember the oldest packet
|
||||
#if VERBOSE_PACKET_HISTORY >= 2
|
||||
LOG_DEBUG("Packet History - insert: Older slot@ %d/%d age=%d", tu - recentPackets, recentPacketsCapacity,
|
||||
OldtrxTimeMsec);
|
||||
#endif
|
||||
}
|
||||
// keep looking for oldest till entire array is checked
|
||||
}
|
||||
}
|
||||
|
||||
if (tu == NULL) {
|
||||
LOG_ERROR("Packet History - insert: No free slot, no matched packet, no oldest to reuse. Something leaked."); // mx
|
||||
// assert(false); // This should never happen, we should always have at least one packet to clear
|
||||
return; // Return early if we can't update the history
|
||||
}
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
if (tu->id == 0 && tu->sender == 0) {
|
||||
LOG_DEBUG("Packet History - insert: slot@ %d/%d is NEW", tu - recentPackets, recentPacketsCapacity);
|
||||
} else if (tu->id == r.id && tu->sender == r.sender) {
|
||||
LOG_DEBUG("Packet History - insert: slot@ %d/%d MATCHED, age=%d", tu - recentPackets, recentPacketsCapacity,
|
||||
OldtrxTimeMsec);
|
||||
} else {
|
||||
LOG_DEBUG("Packet History - insert: slot@ %d/%d REUSE OLDEST, age=%d", tu - recentPackets, recentPacketsCapacity,
|
||||
OldtrxTimeMsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we are reusing a slot, we should warn if the packet is too recent
|
||||
#if RECENT_WARN_AGE > 0
|
||||
if (tu->rxTimeMsec && (OldtrxTimeMsec < RECENT_WARN_AGE)) {
|
||||
if (!(tu->id == r.id && tu->sender == r.sender)) {
|
||||
LOG_WARN("Packet History - insert: Reusing slot aged %ds < %ds RECENT_WARN_AGE", OldtrxTimeMsec / 1000,
|
||||
RECENT_WARN_AGE / 1000);
|
||||
} else {
|
||||
// debug only
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_WARN("Packet History - insert: Reusing slot aged %.3fs < %ds with MATCHED PACKET - this is normal",
|
||||
OldtrxTimeMsec / 1000., RECENT_WARN_AGE / 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if PACKET_HISTORY_TRACE_AGING
|
||||
if (tu->rxTimeMsec != 0) {
|
||||
LOG_INFO("Packet History - insert: Reusing slot aged %.3fs TRACE %s", OldtrxTimeMsec / 1000.,
|
||||
(tu->id == r.id && tu->sender == r.sender) ? "MATCHED PACKET" : "OLDEST SLOT");
|
||||
} else {
|
||||
LOG_INFO("Packet History - insert: Using new slot @uptime %.3fs TRACE NEW", millis() / 1000.);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - insert: Store slot@ %d/%d s=%08x id=%08x nh=%02x rby=%02x %02x %02x rxT=%d BEFORE",
|
||||
tu - recentPackets, recentPacketsCapacity, tu->sender, tu->id, tu->next_hop, tu->relayed_by[0], tu->relayed_by[1],
|
||||
tu->relayed_by[2], tu->rxTimeMsec);
|
||||
#endif
|
||||
|
||||
if (r.rxTimeMsec == 0) {
|
||||
LOG_WARN("Packet History - insert: I will not store packet with rxTimeMsec = 0.");
|
||||
return; // Return early if we can't update the history
|
||||
}
|
||||
|
||||
*tu = r; // store the packet
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - insert: Store slot@ %d/%d s=%08x id=%08x nh=%02x rby=%02x %02x %02x rxT=%d AFTER",
|
||||
tu - recentPackets, recentPacketsCapacity, tu->sender, tu->id, tu->next_hop, tu->relayed_by[0], tu->relayed_by[1],
|
||||
tu->relayed_by[2], tu->rxTimeMsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
{
|
||||
if (relayer == 0)
|
||||
return false;
|
||||
|
||||
PacketRecord r = {.sender = sender, .id = id, .rxTimeMsec = 0, .next_hop = 0};
|
||||
auto found = recentPackets.find(r);
|
||||
|
||||
if (found == recentPackets.end()) {
|
||||
if (!initOk()) {
|
||||
LOG_ERROR("PacketHistory - wasRelayer: NOT INITIALIZED!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return wasRelayer(relayer, found);
|
||||
if (relayer == 0) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was relayer: s=%08x id=%08x / rl=%02x=zero. NO", sender, id, relayer);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketRecord *found = find(sender, id);
|
||||
|
||||
if (found == NULL) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was relayer: s=%08x id=%08x / rl=%02x / PR not found. NO", sender, id, relayer);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY >= 2
|
||||
LOG_DEBUG("Packet History - was relayer: s=%08x id=%08x nh=%02x age=%d rls=%02x %02x %02x InHistory,check:%02x",
|
||||
found->sender, found->id, found->next_hop, millis() - found->rxTimeMsec, found->relayed_by[0], found->relayed_by[1],
|
||||
found->relayed_by[2], relayer);
|
||||
#endif
|
||||
return wasRelayer(relayer, *found);
|
||||
}
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, std::unordered_set<PacketRecord, PacketRecordHashFunction>::iterator r)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, PacketRecord &r)
|
||||
{
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
|
||||
if (r->relayed_by[i] == relayer) {
|
||||
if (r.relayed_by[i] == relayer) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? YES", r.sender, r.id,
|
||||
r.relayed_by[0], r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? NO", r.sender, r.id, r.relayed_by[0],
|
||||
r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
void PacketHistory::removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
{
|
||||
PacketRecord r = {.sender = sender, .id = id, .rxTimeMsec = 0, .next_hop = 0};
|
||||
auto found = recentPackets.find(r);
|
||||
|
||||
if (found == recentPackets.end()) {
|
||||
if (!initOk()) {
|
||||
LOG_ERROR("Packet History - remove Relayer: NOT INITIALIZED!");
|
||||
return;
|
||||
}
|
||||
// Make a copy of the found record
|
||||
r.next_hop = found->next_hop;
|
||||
r.rxTimeMsec = found->rxTimeMsec;
|
||||
|
||||
// Only add the relayers that are not the one we want to remove
|
||||
uint8_t j = 0;
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
|
||||
if (found->relayed_by[i] != relayer) {
|
||||
r.relayed_by[j] = found->relayed_by[i];
|
||||
j++;
|
||||
}
|
||||
PacketRecord *found = find(sender, id);
|
||||
if (found == NULL) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - remove Relayer s=%08x id=%08x (rl=%02x) NOT FOUND", sender, id, relayer);
|
||||
#endif
|
||||
return; // Nothing to remove
|
||||
}
|
||||
|
||||
recentPackets.erase(found);
|
||||
recentPackets.insert(r);
|
||||
}
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - remove Relayer s=%08x id=%08x rby=%02x %02x %02x, rl:%02x BEFORE", found->sender, found->id,
|
||||
found->relayed_by[0], found->relayed_by[1], found->relayed_by[2], relayer);
|
||||
#endif
|
||||
|
||||
// nexthop and rxTimeMsec too stay in found entry
|
||||
|
||||
uint8_t j = 0;
|
||||
uint8_t i = 0;
|
||||
for (; i < NUM_RELAYERS; i++) {
|
||||
if (found->relayed_by[i] != relayer) {
|
||||
found->relayed_by[j] = found->relayed_by[i];
|
||||
j++;
|
||||
} else
|
||||
found->relayed_by[i] = 0;
|
||||
}
|
||||
for (; j < NUM_RELAYERS; j++) { // Clear the rest of the relayed_by array
|
||||
found->relayed_by[j] = 0;
|
||||
}
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - remove Relayer s=%08x id=%08x rby=%02x %02x %02x rl:%02x AFTER - removed?%d", found->sender,
|
||||
found->id, found->relayed_by[0], found->relayed_by[1], found->relayed_by[2], relayer, i != j);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,49 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "NodeDB.h"
|
||||
#include <unordered_set>
|
||||
|
||||
/// We clear our old flood record 10 minutes after we see the last of it
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
#define FLOOD_EXPIRE_TIME (5 * 1000L) // Don't allow too many packets to accumulate when fuzzing.
|
||||
#else
|
||||
#define FLOOD_EXPIRE_TIME (10 * 60 * 1000L)
|
||||
#endif
|
||||
|
||||
#define NUM_RELAYERS \
|
||||
3 // Number of relayer we keep track of. Use 3 to be efficient with memory alignment of PacketRecord to 16 bytes
|
||||
|
||||
/**
|
||||
* A record of a recent message broadcast
|
||||
*/
|
||||
struct PacketRecord {
|
||||
NodeNum sender;
|
||||
PacketId id;
|
||||
uint32_t rxTimeMsec; // Unix time in msecs - the time we received it
|
||||
uint8_t next_hop; // The next hop asked for this packet
|
||||
uint8_t relayed_by[NUM_RELAYERS]; // Array of nodes that relayed this packet
|
||||
|
||||
bool operator==(const PacketRecord &p) const { return sender == p.sender && id == p.id; }
|
||||
};
|
||||
|
||||
class PacketRecordHashFunction
|
||||
{
|
||||
public:
|
||||
size_t operator()(const PacketRecord &p) const { return (std::hash<NodeNum>()(p.sender)) ^ (std::hash<PacketId>()(p.id)); }
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a mixin that adds a record of past packets we have seen
|
||||
*/
|
||||
class PacketHistory
|
||||
{
|
||||
private:
|
||||
std::unordered_set<PacketRecord, PacketRecordHashFunction> recentPackets;
|
||||
struct PacketRecord { // A record of a recent message broadcast, no need to be visible outside this class.
|
||||
NodeNum sender;
|
||||
PacketId id;
|
||||
uint32_t rxTimeMsec; // Unix time in msecs - the time we received it, 0 means empty
|
||||
uint8_t next_hop; // The next hop asked for this packet
|
||||
uint8_t relayed_by[NUM_RELAYERS]; // Array of nodes that relayed this packet
|
||||
}; // 4B + 4B + 4B + 1B + 3B = 16B
|
||||
|
||||
void clearExpiredRecentPackets(); // clear all recentPackets older than FLOOD_EXPIRE_TIME
|
||||
uint32_t recentPacketsCapacity =
|
||||
0; // Can be set in constructor, no need to recompile. Used to allocate memory for mx_recentPackets.
|
||||
PacketRecord *recentPackets = NULL; // Simple and fixed in size. Debloat.
|
||||
|
||||
/** Find a packet record in history.
|
||||
* @param sender NodeNum
|
||||
* @param id PacketId
|
||||
* @return pointer to PacketRecord if found, NULL if not found */
|
||||
PacketRecord *find(NodeNum sender, PacketId id);
|
||||
|
||||
/** Insert/Replace oldest PacketRecord in mx_recentPackets.
|
||||
* @param r PacketRecord to insert or replace */
|
||||
void insert(PacketRecord &r); // Insert or replace a packet record in the history
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, PacketRecord &r);
|
||||
|
||||
PacketHistory(const PacketHistory &); // non construction-copyable
|
||||
PacketHistory &operator=(const PacketHistory &); // non copyable
|
||||
public:
|
||||
PacketHistory();
|
||||
explicit PacketHistory(uint32_t size = -1); // Constructor with size parameter, default is PACKETHISTORY_MAX
|
||||
~PacketHistory();
|
||||
|
||||
/**
|
||||
* Update recentBroadcasts and return true if we have already seen this packet
|
||||
@@ -59,10 +57,9 @@ class PacketHistory
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, std::unordered_set<PacketRecord, PacketRecordHashFunction>::iterator r);
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
};
|
||||
|
||||
// To check if the PacketHistory was initialized correctly by constructor
|
||||
bool initOk(void) { return recentPackets != NULL && recentPacketsCapacity != 0; }
|
||||
};
|
||||
|
||||
@@ -283,7 +283,9 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
|
||||
/* Philippines 868mhz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_PH_868 = 20,
|
||||
/* Philippines 915mhz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21
|
||||
meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21,
|
||||
/* Australia / New Zealand 433MHz */
|
||||
meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22
|
||||
} meshtastic_Config_LoRaConfig_RegionCode;
|
||||
|
||||
/* Standard predefined channel settings
|
||||
@@ -679,8 +681,8 @@ extern "C" {
|
||||
#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_PH_915
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_PH_915+1))
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_ANZ_433
|
||||
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ANZ_433+1))
|
||||
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
|
||||
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO
|
||||
|
||||
@@ -46,6 +46,10 @@ uint8_t wifiDisconnectReason = 0;
|
||||
// Stores our hostname
|
||||
char ourHost[16];
|
||||
|
||||
// To replace blocking wifi connect delay with a non-blocking sleep
|
||||
static unsigned long wifiReconnectStartMillis = 0;
|
||||
static bool wifiReconnectPending = false;
|
||||
|
||||
bool APStartupComplete = 0;
|
||||
|
||||
unsigned long lastrun_ntp = 0;
|
||||
@@ -160,17 +164,30 @@ static int32_t reconnectWiFi()
|
||||
#endif
|
||||
LOG_INFO("Reconnecting to WiFi access point %s", wifiName);
|
||||
|
||||
delay(5000);
|
||||
// Start the non-blocking wait for 5 seconds
|
||||
wifiReconnectStartMillis = millis();
|
||||
wifiReconnectPending = true;
|
||||
// Do not attempt to connect yet, wait for the next invocation
|
||||
return 5000; // Schedule next check soon
|
||||
}
|
||||
|
||||
if (!WiFi.isConnected()) {
|
||||
// Check if we are ready to proceed with the WiFi connection after the 5s wait
|
||||
if (wifiReconnectPending) {
|
||||
if (millis() - wifiReconnectStartMillis >= 5000) {
|
||||
if (!WiFi.isConnected()) {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
WiFi.useStaticBuffers(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
WiFi.useStaticBuffers(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
#endif
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
WiFi.begin(wifiName, wifiPsw);
|
||||
}
|
||||
isReconnecting = false;
|
||||
wifiReconnectPending = false;
|
||||
} else {
|
||||
// Still waiting for 5s to elapse
|
||||
return 100; // Check again soon
|
||||
}
|
||||
isReconnecting = false;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_NTP
|
||||
@@ -193,8 +210,6 @@ static int32_t reconnectWiFi()
|
||||
|
||||
if (config.network.wifi_enabled && !WiFi.isConnected()) {
|
||||
#ifdef ARCH_RP2040 // (ESP32 handles this in WiFiEvent)
|
||||
/* If APStartupComplete, but we're not connected, try again.
|
||||
Shouldn't try again before APStartupComplete. */
|
||||
needReconnect = APStartupComplete;
|
||||
#endif
|
||||
return 1000; // check once per second
|
||||
@@ -486,4 +501,4 @@ uint8_t getWifiDisconnectReason()
|
||||
{
|
||||
return wifiDisconnectReason;
|
||||
}
|
||||
#endif
|
||||
#endif // HAS_WIFI
|
||||
@@ -293,6 +293,12 @@ bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||
return externalCurrentState[index];
|
||||
}
|
||||
|
||||
// Allow other firmware components to determine whether a notification is ongoing
|
||||
bool ExternalNotificationModule::nagging()
|
||||
{
|
||||
return isNagging;
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::stopNow()
|
||||
{
|
||||
rtttl::stop();
|
||||
|
||||
@@ -40,6 +40,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
void setMute(bool mute) { isMuted = mute; }
|
||||
bool getMute() { return isMuted; }
|
||||
|
||||
bool nagging();
|
||||
|
||||
void stopNow();
|
||||
|
||||
void handleGetRingtone(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||
|
||||
@@ -265,7 +265,6 @@ meshtastic_MeshPacket *PositionModule::allocPositionPacket()
|
||||
}
|
||||
|
||||
LOG_INFO("Position packet: time=%i lat=%i lon=%i", p.time, p.latitude_i, p.longitude_i);
|
||||
lastSentToMesh = millis();
|
||||
|
||||
// TAK Tracker devices should send their position in a TAK packet over the ATAK port
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)
|
||||
@@ -276,13 +275,18 @@ meshtastic_MeshPacket *PositionModule::allocPositionPacket()
|
||||
|
||||
meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND && lastSentToMesh &&
|
||||
Throttle::isWithinTimespanMs(lastSentToMesh, 3 * 60 * 1000)) {
|
||||
LOG_DEBUG("Skip Position reply since we sent it <3min ago");
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND && lastSentReply &&
|
||||
Throttle::isWithinTimespanMs(lastSentReply, 3 * 60 * 1000)) {
|
||||
LOG_DEBUG("Skip Position reply since we sent a reply <3min ago");
|
||||
ignoreRequest = true; // Mark it as ignored for MeshModule
|
||||
return nullptr;
|
||||
}
|
||||
return allocPositionPacket();
|
||||
|
||||
meshtastic_MeshPacket *reply = allocPositionPacket();
|
||||
if (reply) {
|
||||
lastSentReply = millis(); // Track when we sent this reply
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *PositionModule::allocAtakPli()
|
||||
|
||||
@@ -63,7 +63,7 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
void sendLostAndFoundText();
|
||||
bool hasQualityTimesource();
|
||||
bool hasGPS();
|
||||
uint32_t lastSentToMesh = 0; // Last time we sent our position to the mesh
|
||||
uint32_t lastSentReply = 0; // Last time we sent a position reply (used for reply throttling only)
|
||||
|
||||
const uint32_t minimumTimeThreshold =
|
||||
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
// Sensors
|
||||
|
||||
// Sensors
|
||||
#include "Sensor/CGRadSensSensor.h"
|
||||
#include "Sensor/RCWL9620Sensor.h"
|
||||
#include "Sensor/nullSensor.h"
|
||||
@@ -101,6 +101,13 @@ SHTC3Sensor shtc3Sensor;
|
||||
NullSensor shtc3Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
#include "Sensor/RAK12035Sensor.h"
|
||||
RAK12035Sensor rak12035Sensor;
|
||||
#else
|
||||
NullSensor rak12035Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_VEML7700.h>)
|
||||
#include "Sensor/VEML7700Sensor.h"
|
||||
VEML7700Sensor veml7700Sensor;
|
||||
@@ -173,6 +180,7 @@ NullSensor pct2075Sensor;
|
||||
|
||||
RCWL9620Sensor rcwl9620Sensor;
|
||||
CGRadSensSensor cgRadSens;
|
||||
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
#include "Sensor/T1000xSensor.h"
|
||||
@@ -182,6 +190,7 @@ T1000xSensor t1000xSensor;
|
||||
#include "Sensor/IndicatorSensor.h"
|
||||
IndicatorSensor indicatorSensor;
|
||||
#endif
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
@@ -288,6 +297,11 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
|
||||
result = rak9154Sensor.runOnce();
|
||||
#endif
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
result = rak12035Sensor.runOnce();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// it's possible to have this module enabled, only for displaying values on the screen.
|
||||
@@ -625,6 +639,14 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && rak9154Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#endif
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \
|
||||
RAK_4631 == \
|
||||
1 // Not really needed, but may as well just skip at a lower level it if no library or not a RAK_4631
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
valid = valid && rak12035Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return valid && hasSensor;
|
||||
}
|
||||
@@ -679,6 +701,9 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
|
||||
LOG_INFO("Send: radiation=%fµR/h", m.variant.environment_metrics.radiation);
|
||||
|
||||
LOG_INFO("Send: soil_temperature=%f, soil_moisture=%u", m.variant.environment_metrics.soil_temperature,
|
||||
m.variant.environment_metrics.soil_moisture);
|
||||
|
||||
sensor_read_error_count = 0;
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(m);
|
||||
@@ -850,8 +875,17 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \
|
||||
RAK_4631 == \
|
||||
1 // Not really needed, but may as well just skip it at a lower level if no library or not a RAK_4631
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
result = rak12035Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -29,13 +29,15 @@ bool HostMetricsModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
|
||||
if (t->which_variant == meshtastic_Telemetry_host_metrics_tag) {
|
||||
#ifdef DEBUG_PORT
|
||||
const char *sender = getSenderShortName(mp);
|
||||
if (t->variant.host_metrics.has_user_string)
|
||||
t->variant.host_metrics.user_string[sizeof(t->variant.host_metrics.user_string) - 1] = '\0';
|
||||
|
||||
LOG_INFO("(Received Host Metrics from %s): uptime=%u, diskfree=%lu, memory free=%lu, load=%04.2f, %04.2f, %04.2f, %s",
|
||||
sender, t->variant.host_metrics.uptime_seconds, t->variant.host_metrics.diskfree1_bytes,
|
||||
LOG_INFO("(Received Host Metrics from %s): uptime=%u, diskfree=%lu, memory free=%lu, load=%04.2f, %04.2f, %04.2f", sender,
|
||||
t->variant.host_metrics.uptime_seconds, t->variant.host_metrics.diskfree1_bytes,
|
||||
t->variant.host_metrics.freemem_bytes, static_cast<float>(t->variant.host_metrics.load1) / 100,
|
||||
static_cast<float>(t->variant.host_metrics.load5) / 100,
|
||||
static_cast<float>(t->variant.host_metrics.load15) / 100,
|
||||
t->variant.host_metrics.has_user_string ? t->variant.host_metrics.user_string : "");
|
||||
static_cast<float>(t->variant.host_metrics.load15) / 100);
|
||||
// t->variant.host_metrics.has_user_string ? t->variant.host_metrics.user_string : "");
|
||||
#endif
|
||||
}
|
||||
return false; // Let others look at this message also if they want
|
||||
@@ -111,7 +113,8 @@ meshtastic_Telemetry HostMetricsModule::getHostMetrics()
|
||||
if (settingsStrings[hostMetrics_user_command] != "") {
|
||||
std::string userCommandResult = exec(settingsStrings[hostMetrics_user_command].c_str());
|
||||
if (userCommandResult.length() > 1) {
|
||||
strncpy(t.variant.host_metrics.user_string, userCommandResult.c_str(), 200);
|
||||
strncpy(t.variant.host_metrics.user_string, userCommandResult.c_str(), sizeof(t.variant.host_metrics.user_string));
|
||||
t.variant.host_metrics.user_string[sizeof(t.variant.host_metrics.user_string) - 1] = '\0';
|
||||
t.variant.host_metrics.has_user_string = true;
|
||||
}
|
||||
}
|
||||
@@ -121,12 +124,12 @@ meshtastic_Telemetry HostMetricsModule::getHostMetrics()
|
||||
bool HostMetricsModule::sendMetrics()
|
||||
{
|
||||
meshtastic_Telemetry telemetry = getHostMetrics();
|
||||
LOG_INFO("Send: uptime=%u, diskfree=%lu, memory free=%lu, load=%04.2f, %04.2f, %04.2f %s",
|
||||
LOG_INFO("Send: uptime=%u, diskfree=%lu, memory free=%lu, load=%04.2f, %04.2f, %04.2f",
|
||||
telemetry.variant.host_metrics.uptime_seconds, telemetry.variant.host_metrics.diskfree1_bytes,
|
||||
telemetry.variant.host_metrics.freemem_bytes, static_cast<float>(telemetry.variant.host_metrics.load1) / 100,
|
||||
static_cast<float>(telemetry.variant.host_metrics.load5) / 100,
|
||||
static_cast<float>(telemetry.variant.host_metrics.load15) / 100,
|
||||
telemetry.variant.host_metrics.has_user_string ? telemetry.variant.host_metrics.user_string : "");
|
||||
static_cast<float>(telemetry.variant.host_metrics.load15) / 100);
|
||||
// telemetry.variant.host_metrics.has_user_string ? telemetry.variant.host_metrics.user_string : "");
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
@@ -137,4 +140,4 @@ bool HostMetricsModule::sendMetrics()
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
109
src/modules/Telemetry/Sensor/RAK12035Sensor.cpp
Normal file
109
src/modules/Telemetry/Sensor/RAK12035Sensor.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "configuration.h"
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RAK12035Sensor.h"
|
||||
|
||||
RAK12035Sensor::RAK12035Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RAK12035, "RAK12035") {}
|
||||
|
||||
int32_t RAK12035Sensor::runOnce()
|
||||
{
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
// TODO:: check for up to 2 additional sensors and start them if present.
|
||||
sensor.set_sensor_addr(RAK120351_ADDR);
|
||||
delay(100);
|
||||
sensor.begin(nodeTelemetrySensorsMap[sensorType].first);
|
||||
|
||||
// Get sensor firmware version
|
||||
uint8_t data = 0;
|
||||
sensor.get_sensor_version(&data);
|
||||
if (data != 0) {
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
LOG_INFO("RAK12035Sensor Init Succeed \nSensor1 Firmware version: %i, Sensor Name: %s", data, sensorName);
|
||||
status = true;
|
||||
sensor.sensor_sleep();
|
||||
} else {
|
||||
// If we reach here, it means the sensor did not initialize correctly.
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
LOG_ERROR("RAK12035Sensor Init Failed");
|
||||
status = false;
|
||||
}
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void RAK12035Sensor::setup()
|
||||
{
|
||||
// Set the calibration values
|
||||
// Reading the saved calibration values from the sensor.
|
||||
// TODO:: Check for and run calibration check for up to 2 additional sensors if present.
|
||||
uint16_t zero_val = 0;
|
||||
uint16_t hundred_val = 0;
|
||||
uint16_t default_zero_val = 550;
|
||||
uint16_t default_hundred_val = 420;
|
||||
sensor.sensor_on();
|
||||
delay(200);
|
||||
sensor.get_dry_cal(&zero_val);
|
||||
sensor.get_wet_cal(&hundred_val);
|
||||
delay(200);
|
||||
if (zero_val == 0 || zero_val <= hundred_val) {
|
||||
LOG_INFO("Dry calibration value is %d", zero_val);
|
||||
LOG_INFO("Wet calibration value is %d", hundred_val);
|
||||
LOG_INFO("This does not make sense. You can recalibrate this sensor using the calibration sketch included here: "
|
||||
"https://github.com/RAKWireless/RAK12035_SoilMoisture.");
|
||||
LOG_INFO("For now, setting default calibration value for Dry Calibration: %d", default_zero_val);
|
||||
sensor.set_dry_cal(default_zero_val);
|
||||
sensor.get_dry_cal(&zero_val);
|
||||
LOG_INFO("Dry calibration reset complete. New value is %d", zero_val);
|
||||
}
|
||||
if (hundred_val == 0 || hundred_val >= zero_val) {
|
||||
LOG_INFO("Dry calibration value is %d", zero_val);
|
||||
LOG_INFO("Wet calibration value is %d", hundred_val);
|
||||
LOG_INFO("This does not make sense. You can recalibrate this sensor using the calibration sketch included here: "
|
||||
"https://github.com/RAKWireless/RAK12035_SoilMoisture.");
|
||||
LOG_INFO("For now, setting default calibration value for Wet Calibration: %d", default_hundred_val);
|
||||
sensor.set_wet_cal(default_hundred_val);
|
||||
sensor.get_wet_cal(&hundred_val);
|
||||
LOG_INFO("Wet calibration reset complete. New value is %d", hundred_val);
|
||||
}
|
||||
sensor.sensor_sleep();
|
||||
delay(200);
|
||||
LOG_INFO("Dry calibration value is %d", zero_val);
|
||||
LOG_INFO("Wet calibration value is %d", hundred_val);
|
||||
}
|
||||
|
||||
bool RAK12035Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
// TODO:: read and send metrics for up to 2 additional soil monitors if present.
|
||||
// -- how to do this.. this could get a little complex..
|
||||
// ie - 1> we combine them into an average and send that, 2> we send them as separate metrics
|
||||
// ^-- these scenarios would require different handling of the metrics in the receiving end and maybe a setting in the
|
||||
// device ui and an additional proto for that?
|
||||
measurement->variant.environment_metrics.has_soil_temperature = true;
|
||||
measurement->variant.environment_metrics.has_soil_moisture = true;
|
||||
|
||||
uint8_t moisture = 0;
|
||||
uint16_t temp = 0;
|
||||
bool success = false;
|
||||
|
||||
sensor.sensor_on();
|
||||
delay(200);
|
||||
success = sensor.get_sensor_moisture(&moisture);
|
||||
delay(200);
|
||||
success &= sensor.get_sensor_temperature(&temp);
|
||||
delay(200);
|
||||
sensor.sensor_sleep();
|
||||
|
||||
if (success == false) {
|
||||
LOG_ERROR("Failed to read sensor data");
|
||||
return false;
|
||||
}
|
||||
measurement->variant.environment_metrics.soil_temperature = ((float)temp / 10.0f);
|
||||
measurement->variant.environment_metrics.soil_moisture = moisture;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
28
src/modules/Telemetry/Sensor/RAK12035Sensor.h
Normal file
28
src/modules/Telemetry/Sensor/RAK12035Sensor.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<RAK12035_SoilMoisture.h>) && defined(RAK_4631)
|
||||
#ifndef _MT_RAK12035VBSENSOR_H
|
||||
#define _MT_RAK12035VBSENSOR_H
|
||||
#endif
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RAK12035_SoilMoisture.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
class RAK12035Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
RAK12035 sensor;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
RAK12035Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
#endif
|
||||
@@ -41,21 +41,36 @@ void RCWL9620Sensor::begin(TwoWire *wire, uint8_t addr, uint8_t sda, uint8_t scl
|
||||
|
||||
float RCWL9620Sensor::getDistance()
|
||||
{
|
||||
uint32_t data;
|
||||
_wire->beginTransmission(_addr); // Transfer data to addr.
|
||||
_wire->write(0x01);
|
||||
_wire->endTransmission(); // Stop data transmission with the Ultrasonic
|
||||
// Unit.
|
||||
uint32_t data = 0;
|
||||
uint8_t b1 = 0, b2 = 0, b3 = 0;
|
||||
|
||||
_wire->requestFrom(_addr,
|
||||
(uint8_t)3); // Request 3 bytes from Ultrasonic Unit.
|
||||
LOG_DEBUG("[RCWL9620] Start measure command");
|
||||
|
||||
_wire->beginTransmission(_addr);
|
||||
_wire->write(0x01); // À tester aussi sans cette ligne si besoin
|
||||
uint8_t result = _wire->endTransmission();
|
||||
LOG_DEBUG("[RCWL9620] endTransmission result = %d", result);
|
||||
delay(100); // délai pour laisser le capteur répondre
|
||||
|
||||
LOG_DEBUG("[RCWL9620] Read i2c data:");
|
||||
_wire->requestFrom(_addr, (uint8_t)3);
|
||||
|
||||
if (_wire->available() < 3) {
|
||||
LOG_DEBUG("[RCWL9620] less than 3 octets !");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
b1 = _wire->read();
|
||||
b2 = _wire->read();
|
||||
b3 = _wire->read();
|
||||
|
||||
data = ((uint32_t)b1 << 16) | ((uint32_t)b2 << 8) | b3;
|
||||
|
||||
float Distance = float(data) / 1000.0;
|
||||
|
||||
LOG_DEBUG("[RCWL9620] Bytes readed = %02X %02X %02X", b1, b2, b3);
|
||||
LOG_DEBUG("[RCWL9620] data=%.2f, level=%.2f", (double)data, (double)Distance);
|
||||
|
||||
data = _wire->read();
|
||||
data <<= 8;
|
||||
data |= _wire->read();
|
||||
data <<= 8;
|
||||
data |= _wire->read();
|
||||
float Distance = float(data) / 1000;
|
||||
if (Distance > 4500.00) {
|
||||
return 4500.00;
|
||||
} else {
|
||||
@@ -63,4 +78,4 @@ float RCWL9620Sensor::getDistance()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -308,6 +308,9 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
nrf_gpio_cfg_default(SCREEN_TOUCH_INT);
|
||||
nrf_gpio_cfg_default(WB_I2C1_SCL);
|
||||
nrf_gpio_cfg_default(WB_I2C1_SDA);
|
||||
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SCL);
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SDA);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MESHLINK
|
||||
|
||||
@@ -89,6 +89,13 @@ extra_scripts =
|
||||
${env.extra_scripts}
|
||||
variants/diy/nrf52_promicro_diy_tcxo/custom_build_tasks.py ; Add to PIO's Project Tasks pane: preset builds for common displays
|
||||
|
||||
; Seeed Xiao BLE: https://www.digikey.com/en/products/detail/seeed-technology-co-ltd/102010448/16652893
|
||||
[env:xiao_ble]
|
||||
extends = env:seeed_xiao_nrf52840_kit
|
||||
board_level = extra
|
||||
build_flags = ${env:seeed_xiao_nrf52840_kit.build_flags} -D PRIVATE_HW -DXIAO_BLE_LEGACY_PINOUT -DEBYTE_E22 -DEBYTE_E22_900M30S
|
||||
build_unflags = -DGPS_L76K
|
||||
|
||||
; Seeed XIAO nRF52840 + XIAO Wio SX1262 DIY
|
||||
[env:seeed-xiao-nrf52840-wio-sx1262]
|
||||
board = xiao_ble_sense
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
extends = esp32s3_base
|
||||
board = lolin_s3_mini
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -D PRIVATE_HW -I variants/nugget_s3_lora
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -D ARDUINO_USB_CDC_ON_BOOT=1 -D PRIVATE_HW -I variants/nugget_s3_lora
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#define I2C_SDA 34 // I2C pins for this board
|
||||
#define I2C_SCL 38
|
||||
#define I2C_SDA 35 // I2C pins for this board
|
||||
#define I2C_SCL 36
|
||||
|
||||
#define USE_SSD1306
|
||||
#define DISPLAY_FLIP_SCREEN
|
||||
|
||||
#define LED_PIN 15 // If defined we will blink this LED
|
||||
|
||||
@@ -8,7 +11,8 @@
|
||||
#define NEOPIXEL_DATA 10 // gpio pin used to send data to the neopixels
|
||||
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
|
||||
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||
// Button A (44), B (43), R (12), U (13), L (11), D (18)
|
||||
#define BUTTON_PIN 44 // If defined, this will be used for user button presses
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
#define USE_RF95
|
||||
|
||||
@@ -18,6 +18,7 @@ lib_deps =
|
||||
melopero/Melopero RV3028@^1.1.0
|
||||
https://github.com/RAKWireless/RAK13800-W5100S/archive/1.0.2.zip
|
||||
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
|
||||
beegee-tokyo/RAK12035_SoilMoisture@^1.0.4
|
||||
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
|
||||
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
@@ -51,4 +52,4 @@ lib_deps =
|
||||
upload_protocol = stlink
|
||||
; eventually use platformio/tool-pyocd@^2.3600.0 instad
|
||||
;upload_protocol = custom
|
||||
;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE
|
||||
;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE
|
||||
|
||||
@@ -88,8 +88,13 @@ static const uint8_t A7 = PIN_A7;
|
||||
#define ADC_RESOLUTION 14
|
||||
|
||||
// Other pins
|
||||
#define WB_I2C1_SDA (13) // SENSOR_SLOT IO_SLOT
|
||||
#define WB_I2C1_SCL (14) // SENSOR_SLOT IO_SLOT
|
||||
|
||||
#define PIN_AREF (2)
|
||||
#define PIN_NFC1 (9)
|
||||
#define WB_IO5 PIN_NFC1
|
||||
#define WB_IO4 (4)
|
||||
#define PIN_NFC2 (10)
|
||||
|
||||
static const uint8_t AREF = PIN_AREF;
|
||||
@@ -143,8 +148,8 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
*/
|
||||
#define WIRE_INTERFACES_COUNT 1
|
||||
|
||||
#define PIN_WIRE_SDA (13)
|
||||
#define PIN_WIRE_SCL (14)
|
||||
#define PIN_WIRE_SDA (WB_I2C1_SDA)
|
||||
#define PIN_WIRE_SCL (WB_I2C1_SCL)
|
||||
|
||||
// QSPI Pins
|
||||
#define PIN_QSPI_SCK 3
|
||||
@@ -227,6 +232,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
||||
// enables 3.3V periphery like GPS or IO Module
|
||||
// Do not toggle this for GPS power savings
|
||||
#define PIN_3V3_EN (34)
|
||||
#define WB_IO2 PIN_3V3_EN
|
||||
|
||||
// RAK1910 GPS module
|
||||
// If using the wisblock GPS module and pluged into Port A on WisBlock base
|
||||
@@ -280,4 +286,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@ lib_deps =
|
||||
melopero/Melopero RV3028@^1.1.0
|
||||
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
|
||||
beegee-tokyo/RAKwireless RAK12034@^1.0.0
|
||||
beegee-tokyo/RAK12035_SoilMoisture@^1.0.4
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
|
||||
@@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7;
|
||||
// Other pins
|
||||
#define PIN_AREF (2)
|
||||
#define PIN_NFC1 (9)
|
||||
#define WB_IO5 PIN_NFC1
|
||||
#define WB_IO4 (4)
|
||||
#define PIN_NFC2 (10)
|
||||
|
||||
static const uint8_t AREF = PIN_AREF;
|
||||
@@ -188,6 +190,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
// enables 3.3V periphery like GPS or IO Module
|
||||
#define PIN_3V3_EN (34)
|
||||
#define WB_IO2 PIN_3V3_EN
|
||||
|
||||
// RAK1910 GPS module
|
||||
// If using the wisblock GPS module and pluged into Port A on WisBlock base
|
||||
@@ -231,4 +234,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@ lib_deps =
|
||||
melopero/Melopero RV3028@^1.1.0
|
||||
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
|
||||
beegee-tokyo/RAKwireless RAK12034@^1.0.0
|
||||
beegee-tokyo/RAK12035_SoilMoisture@^1.0.4
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
|
||||
@@ -69,7 +69,9 @@ static const uint8_t A7 = PIN_A7;
|
||||
|
||||
// Other pins
|
||||
#define PIN_AREF (2)
|
||||
// #define PIN_NFC1 (9)
|
||||
#define PIN_NFC1 (9)
|
||||
#define WB_IO5 PIN_NFC1
|
||||
#define WB_IO4 (4)
|
||||
// #define PIN_NFC2 (10)
|
||||
|
||||
static const uint8_t AREF = PIN_AREF;
|
||||
@@ -160,6 +162,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
// enables 3.3V periphery like GPS or IO Module
|
||||
#define PIN_3V3_EN (34)
|
||||
#define WB_IO2 PIN_3V3_EN
|
||||
|
||||
// NO GPS
|
||||
#undef GPS_RX_PIN
|
||||
@@ -202,4 +205,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7;
|
||||
// Other pins
|
||||
#define PIN_AREF (2)
|
||||
#define PIN_NFC1 (9)
|
||||
#define WB_IO5 PIN_NFC1
|
||||
#define WB_IO4 (4)
|
||||
#define PIN_NFC2 (10)
|
||||
|
||||
static const uint8_t AREF = PIN_AREF;
|
||||
@@ -217,6 +219,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
||||
// enables 3.3V periphery like GPS or IO Module
|
||||
// Do not toggle this for GPS power savings
|
||||
#define PIN_3V3_EN (34)
|
||||
#define WB_IO2 PIN_3V3_EN
|
||||
|
||||
// RAK1910 GPS module
|
||||
// If using the wisblock GPS module and pluged into Port A on WisBlock base
|
||||
@@ -270,4 +273,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,7 @@ lib_deps =
|
||||
bodmer/TFT_eSPI
|
||||
beegee-tokyo/RAKwireless RAK12034@^1.0.0
|
||||
beegee-tokyo/RAK14014-FT6336U @ 1.0.1
|
||||
beegee-tokyo/RAK12035_SoilMoisture@^1.0.4
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
|
||||
@@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7;
|
||||
// Other pins
|
||||
#define PIN_AREF (2)
|
||||
#define PIN_NFC1 (9)
|
||||
#define WB_IO5 PIN_NFC1
|
||||
#define WB_IO4 (4)
|
||||
#define PIN_NFC2 (10)
|
||||
|
||||
static const uint8_t AREF = PIN_AREF;
|
||||
@@ -176,11 +178,11 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
// No reason not to have the RAK Wireless pin defs here too. This allows code from example RAK sketches to run without
|
||||
// modification.
|
||||
|
||||
static const uint8_t WB_IO1 = 17; // SLOT_A SLOT_B
|
||||
static const uint8_t WB_IO2 = 34; // SLOT_A SLOT_B
|
||||
static const uint8_t WB_IO3 = 21; // SLOT_C
|
||||
static const uint8_t WB_IO4 = 4; // SLOT_C
|
||||
static const uint8_t WB_IO5 = 9; // SLOT_D
|
||||
static const uint8_t WB_IO1 = 17; // SLOT_A SLOT_B
|
||||
static const uint8_t WB_IO2 = 34; // SLOT_A SLOT_B
|
||||
static const uint8_t WB_IO3 = 21; // SLOT_C
|
||||
// static const uint8_t WB_IO4 = 4; // SLOT_C <- already defined above (ln. 94)
|
||||
// static const uint8_t WB_IO5 = 9; // SLOT_D <- already defined above (ln. 93)
|
||||
static const uint8_t WB_IO6 = 10; // SLOT_D
|
||||
static const uint8_t WB_SW1 = 33; // IO_SLOT
|
||||
static const uint8_t WB_A0 = 5; // IO_SLOT
|
||||
@@ -314,4 +316,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -59,8 +59,8 @@ const uint32_t g_ADigitalPinMap[] = {
|
||||
// D16 - Battery voltage ADC input
|
||||
31, // D16 P0.31 VBAT_ADC
|
||||
// GROVE
|
||||
0, // D17 P0.00 GROVESDA
|
||||
1, // D18 P0.01 GROVESCL
|
||||
43, // D17 P0.00 GROVESDA
|
||||
44, // D18 P0.01 GROVESCL
|
||||
|
||||
// FLASH
|
||||
21, // D19 P0.21 (QSPI_SCK)
|
||||
|
||||
@@ -74,10 +74,12 @@
|
||||
// Communication Interfaces
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// I2C Configuration
|
||||
#define HAS_WIRE 1
|
||||
// #define HAS_WIRE 1
|
||||
#define PIN_WIRE_SDA D14 // P0.09
|
||||
#define PIN_WIRE_SCL D15 // P0.10
|
||||
#define WIRE_INTERFACES_COUNT 1
|
||||
#define WIRE_INTERFACES_COUNT 2
|
||||
#define PIN_WIRE1_SDA D18
|
||||
#define PIN_WIRE1_SCL D17
|
||||
#define I2C_NO_RESCAN
|
||||
|
||||
static const uint8_t SDA = PIN_WIRE_SDA;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[env:seeed_xiao_nrf52840_kit]
|
||||
extends = nrf52840_base
|
||||
board = xiao_ble_sense
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/seeed_xiao_nrf52840_kit -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DSEEED_XIAO_NRF52840_KIT
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/seeed_xiao_nrf52840_kit -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DSEEED_XIAO_NRF52840_KIT -DGPS_L76K
|
||||
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/seeed_xiao_nrf52840_kit>
|
||||
lib_deps =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _SEEED_XIAO_NRF52840_SENSE_H_
|
||||
#define _SEEED_XIAO_NRF52840_SENSE_H_
|
||||
#ifndef _SEEED_XIAO_NRF52840_KIT_H_
|
||||
#define _SEEED_XIAO_NRF52840_KIT_H_
|
||||
|
||||
/** Master clock frequency */
|
||||
#define VARIANT_MCK (64000000ul)
|
||||
@@ -79,9 +79,8 @@ static const uint8_t A5 = PIN_A5;
|
||||
*/
|
||||
|
||||
/*
|
||||
* D0 is shared with PIN_GPS_STANDBY on the L76K GNSS Module.
|
||||
* There are some technical solutions that can solve this problem, and we are
|
||||
* currently exploring and researching them.
|
||||
* D0 is shared with PIN_GPS_STANDBY on the L76K GNSS Module, so refer to
|
||||
* GPS_L76K definition preventing this conflict
|
||||
*/
|
||||
|
||||
// #define BUTTON_PIN D0
|
||||
@@ -93,51 +92,60 @@ static const uint8_t A5 = PIN_A5;
|
||||
#define PIN_SERIAL2_TX (-1)
|
||||
|
||||
/*
|
||||
* SPI Interfaces
|
||||
* Pinout for SX126x
|
||||
*/
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
|
||||
#define PIN_SPI_MISO (9)
|
||||
#define PIN_SPI_MOSI (10)
|
||||
#define PIN_SPI_SCK (8)
|
||||
|
||||
static const uint8_t SS = D4;
|
||||
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||
static const uint8_t MISO = PIN_SPI_MISO;
|
||||
static const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
#define USE_SX1262
|
||||
|
||||
// Pinout for SX126X
|
||||
#ifdef XIAO_BLE_LEGACY_PINOUT
|
||||
// Legacy xiao_ble variant pinout for third-party SX126x modules e.g. EBYTE E22
|
||||
#define SX126X_CS D0
|
||||
#define SX126X_DIO1 D1
|
||||
#define SX126X_BUSY D2
|
||||
#define SX126X_RESET D3
|
||||
#define SX126X_RXEN D7
|
||||
|
||||
#elif defined(SEEED_XIAO_WIO_BTB)
|
||||
// Wio-SX1262 for XIAO with 30-pin board-to-board connector
|
||||
// https://files.seeedstudio.com/products/SenseCAP/Wio_SX1262/Schematic_Diagram_Wio-SX1262_for_XIAO.pdf
|
||||
#define SX126X_CS D3
|
||||
#define SX126X_DIO1 D0
|
||||
#define SX126X_BUSY D1
|
||||
#define SX126X_RESET D2
|
||||
#define SX126X_RXEN D4
|
||||
#else
|
||||
// Wio-SX1262 for XIAO (standalone SKU 113010003 or nRF52840 kit SKU 102010710)
|
||||
// https://files.seeedstudio.com/products/SenseCAP/Wio_SX1262/Wio-SX1262%20for%20XIAO%20V1.0_SCH.pdf
|
||||
#define SX126X_CS D4
|
||||
#define SX126X_DIO1 D1
|
||||
#define SX126X_BUSY D3
|
||||
#define SX126X_RESET D2
|
||||
#define SX126X_RXEN D5
|
||||
#endif
|
||||
|
||||
// Common pinouts for all SX126x pinouts above
|
||||
#define SX126X_TXEN RADIOLIB_NC
|
||||
|
||||
#define SX126X_RXEN D5 // This is used to control the RX side of the RF switch
|
||||
#define SX126X_DIO2_AS_RF_SWITCH // DIO2 is used to control the TX side of the RF switch
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
/*
|
||||
* Wire Interfaces
|
||||
* SPI Interfaces
|
||||
* Defined after pinout for SX1262x to factor in CS pinout variations
|
||||
*/
|
||||
#define I2C_NO_RESCAN // I2C is a bit finicky, don't scan too much
|
||||
#define WIRE_INTERFACES_COUNT 1 // 2
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
|
||||
// LSM6DS3TR on XIAO nRF52840 Series
|
||||
#define PIN_WIRE_SDA (17)
|
||||
#define PIN_WIRE_SCL (16)
|
||||
#define PIN_SPI_MISO D9
|
||||
#define PIN_SPI_MOSI D10
|
||||
#define PIN_SPI_SCK D8
|
||||
|
||||
static const uint8_t SDA = PIN_WIRE_SDA;
|
||||
static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
static const uint8_t SS = SX126X_CS;
|
||||
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||
static const uint8_t MISO = PIN_SPI_MISO;
|
||||
static const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
/*
|
||||
* GPS
|
||||
*/
|
||||
// GPS L76KB
|
||||
#define GPS_L76K
|
||||
// GPS L76K
|
||||
#ifdef GPS_L76K
|
||||
#define PIN_GPS_RX D6
|
||||
#define PIN_GPS_TX D7
|
||||
@@ -146,6 +154,9 @@ static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
#define PIN_SERIAL1_RX PIN_GPS_TX
|
||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||
#define PIN_GPS_STANDBY D0
|
||||
#else
|
||||
#define PIN_SERIAL1_RX (-1)
|
||||
#define PIN_SERIAL1_TX (-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -161,6 +172,39 @@ static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS (10)
|
||||
|
||||
/*
|
||||
* Wire Interfaces
|
||||
* Keep this section after potentially conflicting pin definitions
|
||||
*/
|
||||
#define I2C_NO_RESCAN // I2C is a bit finicky, don't scan too much
|
||||
#define WIRE_INTERFACES_COUNT 1
|
||||
|
||||
#if !defined(XIAO_BLE_LEGACY_PINOUT) && !defined(GPS_L76K)
|
||||
// If D6 and D7 are free, I2C is probably the most versatile assignment
|
||||
#define PIN_WIRE_SDA D6
|
||||
#define PIN_WIRE_SCL D7
|
||||
#else
|
||||
// Internal LSM6DS3TR on XIAO nRF52840 Series
|
||||
#define PIN_WIRE_SDA (17)
|
||||
#define PIN_WIRE_SCL (16)
|
||||
#endif
|
||||
|
||||
static const uint8_t SDA = PIN_WIRE_SDA;
|
||||
static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
|
||||
/*
|
||||
* Buttons
|
||||
* Keep this section after potentially conflicting pin definitions
|
||||
* because D0 has multiple possible conflicts with various XIAO modules:
|
||||
* - PIN_GPS_STANDBY on the L76K GNSS Module
|
||||
* - DIO1 on the Wio-SX1262 - 30-pin board-to-board connector version
|
||||
* - SX1262X CS on XIAO BLE legacy pinout
|
||||
*/
|
||||
|
||||
#if !defined(GPS_L76K) && !defined(SEEED_XIAO_WIO_BTB) && !defined(XIAO_BLE_OLD_PINOUT)
|
||||
#define BUTTON_PIN D0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -139,6 +139,7 @@ External serial flash WP25R1635FZUIL0
|
||||
// Not really an E22 but TTGO seems to be trying to clone that
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#define TCXO_OPTIONAL
|
||||
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||
// code)
|
||||
|
||||
@@ -214,7 +215,7 @@ External serial flash WP25R1635FZUIL0
|
||||
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||
#define ADC_MULTIPLIER (2.0F)
|
||||
|
||||
#define NO_EXT_GPIO 1
|
||||
// #define NO_EXT_GPIO 1
|
||||
|
||||
#define HAS_RTC 1
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
; Seeed Xiao BLE: https://www.digikey.com/en/products/detail/seeed-technology-co-ltd/102010448/16652893
|
||||
[env:xiao_ble]
|
||||
extends = nrf52840_base
|
||||
board = xiao_ble_sense
|
||||
board_level = extra
|
||||
build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -D EBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW
|
||||
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
debug_tool = jlink
|
||||
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
|
||||
;upload_protocol = jlink
|
||||
@@ -1,62 +0,0 @@
|
||||
#include "variant.h"
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
|
||||
const uint32_t g_ADigitalPinMap[] = {
|
||||
// D0 .. D13
|
||||
2, // D0 is P0.02 (A0)
|
||||
3, // D1 is P0.03 (A1)
|
||||
28, // D2 is P0.28 (A2)
|
||||
29, // D3 is P0.29 (A3)
|
||||
4, // D4 is P0.04 (A4,SDA)
|
||||
5, // D5 is P0.05 (A5,SCL)
|
||||
43, // D6 is P1.11 (TX)
|
||||
44, // D7 is P1.12 (RX)
|
||||
45, // D8 is P1.13 (SCK)
|
||||
46, // D9 is P1.14 (MISO)
|
||||
47, // D10 is P1.15 (MOSI)
|
||||
|
||||
// LEDs
|
||||
26, // D11 is P0.26 (LED RED)
|
||||
6, // D12 is P0.06 (LED BLUE)
|
||||
30, // D13 is P0.30 (LED GREEN)
|
||||
14, // D14 is P0.14 (READ_BAT)
|
||||
|
||||
// LSM6DS3TR
|
||||
40, // D15 is P1.08 (6D_PWR)
|
||||
27, // D16 is P0.27 (6D_I2C_SCL)
|
||||
7, // D17 is P0.07 (6D_I2C_SDA)
|
||||
11, // D18 is P0.11 (6D_INT1)
|
||||
|
||||
// MIC
|
||||
42, // 17,//42, // D19 is P1.10 (MIC_PWR)
|
||||
32, // 26,//32, // D20 is P1.00 (PDM_CLK)
|
||||
16, // 25,//16, // D21 is P0.16 (PDM_DATA)
|
||||
|
||||
// BQ25100
|
||||
13, // D22 is P0.13 (HICHG)
|
||||
17, // D23 is P0.17 (~CHG)
|
||||
|
||||
//
|
||||
21, // D24 is P0.21 (QSPI_SCK)
|
||||
25, // D25 is P0.25 (QSPI_CSN)
|
||||
20, // D26 is P0.20 (QSPI_SIO_0 DI)
|
||||
24, // D27 is P0.24 (QSPI_SIO_1 DO)
|
||||
22, // D28 is P0.22 (QSPI_SIO_2 WP)
|
||||
23, // D29 is P0.23 (QSPI_SIO_3 HOLD)
|
||||
|
||||
// NFC
|
||||
9, // D30 is P0.09 (NFC1)
|
||||
10, // D31 is P0.10 (NFC2)
|
||||
|
||||
// VBAT
|
||||
31, // D32 is P0.10 (VBAT)
|
||||
};
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
// Set BQ25101 ISET to 100mA instead of 50mA
|
||||
pinMode(HICHG, OUTPUT);
|
||||
digitalWrite(HICHG, LOW);
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
#ifndef _SEEED_XIAO_NRF52840_SENSE_H_
|
||||
#define _SEEED_XIAO_NRF52840_SENSE_H_
|
||||
|
||||
/** Master clock frequency */
|
||||
#define VARIANT_MCK (64000000ul)
|
||||
|
||||
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||
// #define USE_LFRC // Board uses RC for LF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define PINS_COUNT (33)
|
||||
#define NUM_DIGITAL_PINS (33)
|
||||
#define NUM_ANALOG_INPUTS (8) // A6 is used for battery, A7 is analog reference
|
||||
#define NUM_ANALOG_OUTPUTS (0)
|
||||
|
||||
// LEDs
|
||||
|
||||
#define LED_RED 11
|
||||
#define LED_BLUE 12
|
||||
#define LED_GREEN 13
|
||||
|
||||
#define PIN_LED1 LED_GREEN
|
||||
#define PIN_LED2 LED_BLUE
|
||||
#define PIN_LED3 LED_RED
|
||||
|
||||
#define PIN_LED PIN_LED1
|
||||
#define LED_PWR (PINS_COUNT)
|
||||
|
||||
#define LED_BUILTIN PIN_LED
|
||||
|
||||
#define LED_STATE_ON 1 // State when LED is lit
|
||||
|
||||
/*
|
||||
* Buttons
|
||||
*/
|
||||
#define PIN_BUTTON1 (PINS_COUNT)
|
||||
|
||||
// Digital PINs
|
||||
#define D0 (0ul)
|
||||
#define D1 (1ul)
|
||||
#define D2 (2ul)
|
||||
#define D3 (3ul)
|
||||
#define D4 (4ul)
|
||||
#define D5 (5ul)
|
||||
#define D6 (6ul)
|
||||
#define D7 (7ul)
|
||||
#define D8 (8ul)
|
||||
#define D9 (9ul)
|
||||
#define D10 (10ul)
|
||||
|
||||
/*
|
||||
* Analog pins
|
||||
*/
|
||||
#define PIN_A0 (0)
|
||||
#define PIN_A1 (1)
|
||||
#define PIN_A2 (2)
|
||||
#define PIN_A3 (3)
|
||||
#define PIN_A4 (4)
|
||||
#define PIN_A5 (5)
|
||||
#define PIN_VBAT (32)
|
||||
#define VBAT_ENABLE (14)
|
||||
|
||||
static const uint8_t A0 = PIN_A0;
|
||||
static const uint8_t A1 = PIN_A1;
|
||||
static const uint8_t A2 = PIN_A2;
|
||||
static const uint8_t A3 = PIN_A3;
|
||||
static const uint8_t A4 = PIN_A4;
|
||||
static const uint8_t A5 = PIN_A5;
|
||||
#define ADC_RESOLUTION 12
|
||||
|
||||
// Other pins
|
||||
#define PIN_NFC1 (30)
|
||||
#define PIN_NFC2 (31)
|
||||
|
||||
/*
|
||||
* Serial interfaces
|
||||
*/
|
||||
#define PIN_SERIAL1_RX (-1) // (7)
|
||||
#define PIN_SERIAL1_TX (-1) // (6)
|
||||
|
||||
#define PIN_SERIAL2_RX (-1)
|
||||
#define PIN_SERIAL2_TX (-1)
|
||||
|
||||
/*
|
||||
* SPI Interfaces
|
||||
*/
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
|
||||
#define PIN_SPI_MISO (9)
|
||||
#define PIN_SPI_MOSI (10)
|
||||
#define PIN_SPI_SCK (8)
|
||||
|
||||
static const uint8_t SS = D0;
|
||||
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||
static const uint8_t MISO = PIN_SPI_MISO;
|
||||
static const uint8_t SCK = PIN_SPI_SCK;
|
||||
|
||||
// supported modules list
|
||||
#define USE_SX1262
|
||||
|
||||
// common pinouts for SX126X modules
|
||||
#define SX126X_CS D0
|
||||
#define SX126X_DIO1 D1
|
||||
#define SX126X_BUSY D2
|
||||
#define SX126X_RESET D3
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// E22 Tx/Rx control options:
|
||||
|
||||
// 1. Let the E22 control Tx and Rx automagically via DIO2.
|
||||
|
||||
// * The E22's TXEN and DIO2 pins are connected to each other, but not to the MCU.
|
||||
// * The E22's RXEN pin *is* connected to the MCU.
|
||||
// * E22_TXEN_CONNECTED_TO_DIO2 is defined so the logic in SX126XInterface.cpp handles this configuration correctly.
|
||||
|
||||
#define SX126X_TXEN RADIOLIB_NC
|
||||
#define SX126X_RXEN D7
|
||||
|
||||
// ------------------------------ OR ------------------------------
|
||||
|
||||
// 2. Control Tx and Rx manually.
|
||||
|
||||
// * The E22's TXEN and RXEN pins are both connected to the MCU.
|
||||
|
||||
// #define SX126X_TXEN D6
|
||||
// #define SX126X_RXEN D7
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
#ifdef EBYTE_E22
|
||||
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
|
||||
// (which is the default for the sx1262interface code)
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#ifdef EBYTE_E22_900M30S
|
||||
// 10dB PA gain and 30dB rated output; based on measurements from
|
||||
// https://github.com/S5NC/EBYTE_ESP32-S3/blob/main/E22-900M30S%20power%20output%20testing.txt
|
||||
#define TX_GAIN_LORA 7
|
||||
#define SX126X_MAX_POWER 22
|
||||
#endif
|
||||
#ifdef EBYTE_E22_900M33S
|
||||
// 25dB PA gain and 33dB rated output; based on TX Power Curve from E22-900M33S_UserManual_EN_v1.0.pdf
|
||||
#define TX_GAIN_LORA 25
|
||||
#define SX126X_MAX_POWER 8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wire Interfaces
|
||||
*/
|
||||
#define WIRE_INTERFACES_COUNT 1 // 2
|
||||
|
||||
#define PIN_WIRE_SDA (4)
|
||||
#define PIN_WIRE_SCL (5)
|
||||
|
||||
static const uint8_t SDA = PIN_WIRE_SDA;
|
||||
static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
|
||||
#define PIN_LSM6DS3TR_C_POWER (15)
|
||||
#define PIN_LSM6DS3TR_C_INT1 (18)
|
||||
|
||||
// PDM Interfaces
|
||||
// ---------------
|
||||
#define PIN_PDM_PWR (19)
|
||||
#define PIN_PDM_CLK (20)
|
||||
#define PIN_PDM_DIN (21)
|
||||
|
||||
// QSPI Pins
|
||||
#define PIN_QSPI_SCK (24)
|
||||
#define PIN_QSPI_CS (25)
|
||||
#define PIN_QSPI_IO0 (26)
|
||||
#define PIN_QSPI_IO1 (27)
|
||||
#define PIN_QSPI_IO2 (28)
|
||||
#define PIN_QSPI_IO3 (29)
|
||||
|
||||
// On-board QSPI Flash
|
||||
#define EXTERNAL_FLASH_DEVICES P25Q16H
|
||||
#define EXTERNAL_FLASH_USE_QSPI
|
||||
|
||||
// Battery
|
||||
|
||||
#define ADC_CTRL VBAT_ENABLE // P0.14: VBAT voltage divider
|
||||
#define ADC_CTRL_ENABLED LOW // ... sink
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||
#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED
|
||||
#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge
|
||||
|
||||
// The battery sense is hooked to pin A0 (5)
|
||||
#define BATTERY_PIN PIN_VBAT // PIN_A0
|
||||
|
||||
// ratio of voltage divider = 3.0 (R17=1M, R18=510k)
|
||||
#define ADC_MULTIPLIER 3 // 3.0 + a bit for being optimistic
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Arduino objects - C++ only
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
# adapted from the script linked in this very helpful article: https://enzolombardi.net/low-power-bluetooth-advertising-with-xiao-ble-and-platformio-e8e7d0da80d2
|
||||
|
||||
# source: https://gist.githubusercontent.com/turing-complete-labs/b3105ee653782183c54b4fdbe18f411f/raw/d86779ba7702775d3b79781da63d85442acd9de6/xiao_ble.sh
|
||||
# download the core for arduino from seeedstudio. Softdevice 7.3.0, linker and variants folder are what we need
|
||||
curl https://files.seeedstudio.com/arduino/core/nRF52840/Arduino_core_nRF52840.tar.bz2 -o arduino.core.1.0.0.tar.bz2
|
||||
tar -xjf arduino.core.1.0.0.tar.bz2
|
||||
rm arduino.core.1.0.0.tar.bz2
|
||||
|
||||
# copy the needed files
|
||||
cp 1.0.0/cores/nRF5/linker/nrf52840_s140_v7.ld ~/.platformio/packages/framework-arduinoadafruitnrf52/cores/nRF5/linker
|
||||
cp -r 1.0.0/cores/nRF5/nordic/softdevice/s140_nrf52_7.3.0_API ~/.platformio/packages/framework-arduinoadafruitnrf52/cores/nRF5/nordic/softdevice
|
||||
|
||||
rm -rf 1.0.0
|
||||
echo done!
|
||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 6
|
||||
build = 12
|
||||
build = 13
|
||||
|
||||
Reference in New Issue
Block a user