Merge branch 'dev' into rep-room-acl

This commit is contained in:
Scott Powell
2025-09-16 13:07:14 +10:00
13 changed files with 146 additions and 165 deletions

View File

@@ -294,7 +294,7 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) {
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
} }
bool MyMesh::processAck(const uint8_t *data) { ContactInfo* MyMesh::processAck(const uint8_t *data) {
// see if matches any in a table // see if matches any in a table
for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) {
if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient
@@ -306,7 +306,7 @@ bool MyMesh::processAck(const uint8_t *data) {
// NOTE: the same ACK can be received multiple times! // NOTE: the same ACK can be received multiple times!
expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK
return true; return expected_ack_table[i].contact;
} }
} }
return checkConnectionsAck(data); return checkConnectionsAck(data);
@@ -825,6 +825,7 @@ void MyMesh::handleCmdFrame(size_t len) {
if (expected_ack) { if (expected_ack) {
expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table
expected_ack_table[next_ack_idx].ack = expected_ack; expected_ack_table[next_ack_idx].ack = expected_ack;
expected_ack_table[next_ack_idx].contact = recipient;
next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE;
} }

View File

@@ -112,7 +112,7 @@ protected:
bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override; bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override; void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
void onContactPathUpdated(const ContactInfo &contact) override; void onContactPathUpdated(const ContactInfo &contact) override;
bool processAck(const uint8_t *data) override; ContactInfo* processAck(const uint8_t *data) override;
void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp,
const uint8_t *extra, int extra_len, const char *text); const uint8_t *extra, int extra_len, const char *text);
@@ -205,6 +205,7 @@ private:
struct AckTableEntry { struct AckTableEntry {
unsigned long msg_sent; unsigned long msg_sent;
uint32_t ack; uint32_t ack;
ContactInfo* contact;
}; };
#define EXPECTED_ACK_TABLE_SIZE 8 #define EXPECTED_ACK_TABLE_SIZE 8
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table

View File

@@ -217,18 +217,18 @@ protected:
saveContacts(); saveContacts();
} }
bool processAck(const uint8_t *data) override { ContactInfo* processAck(const uint8_t *data) override {
if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient
Serial.printf(" Got ACK! (round trip: %d millis)\n", _ms->getMillis() - last_msg_sent); Serial.printf(" Got ACK! (round trip: %d millis)\n", _ms->getMillis() - last_msg_sent);
// NOTE: the same ACK can be received multiple times! // NOTE: the same ACK can be received multiple times!
expected_ack_crc = 0; // reset our expected hash, now that we have received ACK expected_ack_crc = 0; // reset our expected hash, now that we have received ACK
return true; return NULL; // TODO: really should return ContactInfo pointer
} }
//uint32_t crc; //uint32_t crc;
//memcpy(&crc, data, 4); //memcpy(&crc, data, 4);
//MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); //MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc);
return false; return NULL;
} }
void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override {

View File

@@ -158,6 +158,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
data[len] = 0; // need to make a C string again, with null terminator data[len] = 0; // need to make a C string again, with null terminator
if (flags == TXT_TYPE_PLAIN) { if (flags == TXT_TYPE_PLAIN) {
from.lastmod = getRTCClock()->getCurrentTime(); // update last heard time
onMessageRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know onMessageRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it
@@ -184,6 +185,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
if (timestamp > from.sync_since) { // make sure 'sync_since' is up-to-date if (timestamp > from.sync_since) { // make sure 'sync_since' is up-to-date
from.sync_since = timestamp; from.sync_since = timestamp;
} }
from.lastmod = getRTCClock()->getCurrentTime(); // update last heard time
onSignedMessageRecv(from, packet, timestamp, &data[5], (const char *) &data[9]); // let UI know onSignedMessageRecv(from, packet, timestamp, &data[5], (const char *) &data[9]); // let UI know
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + OUR pub_key, to prove to sender that we got it uint32_t ack_hash; // calc truncated hash of the message timestamp + text + OUR pub_key, to prove to sender that we got it
@@ -223,6 +225,10 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
} }
} else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) { } else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) {
onContactResponse(from, data, len); onContactResponse(from, data, len);
if (packet->isRouteFlood() && from.out_path_len >= 0) {
// we have direct path, but other node is still sending flood response, so maybe they didn't receive reciprocal path properly(?)
handleReturnPathRetry(from, packet->path, packet->path_len);
}
} }
} }
@@ -248,7 +254,7 @@ bool BaseChatMesh::onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_
if (extra_type == PAYLOAD_TYPE_ACK && extra_len >= 4) { if (extra_type == PAYLOAD_TYPE_ACK && extra_len >= 4) {
// also got an encoded ACK! // also got an encoded ACK!
if (processAck(extra)) { if (processAck(extra) != NULL) {
txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer
} }
} else if (extra_type == PAYLOAD_TYPE_RESPONSE && extra_len > 0) { } else if (extra_type == PAYLOAD_TYPE_RESPONSE && extra_len > 0) {
@@ -258,12 +264,25 @@ bool BaseChatMesh::onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_
} }
void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) { void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
if (processAck((uint8_t *)&ack_crc)) { ContactInfo* from;
if ((from = processAck((uint8_t *)&ack_crc)) != NULL) {
txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer
packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit
if (packet->isRouteFlood() && from->out_path_len >= 0) {
// we have direct path, but other node is still sending flood, so maybe they didn't receive reciprocal path properly(?)
handleReturnPathRetry(*from, packet->path, packet->path_len);
}
} }
} }
void BaseChatMesh::handleReturnPathRetry(const ContactInfo& contact, const uint8_t* path, uint8_t path_len) {
// NOTE: simplest impl is just to re-send a reciprocal return path to sender (DIRECTLY)
// override this method in various firmwares, if there's a better strategy
mesh::Packet* rpath = createPathReturn(contact.id, contact.shared_secret, path, path_len, 0, NULL, 0);
if (rpath) sendDirect(rpath, contact.out_path, contact.out_path_len, 3000); // 3 second delay
}
#ifdef MAX_GROUP_CHANNELS #ifdef MAX_GROUP_CHANNELS
int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) { int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) {
int n = 0; int n = 0;
@@ -550,7 +569,7 @@ void BaseChatMesh::markConnectionActive(const ContactInfo& contact) {
} }
} }
bool BaseChatMesh::checkConnectionsAck(const uint8_t* data) { ContactInfo* BaseChatMesh::checkConnectionsAck(const uint8_t* data) {
for (int i = 0; i < MAX_CONNECTIONS; i++) { for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) { if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) {
// yes, got an ack for our keep_alive request! // yes, got an ack for our keep_alive request!
@@ -559,10 +578,12 @@ bool BaseChatMesh::checkConnectionsAck(const uint8_t* data) {
// re-schedule next KEEP_ALIVE, now that we have heard from server // re-schedule next KEEP_ALIVE, now that we have heard from server
connections[i].next_ping = futureMillis(connections[i].keep_alive_millis); connections[i].next_ping = futureMillis(connections[i].keep_alive_millis);
return true; // yes, a match
auto id = &connections[i].server_id;
return lookupContactByPubKey(id->pub_key, PUB_KEY_SIZE); // yes, a match
} }
} }
return false; /// no match return NULL; /// no match
} }
void BaseChatMesh::checkConnections() { void BaseChatMesh::checkConnections() {

View File

@@ -93,7 +93,7 @@ protected:
// 'UI' concepts, for sub-classes to implement // 'UI' concepts, for sub-classes to implement
virtual bool isAutoAddEnabled() const { return true; } virtual bool isAutoAddEnabled() const { return true; }
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0; virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
virtual bool processAck(const uint8_t *data) = 0; virtual ContactInfo* processAck(const uint8_t *data) = 0;
virtual void onContactPathUpdated(const ContactInfo& contact) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
virtual bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len); virtual bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len);
virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0; virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
@@ -105,6 +105,7 @@ protected:
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0; virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0;
virtual uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) = 0; virtual uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) = 0;
virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0; virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0;
virtual void handleReturnPathRetry(const ContactInfo& contact, const uint8_t* path, uint8_t path_len);
// storage concepts, for sub-classes to override/implement // storage concepts, for sub-classes to override/implement
virtual int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { return 0; } // not implemented virtual int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { return 0; } // not implemented
@@ -127,7 +128,7 @@ protected:
void stopConnection(const uint8_t* pub_key); void stopConnection(const uint8_t* pub_key);
bool hasConnectionTo(const uint8_t* pub_key); bool hasConnectionTo(const uint8_t* pub_key);
void markConnectionActive(const ContactInfo& contact); void markConnectionActive(const ContactInfo& contact);
bool checkConnectionsAck(const uint8_t* data); ContactInfo* checkConnectionsAck(const uint8_t* data);
void checkConnections(); void checkConnections();
public: public:

View File

@@ -4,10 +4,7 @@ static SerialBLEInterface* instance;
void SerialBLEInterface::onConnect(uint16_t connection_handle) { void SerialBLEInterface::onConnect(uint16_t connection_handle) {
BLE_DEBUG_PRINTLN("SerialBLEInterface: connected"); BLE_DEBUG_PRINTLN("SerialBLEInterface: connected");
if(instance){ // we now set _isDeviceConnected=true in onSecured callback instead
instance->_isDeviceConnected = true;
// no need to stop advertising on connect, as the ble stack does this automatically
}
} }
void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) { void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) {
@@ -18,6 +15,14 @@ void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason
} }
} }
void SerialBLEInterface::onSecured(uint16_t connection_handle) {
BLE_DEBUG_PRINTLN("SerialBLEInterface: onSecured");
if(instance){
instance->_isDeviceConnected = true;
// no need to stop advertising on connect, as the ble stack does this automatically
}
}
void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) {
instance = this; instance = this;
@@ -36,6 +41,7 @@ void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) {
Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setConnectCallback(onConnect);
Bluefruit.Periph.setDisconnectCallback(onDisconnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect);
Bluefruit.Security.setSecuredCallback(onSecured);
// To be consistent OTA DFU should be added first if it exists // To be consistent OTA DFU should be added first if it exists
//bledfu.begin(); //bledfu.begin();
@@ -80,7 +86,7 @@ void SerialBLEInterface::startAdv() {
* https://developer.apple.com/library/content/qa/qa1931/_index.html * https://developer.apple.com/library/content/qa/qa1931/_index.html
*/ */
Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect
Bluefruit.Advertising.setInterval(32, 1600); Bluefruit.Advertising.setInterval(32, 244);
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds

View File

@@ -25,6 +25,7 @@ class SerialBLEInterface : public BaseSerialInterface {
void clearBuffers() { send_queue_len = 0; } void clearBuffers() { send_queue_len = 0; }
static void onConnect(uint16_t connection_handle); static void onConnect(uint16_t connection_handle);
static void onDisconnect(uint16_t connection_handle, uint8_t reason); static void onDisconnect(uint16_t connection_handle, uint8_t reason);
static void onSecured(uint16_t connection_handle);
public: public:
SerialBLEInterface() { SerialBLEInterface() {

View File

@@ -1,21 +1,19 @@
#ifdef XIAO_NRF52 #ifdef XIAO_NRF52
#include <Arduino.h> #include <Arduino.h>
#include "XiaoNrf52Board.h"
#include <bluefruit.h>
#include <Wire.h> #include <Wire.h>
#include <bluefruit.h>
#include "XiaoNrf52Board.h"
static BLEDfu bledfu; static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle) static void connect_callback(uint16_t conn_handle) {
{
(void)conn_handle; (void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected"); MESH_DEBUG_PRINTLN("BLE client connected");
} }
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
{
(void)conn_handle; (void)conn_handle;
(void)reason; (void)reason;
@@ -41,12 +39,12 @@ void XiaoNrf52Board::begin() {
digitalWrite(P_LORA_TX_LED, HIGH); digitalWrite(P_LORA_TX_LED, HIGH);
#endif #endif
// pinMode(SX126X_POWER_EN, OUTPUT); // pinMode(SX126X_POWER_EN, OUTPUT);
// digitalWrite(SX126X_POWER_EN, HIGH); // digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up delay(10); // give sx1262 some time to power up
} }
bool XiaoNrf52Board::startOTAUpdate(const char* id, char reply[]) { bool XiaoNrf52Board::startOTAUpdate(const char *id, char reply[]) {
// Config the peripheral connection with maximum bandwidth // Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice // more SRAM required by SoftDevice
// Note: All config***() function must be called before begin() // Note: All config***() function must be called before begin()
@@ -86,10 +84,8 @@ bool XiaoNrf52Board::startOTAUpdate(const char* id, char reply[]) {
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started"); strcpy(reply, "OK - started");
return true; return true;
return false;
} }
#endif #endif

View File

@@ -5,20 +5,6 @@
#ifdef XIAO_NRF52 #ifdef XIAO_NRF52
// redefine lora pins if using the S3 variant of SX1262 board
#ifdef SX1262_XIAO_S3_VARIANT
#undef P_LORA_DIO_1
#undef P_LORA_BUSY
#undef P_LORA_RESET
#undef P_LORA_NSS
#undef SX126X_RXEN
#define P_LORA_DIO_1 D0
#define P_LORA_BUSY D1
#define P_LORA_RESET D2
#define P_LORA_NSS D3
#define SX126X_RXEN D4
#endif
class XiaoNrf52Board : public mesh::MainBoard { class XiaoNrf52Board : public mesh::MainBoard {
protected: protected:
uint8_t startup_reason; uint8_t startup_reason;
@@ -40,13 +26,13 @@ public:
// Please read befor going further ;) // Please read befor going further ;)
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
// We can't drive VBAT_ENABLE to HIGH as long // We can't drive VBAT_ENABLE to HIGH as long
// as we don't know wether we are charging or not ... // as we don't know wether we are charging or not ...
// this is a 3mA loss (4/1500) // this is a 3mA loss (4/1500)
digitalWrite(VBAT_ENABLE, LOW); digitalWrite(VBAT_ENABLE, LOW);
int adcvalue = 0; int adcvalue = 0;
analogReadResolution(12); analogReadResolution(12);
analogReference(AR_INTERNAL_3_0); analogReference(AR_INTERNAL_3_0);
delay(10); delay(10);
adcvalue = analogRead(PIN_VBAT); adcvalue = analogRead(PIN_VBAT);
return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096; return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;

View File

@@ -1,37 +1,19 @@
[nrf52840_xiao] [Xiao_nrf52]
extends = nrf52_base extends = nrf52_base
platform_packages =
toolchain-gccarmnoneeabi@~1.100301.0
framework-arduinoadafruitnrf52
board = seeed-xiao-afruitnrf52-nrf52840 board = seeed-xiao-afruitnrf52-nrf52840
board_build.ldscript = boards/nrf52840_s140_v7.ld board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52_base.build_flags} build_flags = ${nrf52_base.build_flags}
-D NRF52_PLATFORM -D XIAO_NRF52 ${sensor_base.build_flags}
-I lib/nrf52/s140_nrf52_7.3.0_API/include -I lib/nrf52/s140_nrf52_7.3.0_API/include
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
lib_ignore =
BluetoothOTA
lvgl
lib5b4
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
[Xiao_nrf52]
extends = nrf52840_xiao
;board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52840_xiao.build_flags}
-D P_LORA_TX_LED=11
-I variants/xiao_nrf52 -I variants/xiao_nrf52
-I src/helpers/nrf52 -UENV_INCLUDE_GPS
-D NRF52_PLATFORM
-D XIAO_NRF52
-D RADIO_CLASS=CustomSX1262 -D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper -D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22 -D LORA_TX_POWER=22
-D P_LORA_TX_LED=11
-D P_LORA_DIO_1=D1 -D P_LORA_DIO_1=D1
-D P_LORA_RESET=D2 -D P_LORA_RESET=D2
-D P_LORA_BUSY=D3 -D P_LORA_BUSY=D3
@@ -42,18 +24,16 @@ build_flags = ${nrf52840_xiao.build_flags}
-D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140 -D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1 -D SX126X_RX_BOOSTED_GAIN=1
-D PIN_WIRE_SCL=6 -D PIN_WIRE_SCL=D6
-D PIN_WIRE_SDA=7 -D PIN_WIRE_SDA=D7
-D ENV_INCLUDE_AHTX0=1 build_src_filter = ${nrf52_base.build_src_filter}
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp> +<helpers/*.cpp>
+<helpers/sensors> +<helpers/sensors>
+<../variants/xiao_nrf52> +<../variants/xiao_nrf52>
debug_tool = jlink debug_tool = jlink
upload_protocol = nrfutil upload_protocol = nrfutil
lib_deps = ${nrf52_base.lib_deps}
${sensor_base.lib_deps}
[env:Xiao_nrf52_companion_radio_ble] [env:Xiao_nrf52_companion_radio_ble]
extends = Xiao_nrf52 extends = Xiao_nrf52
@@ -94,12 +74,6 @@ lib_deps =
${Xiao_nrf52.lib_deps} ${Xiao_nrf52.lib_deps}
densaugeo/base64 @ ~1.4.0 densaugeo/base64 @ ~1.4.0
[env:Xiao_nrf52_alt_pinout_companion_radio_ble]
extends = env:Xiao_nrf52_companion_radio_ble
build_flags =
${env:Xiao_nrf52_companion_radio_ble.build_flags}
-D SX1262_XIAO_S3_VARIANT
[env:Xiao_nrf52_repeater] [env:Xiao_nrf52_repeater]
extends = Xiao_nrf52 extends = Xiao_nrf52
build_flags = build_flags =
@@ -114,12 +88,6 @@ build_flags =
build_src_filter = ${Xiao_nrf52.build_src_filter} build_src_filter = ${Xiao_nrf52.build_src_filter}
+<../examples/simple_repeater/*.cpp> +<../examples/simple_repeater/*.cpp>
[env:Xiao_nrf52_alt_pinout_repeater]
extends = env:Xiao_nrf52_repeater
build_flags =
${env:Xiao_nrf52_repeater.build_flags}
-D SX1262_XIAO_S3_VARIANT
[env:Xiao_nrf52_room_server] [env:Xiao_nrf52_room_server]
extends = Xiao_nrf52 extends = Xiao_nrf52
build_flags = build_flags =

View File

@@ -10,12 +10,13 @@ WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock; VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock); AutoDiscoverRTCClock rtc_clock(fallback_clock);
EnvironmentSensorManager sensors; EnvironmentSensorManager sensors;
bool radio_init() { bool radio_init() {
rtc_clock.begin(Wire); rtc_clock.begin(Wire);
return radio.std_init(&SPI); return radio.std_init(&SPI);
} }
uint32_t radio_get_rng_seed() { uint32_t radio_get_rng_seed() {
@@ -35,5 +36,5 @@ void radio_set_tx_power(uint8_t dbm) {
mesh::LocalIdentity radio_new_identity() { mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio); RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity return mesh::LocalIdentity(&rng); // create new random identity
} }

View File

@@ -1,86 +1,85 @@
#include "variant.h" #include "variant.h"
#include "nrf.h"
#include "wiring_constants.h" #include "wiring_constants.h"
#include "wiring_digital.h" #include "wiring_digital.h"
#include "nrf.h"
const uint32_t g_ADigitalPinMap[] = const uint32_t g_ADigitalPinMap[] = {
{ // D0 .. D10
// D0 .. D10 2, // D0 is P0.02 (A0)
2, // D0 is P0.02 (A0) 3, // D1 is P0.03 (A1)
3, // D1 is P0.03 (A1) 28, // D2 is P0.28 (A2)
28, // D2 is P0.28 (A2) 29, // D3 is P0.29 (A3)
29, // D3 is P0.29 (A3) 4, // D4 is P0.04 (A4,SDA)
4, // D4 is P0.04 (A4,SDA) 5, // D5 is P0.05 (A5,SCL)
5, // D5 is P0.05 (A5,SCL) 43, // D6 is P1.11 (TX)
43, // D6 is P1.11 (TX) 44, // D7 is P1.12 (RX)
44, // D7 is P1.12 (RX) 45, // D8 is P1.13 (SCK)
45, // D8 is P1.13 (SCK) 46, // D9 is P1.14 (MISO)
46, // D9 is P1.14 (MISO) 47, // D10 is P1.15 (MOSI)
47, // D10 is P1.15 (MOSI)
// LEDs // LEDs
26, // D11 is P0.26 (LED RED) 26, // D11 is P0.26 (LED RED)
6, // D12 is P0.06 (LED BLUE) 6, // D12 is P0.06 (LED BLUE)
30, // D13 is P0.30 (LED GREEN) 30, // D13 is P0.30 (LED GREEN)
14, // D14 is P0.14 (READ_BAT) 14, // D14 is P0.14 (READ_BAT)
// LSM6DS3TR // LSM6DS3TR
40, // D15 is P1.08 (6D_PWR) 40, // D15 is P1.08 (6D_PWR)
27, // D16 is P0.27 (6D_I2C_SCL) 27, // D16 is P0.27 (6D_I2C_SCL)
7, // D17 is P0.07 (6D_I2C_SDA) 7, // D17 is P0.07 (6D_I2C_SDA)
11, // D18 is P0.11 (6D_INT1) 11, // D18 is P0.11 (6D_INT1)
// MIC // MIC
42, // D19 is P1.10 (MIC_PWR) 42, // D19 is P1.10 (MIC_PWR)
32, // D20 is P1.00 (PDM_CLK) 32, // D20 is P1.00 (PDM_CLK)
16, // D21 is P0.16 (PDM_DATA) 16, // D21 is P0.16 (PDM_DATA)
// BQ25100 // BQ25100
13, // D22 is P0.13 (HICHG) 13, // D22 is P0.13 (HICHG)
17, // D23 is P0.17 (~CHG) 17, // D23 is P0.17 (~CHG)
// //
21, // D24 is P0.21 (QSPI_SCK) 21, // D24 is P0.21 (QSPI_SCK)
25, // D25 is P0.25 (QSPI_CSN) 25, // D25 is P0.25 (QSPI_CSN)
20, // D26 is P0.20 (QSPI_SIO_0 DI) 20, // D26 is P0.20 (QSPI_SIO_0 DI)
24, // D27 is P0.24 (QSPI_SIO_1 DO) 24, // D27 is P0.24 (QSPI_SIO_1 DO)
22, // D28 is P0.22 (QSPI_SIO_2 WP) 22, // D28 is P0.22 (QSPI_SIO_2 WP)
23, // D29 is P0.23 (QSPI_SIO_3 HOLD) 23, // D29 is P0.23 (QSPI_SIO_3 HOLD)
// NFC // NFC
9, // D30 is P0.09 (NFC1) 9, // D30 is P0.09 (NFC1)
10, // D31 is P0.10 (NFC2) 10, // D31 is P0.10 (NFC2)
// VBAT // VBAT
31, // D32 is P0.31 (VBAT) 31, // D32 is P0.31 (VBAT)
}; };
void initVariant() void initVariant() {
{ // Disable reading of the BAT voltage.
// Disable reading of the BAT voltage. // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging pinMode(VBAT_ENABLE, OUTPUT);
pinMode(VBAT_ENABLE, OUTPUT); // digitalWrite(VBAT_ENABLE, HIGH);
//digitalWrite(VBAT_ENABLE, HIGH); // This was taken from Seeed github butis not coherent with the doc,
// This was taken from Seeed github butis not coherent with the doc, // VBAT_ENABLE should be kept to LOW to protect P0.14, (1500/500)*(4.2-3.3)+3.3 = 3.9V > 3.6V
// VBAT_ENABLE should be kept to LOW to protect P0.14, (1500/500)*(4.2-3.3)+3.3 = 3.9V > 3.6V // This induces a 3mA current in the resistors :( but it's better than burning the nrf
// This induces a 3mA current in the resistors :( but it's better than burning the nrf digitalWrite(VBAT_ENABLE, LOW);
digitalWrite(VBAT_ENABLE, LOW);
// Low charging current (50mA) // Low charging current (50mA)
// https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current // https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current
//pinMode(PIN_CHARGING_CURRENT, INPUT); // pinMode(PIN_CHARGING_CURRENT, INPUT);
// High charging current (100mA) // High charging current (100mA)
pinMode(PIN_CHARGING_CURRENT, OUTPUT); pinMode(PIN_CHARGING_CURRENT, OUTPUT);
digitalWrite(PIN_CHARGING_CURRENT, LOW); digitalWrite(PIN_CHARGING_CURRENT, LOW);
pinMode(PIN_QSPI_CS, OUTPUT); pinMode(PIN_QSPI_CS, OUTPUT);
digitalWrite(PIN_QSPI_CS, HIGH); digitalWrite(PIN_QSPI_CS, HIGH);
pinMode(LED_RED, OUTPUT); pinMode(LED_RED, OUTPUT);
digitalWrite(LED_RED, HIGH); digitalWrite(LED_RED, HIGH);
pinMode(LED_GREEN, OUTPUT); pinMode(LED_GREEN, OUTPUT);
digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_GREEN, HIGH);
pinMode(LED_BLUE, OUTPUT); pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_BLUE, HIGH); digitalWrite(LED_BLUE, HIGH);
} }

View File

@@ -113,8 +113,8 @@ static const uint8_t A5 = PIN_A5;
// #define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! // #define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 !
// #define PIN_WIRE_SCL (16) // use WIRE1_SDA // #define PIN_WIRE_SCL (16) // use WIRE1_SDA
static const uint8_t SDA = PIN_WIRE_SDA; // static const uint8_t SDA = PIN_WIRE_SDA;
static const uint8_t SCL = PIN_WIRE_SCL; // static const uint8_t SCL = PIN_WIRE_SCL;
//#define PIN_WIRE1_SDA (17) //#define PIN_WIRE1_SDA (17)
//#define PIN_WIRE1_SCL (16) //#define PIN_WIRE1_SCL (16)