Merge branch 'dev' into rep-room-acl
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user