mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-01 09:46:22 +00:00
Merge upstream/main (v1.16.0) into wio-unified
Merge 254 upstream commits. Highlights relevant to the Wio fork: native NRF52 companion power-saving (sleep when !hasPendingWork), preamble 16->32 for SF<9, generic sensor-registration model, CMD_SEND_RAW_PACKET, isEink() display abstraction, KEEP_DISPLAY_ON_USB, contacts-sync/transient fixes. Conflicts resolved (11 files): - buzzer.h/.cpp: keep NRF52 include guard + our begin()->startup(); fold in upstream doc comment. - platformio (wio + eink): keep our slim env layout, add upstream kiss_modem env (+ debug_tool=stlink on eink ble). - GxEPDDisplay.h: take upstream isEink() override. - EnvironmentSensorManager.h: take upstream's wider #if guard. - DataStore.cpp: take upstream saveContacts(filter) signature, keep our ::openWrite (member openWrite would shadow the global 2-arg overload). - main.cpp: keep our watchdog init + add board.onBootComplete(); adopt upstream's `if(!hasPendingWork()) sleep` loop. - MyMesh.h: version -> v1.16-solo.0, build date 6 Jun 2026. - MyMesh.cpp: keep both CMD codes (SCREENSHOT 66 + RAW_PACKET 65), both field inits, both handlers, our screenshot fns + upstream saveContacts/save_filter, upstream hasPendingWork() + our MyMeshBot include. - UITask.cpp: keep our solo splash/clock page/snprintf/buzzer init; merge auto-off (+ opt-in KEEP_DISPLAY_ON_USB); merge low-batt shutdown (our EMA + prefs threshold + upstream's !isExternalPowered() guard and eink-aware delay). Post-merge drift fixes (upstream API/architecture changes, not conflicts): - applyTxPower(): radio_set_tx_power() removed upstream -> radio_driver.setTxPower(). - Sensor refactor dropped the per-sensor *_initialized flags our getAvailableLPPTypes() relied on; removed that override and the SENSORS page now derives available LPP types from the populated sensors_lpp buffer. README kept ours via .gitattributes merge=ours. Builds verified on all 5 Wio envs (dual, eink dual, radio_ble, dual_dev, eink_dual_dev). Not yet hardware-verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
#define CMD_REBOOT 19
|
||||
#define CMD_GET_BATT_AND_STORAGE 20 // was CMD_GET_BATTERY_VOLTAGE
|
||||
#define CMD_SET_TUNING_PARAMS 21
|
||||
#define CMD_DEVICE_QEURY 22
|
||||
#define CMD_DEVICE_QUERY 22
|
||||
#define CMD_EXPORT_PRIVATE_KEY 23
|
||||
#define CMD_IMPORT_PRIVATE_KEY 24
|
||||
#define CMD_SEND_RAW_DATA 25
|
||||
@@ -68,6 +68,7 @@
|
||||
#define CMD_SEND_CHANNEL_DATA 62
|
||||
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63
|
||||
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64
|
||||
#define CMD_SEND_RAW_PACKET 65
|
||||
#ifdef ENABLE_SCREENSHOT
|
||||
#define CMD_GET_SCREENSHOT 66 // Request screenshot from display
|
||||
#endif
|
||||
@@ -90,7 +91,7 @@
|
||||
#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE
|
||||
#define RESP_CODE_EXPORT_CONTACT 11
|
||||
#define RESP_CODE_BATT_AND_STORAGE 12 // a reply to a CMD_GET_BATT_AND_STORAGE
|
||||
#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY
|
||||
#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QUERY
|
||||
#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY
|
||||
#define RESP_CODE_DISABLED 15
|
||||
#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3)
|
||||
@@ -506,19 +507,27 @@ void MyMesh::sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint3
|
||||
|
||||
void MyMesh::sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis) {
|
||||
// TODO: dynamic send_scope, depending on recipient and current 'home' Region
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
if (send_unscoped) {
|
||||
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); // app has explicitly requested un-scoped
|
||||
} else {
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
|
||||
auto scope = send_scope.isNull() ? &default_scope : &send_scope;
|
||||
sendFloodScoped(*scope, pkt, delay_millis);
|
||||
auto scope = send_scope.isNull() ? &default_scope : &send_scope;
|
||||
sendFloodScoped(*scope, pkt, delay_millis);
|
||||
}
|
||||
}
|
||||
void MyMesh::sendFloodScoped(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t delay_millis) {
|
||||
// TODO: have per-channel send_scope
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
if (send_unscoped) {
|
||||
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1); // app has explicitly requested un-scoped
|
||||
} else {
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
|
||||
auto scope = send_scope.isNull() ? &default_scope : &send_scope;
|
||||
sendFloodScoped(*scope, pkt, delay_millis);
|
||||
auto scope = send_scope.isNull() ? &default_scope : &send_scope;
|
||||
sendFloodScoped(*scope, pkt, delay_millis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,6 +1081,8 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||
_ping_callback_arg = NULL;
|
||||
memset(_ping_results, 0, sizeof(_ping_results));
|
||||
|
||||
send_unscoped = false;
|
||||
|
||||
// defaults
|
||||
memset(&_prefs, 0, sizeof(_prefs));
|
||||
_prefs.airtime_factor = 1.0;
|
||||
@@ -1186,8 +1197,8 @@ void MyMesh::begin(bool has_display) {
|
||||
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
||||
_store->loadChannels(this);
|
||||
|
||||
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||
radio_set_tx_power(_prefs.tx_power_dbm);
|
||||
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
||||
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
|
||||
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
|
||||
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
|
||||
@@ -1208,9 +1219,13 @@ struct FreqRange {
|
||||
};
|
||||
|
||||
static FreqRange repeat_freq_ranges[] = {
|
||||
#ifdef ALLOWED_REPEAT_FREQ_RANGE
|
||||
ALLOWED_REPEAT_FREQ_RANGE
|
||||
#else
|
||||
{ 433000, 433000 },
|
||||
{ 869000, 869000 },
|
||||
{ 869495, 869495 },
|
||||
{ 918000, 918000 }
|
||||
#endif
|
||||
};
|
||||
|
||||
bool MyMesh::isValidClientRepeatFreq(uint32_t f) const {
|
||||
@@ -1227,7 +1242,7 @@ void MyMesh::startInterface(BaseSerialInterface &serial) {
|
||||
}
|
||||
|
||||
void MyMesh::handleCmdFrame(size_t len) {
|
||||
if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection
|
||||
if (cmd_frame[0] == CMD_DEVICE_QUERY && len >= 2) { // sent when app establishes connection
|
||||
app_target_ver = cmd_frame[1]; // which version of protocol does app understand
|
||||
|
||||
int i = 0;
|
||||
@@ -1333,7 +1348,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
} else {
|
||||
writeErrFrame(recipient == NULL
|
||||
? ERR_CODE_NOT_FOUND
|
||||
: ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_*
|
||||
: ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsupported TXT_TYPE_*
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel text msg
|
||||
int i = 1;
|
||||
@@ -1611,7 +1626,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
_prefs.client_repeat = repeat;
|
||||
savePrefs();
|
||||
|
||||
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
|
||||
MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf,
|
||||
(uint32_t)cr);
|
||||
|
||||
@@ -1628,7 +1643,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
} else {
|
||||
_prefs.tx_power_dbm = power;
|
||||
savePrefs();
|
||||
radio_set_tx_power(_prefs.tx_power_dbm);
|
||||
radio_driver.setTxPower(_prefs.tx_power_dbm);
|
||||
writeOKFrame();
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) {
|
||||
@@ -1759,6 +1774,15 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
} else if (cmd_frame[0] == CMD_SEND_ANON_REQ && len > 1 + PUB_KEY_SIZE) {
|
||||
uint8_t *pub_key = &cmd_frame[1];
|
||||
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
|
||||
ContactInfo anon;
|
||||
if (recipient == NULL) { // FIRMWARE_VER_CODE 13+, allow non-contact requests
|
||||
memset(&anon, 0, sizeof(anon));
|
||||
memcpy(anon.id.pub_key, pub_key, PUB_KEY_SIZE);
|
||||
anon.out_path_len = 0; // default to zero-hop direct
|
||||
anon.type = ADV_TYPE_NONE; // unknown
|
||||
|
||||
if (addContact(anon)) recipient = &anon;
|
||||
}
|
||||
uint8_t *data = &cmd_frame[1 + PUB_KEY_SIZE];
|
||||
if (recipient) {
|
||||
uint32_t tag, est_timeout;
|
||||
@@ -1775,7 +1799,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
_serial->writeFrame(out_frame, 10);
|
||||
}
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
|
||||
writeErrFrame(ERR_CODE_TABLE_FULL); // contacts full
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_STATUS_REQ && len >= 1 + PUB_KEY_SIZE) {
|
||||
uint8_t *pub_key = &cmd_frame[1];
|
||||
@@ -2131,10 +2155,14 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SET_FLOOD_SCOPE_KEY && len >= 2 && cmd_frame[1] == 0) {
|
||||
if (len >= 2 + 16) {
|
||||
memcpy(send_scope.key, &cmd_frame[2], sizeof(send_scope.key)); // set curr scope TransportKey
|
||||
memcpy(send_scope.key, &cmd_frame[2], sizeof(send_scope.key)); // set scope override TransportKey
|
||||
} else {
|
||||
memset(send_scope.key, 0, sizeof(send_scope.key)); // set scope to null
|
||||
memset(send_scope.key, 0, sizeof(send_scope.key)); // reset scope override
|
||||
}
|
||||
send_unscoped = false;
|
||||
writeOKFrame();
|
||||
} else if (cmd_frame[0] == CMD_SET_FLOOD_SCOPE_KEY && len >= 2 && cmd_frame[1] == 1) { // ver 12+
|
||||
send_unscoped = true;
|
||||
writeOKFrame();
|
||||
} else if (cmd_frame[0] == CMD_SET_DEFAULT_FLOOD_SCOPE && len >= 1) {
|
||||
if (len >= 1+31+16) {
|
||||
@@ -2195,6 +2223,19 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
memcpy(&out_frame[i], &r->upper_freq, 4); i += 4;
|
||||
}
|
||||
_serial->writeFrame(out_frame, i);
|
||||
} else if (cmd_frame[0] == CMD_SEND_RAW_PACKET && len >= 4) {
|
||||
auto pkt = obtainNewPacket();
|
||||
if (pkt) {
|
||||
uint8_t priority = cmd_frame[1];
|
||||
if (tryParsePacket(pkt, &cmd_frame[2], len - 2)) {
|
||||
sendPacket(pkt, priority, 0);
|
||||
writeOKFrame();
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
}
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_TABLE_FULL);
|
||||
}
|
||||
#ifdef ENABLE_SCREENSHOT
|
||||
} else if (cmd_frame[0] == CMD_GET_SCREENSHOT) {
|
||||
handleScreenshotRequest();
|
||||
@@ -2268,6 +2309,14 @@ void MyMesh::sendScreenshotResponse(DisplayDriver* display, const uint8_t* buffe
|
||||
}
|
||||
#endif // ENABLE_SCREENSHOT
|
||||
|
||||
static bool save_filter(const ContactInfo& c) {
|
||||
return c.type != ADV_TYPE_NONE; // don't save the transient/anon entries
|
||||
}
|
||||
|
||||
void MyMesh::saveContacts() {
|
||||
_store->saveContacts(this, save_filter);
|
||||
}
|
||||
|
||||
void MyMesh::enterCLIRescue() {
|
||||
_cli_rescue = true;
|
||||
cli_command[0] = 0;
|
||||
@@ -2454,7 +2503,15 @@ void MyMesh::checkSerialInterface() {
|
||||
&& !_serial->isWriteBusy() // don't spam the Serial Interface too quickly!
|
||||
) {
|
||||
ContactInfo contact;
|
||||
if (_iter.hasNext(this, contact)) {
|
||||
bool found = false;
|
||||
while (_iter.hasNext(this, contact)) {
|
||||
if (contact.type != ADV_TYPE_NONE) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter
|
||||
writeContactRespFrame(RESP_CODE_CONTACT, contact);
|
||||
if (contact.lastmod > _most_recent_lastmod) {
|
||||
@@ -2521,4 +2578,9 @@ bool MyMesh::advert() {
|
||||
}
|
||||
}
|
||||
|
||||
// To check if there is pending work
|
||||
bool MyMesh::hasPendingWork() const {
|
||||
return _mgr->getOutboundTotal() > 0 || dirty_contacts_expiry != 0;
|
||||
}
|
||||
|
||||
#include "MyMeshBot.h"
|
||||
|
||||
Reference in New Issue
Block a user