mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-24 20:06:37 +00:00
Merge branch 'dev' into cli-lna-command
This commit is contained in:
@@ -52,7 +52,7 @@
|
||||
#define CMD_SEND_BINARY_REQ 50
|
||||
#define CMD_FACTORY_RESET 51
|
||||
#define CMD_SEND_PATH_DISCOVERY_REQ 52
|
||||
#define CMD_SET_FLOOD_SCOPE 54 // v8+
|
||||
#define CMD_SET_FLOOD_SCOPE_KEY 54 // v8+
|
||||
#define CMD_SEND_CONTROL_DATA 55 // v8+
|
||||
#define CMD_GET_STATS 56 // v8+, second byte is stats type
|
||||
#define CMD_SEND_ANON_REQ 57
|
||||
@@ -60,6 +60,9 @@
|
||||
#define CMD_GET_AUTOADD_CONFIG 59
|
||||
#define CMD_GET_ALLOWED_REPEAT_FREQ 60
|
||||
#define CMD_SET_PATH_HASH_MODE 61
|
||||
#define CMD_SEND_CHANNEL_DATA 62
|
||||
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63
|
||||
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64
|
||||
|
||||
// Stats sub-types for CMD_GET_STATS
|
||||
#define STATS_TYPE_CORE 0
|
||||
@@ -93,6 +96,10 @@
|
||||
#define RESP_CODE_STATS 24 // v8+, second byte is stats type
|
||||
#define RESP_CODE_AUTOADD_CONFIG 25
|
||||
#define RESP_ALLOWED_REPEAT_FREQ 26
|
||||
#define RESP_CODE_CHANNEL_DATA_RECV 27
|
||||
#define RESP_CODE_DEFAULT_FLOOD_SCOPE 28
|
||||
|
||||
#define MAX_CHANNEL_DATA_LENGTH (MAX_FRAME_SIZE - 9)
|
||||
|
||||
#define SEND_TIMEOUT_BASE_MILLIS 500
|
||||
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
|
||||
@@ -206,7 +213,8 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, uint32_t& last_mod, co
|
||||
}
|
||||
|
||||
bool MyMesh::Frame::isChannelMsg() const {
|
||||
return buf[0] == RESP_CODE_CHANNEL_MSG_RECV || buf[0] == RESP_CODE_CHANNEL_MSG_RECV_V3;
|
||||
return buf[0] == RESP_CODE_CHANNEL_MSG_RECV || buf[0] == RESP_CODE_CHANNEL_MSG_RECV_V3 ||
|
||||
buf[0] == RESP_CODE_CHANNEL_DATA_RECV;
|
||||
}
|
||||
|
||||
void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) {
|
||||
@@ -476,27 +484,32 @@ bool MyMesh::allowPacketForward(const mesh::Packet* packet) {
|
||||
return _prefs.client_repeat != 0;
|
||||
}
|
||||
|
||||
void MyMesh::sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis) {
|
||||
// TODO: dynamic send_scope, depending on recipient and current 'home' Region
|
||||
if (send_scope.isNull()) {
|
||||
void MyMesh::sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis) {
|
||||
if (scope.isNull()) {
|
||||
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1);
|
||||
} else {
|
||||
uint16_t codes[2];
|
||||
codes[0] = send_scope.calcTransportCode(pkt);
|
||||
codes[0] = scope.calcTransportCode(pkt);
|
||||
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
|
||||
sendFlood(pkt, codes, delay_millis, _prefs.path_hash_mode + 1);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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
|
||||
if (send_scope.isNull()) {
|
||||
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1);
|
||||
} else {
|
||||
uint16_t codes[2];
|
||||
codes[0] = send_scope.calcTransportCode(pkt);
|
||||
codes[1] = 0; // REVISIT: set to 'home' Region, for sender/return region?
|
||||
sendFlood(pkt, codes, delay_millis, _prefs.path_hash_mode + 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp,
|
||||
@@ -566,6 +579,41 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyMesh::onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
|
||||
const uint8_t *data, size_t data_len) {
|
||||
if (data_len > MAX_CHANNEL_DATA_LENGTH) {
|
||||
MESH_DEBUG_PRINTLN("onChannelDataRecv: dropping payload_len=%d exceeds frame limit=%d",
|
||||
(uint32_t)data_len, (uint32_t)MAX_CHANNEL_DATA_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
out_frame[i++] = RESP_CODE_CHANNEL_DATA_RECV;
|
||||
out_frame[i++] = (int8_t)(pkt->getSNR() * 4);
|
||||
out_frame[i++] = 0; // reserved1
|
||||
out_frame[i++] = 0; // reserved2
|
||||
|
||||
uint8_t channel_idx = findChannelIdx(channel);
|
||||
out_frame[i++] = channel_idx;
|
||||
out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
|
||||
out_frame[i++] = (uint8_t)(data_type & 0xFF);
|
||||
out_frame[i++] = (uint8_t)(data_type >> 8);
|
||||
out_frame[i++] = (uint8_t)data_len;
|
||||
|
||||
int copy_len = (int)data_len;
|
||||
if (copy_len > 0) {
|
||||
memcpy(&out_frame[i], data, copy_len);
|
||||
i += copy_len;
|
||||
}
|
||||
addToOfflineQueue(out_frame, i);
|
||||
|
||||
if (_serial->isConnected()) {
|
||||
uint8_t frame[1];
|
||||
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
||||
_serial->writeFrame(frame, 1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data,
|
||||
uint8_t len, uint8_t *reply) {
|
||||
if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) {
|
||||
@@ -856,6 +904,17 @@ void MyMesh::begin(bool has_display) {
|
||||
strcpy(_prefs.node_name, pub_key_hex);
|
||||
#endif
|
||||
|
||||
// if build provides default-scope, init with that
|
||||
#ifdef DEFAULT_FLOOD_SCOPE_NAME
|
||||
strcpy(_prefs.default_scope_name, DEFAULT_FLOOD_SCOPE_NAME);
|
||||
{
|
||||
TransportKeyStore temp;
|
||||
TransportKey key;
|
||||
temp.getAutoKeyFor(0, "#" DEFAULT_FLOOD_SCOPE_NAME, key);
|
||||
memcpy(_prefs.default_scope_key, key.key, sizeof(key.key));
|
||||
}
|
||||
#endif
|
||||
|
||||
// load persisted prefs
|
||||
_store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon);
|
||||
|
||||
@@ -1046,7 +1105,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
? ERR_CODE_NOT_FOUND
|
||||
: ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_*
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg
|
||||
} else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel text msg
|
||||
int i = 1;
|
||||
uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN
|
||||
uint8_t channel_idx = cmd_frame[i++];
|
||||
@@ -1066,6 +1125,46 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
|
||||
}
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_CHANNEL_DATA) { // send GroupChannel datagram
|
||||
if (len < 4) {
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
return;
|
||||
}
|
||||
int i = 1;
|
||||
uint8_t channel_idx = cmd_frame[i++];
|
||||
uint8_t path_len = cmd_frame[i++];
|
||||
|
||||
// validate path len, allowing 0xFF for flood
|
||||
if (!mesh::Packet::isValidPathLen(path_len) && path_len != OUT_PATH_UNKNOWN) {
|
||||
MESH_DEBUG_PRINTLN("CMD_SEND_CHANNEL_DATA invalid path size: %d", path_len);
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse provided path if not flood
|
||||
uint8_t path[MAX_PATH_SIZE];
|
||||
if (path_len != OUT_PATH_UNKNOWN) {
|
||||
i += mesh::Packet::writePath(path, &cmd_frame[i], path_len);
|
||||
}
|
||||
|
||||
uint16_t data_type = ((uint16_t)cmd_frame[i]) | (((uint16_t)cmd_frame[i + 1]) << 8);
|
||||
i += 2;
|
||||
const uint8_t *payload = &cmd_frame[i];
|
||||
int payload_len = (len > (size_t)i) ? (int)(len - i) : 0;
|
||||
|
||||
ChannelDetails channel;
|
||||
if (!getChannel(channel_idx, channel)) {
|
||||
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
|
||||
} else if (data_type == DATA_TYPE_RESERVED) {
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
} else if (payload_len > MAX_CHANNEL_DATA_LENGTH) {
|
||||
MESH_DEBUG_PRINTLN("CMD_SEND_CHANNEL_DATA payload too long: %d > %d", payload_len, MAX_CHANNEL_DATA_LENGTH);
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
} else if (sendGroupData(channel.channel, path, path_len, data_type, payload, payload_len)) {
|
||||
writeOKFrame();
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_TABLE_FULL);
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list
|
||||
if (_iter_started) {
|
||||
writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy
|
||||
@@ -1135,7 +1234,9 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
if (pkt) {
|
||||
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
||||
unsigned long delay_millis = 0;
|
||||
sendFlood(pkt, delay_millis, _prefs.path_hash_mode + 1);
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
sendFloodScoped(default_scope, pkt, delay_millis);
|
||||
} else {
|
||||
sendZeroHop(pkt);
|
||||
}
|
||||
@@ -1811,13 +1912,39 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_FILE_IO_ERROR);
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SET_FLOOD_SCOPE && len >= 2 && cmd_frame[1] == 0) {
|
||||
} 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
|
||||
} else {
|
||||
memset(send_scope.key, 0, sizeof(send_scope.key)); // set scope to null
|
||||
}
|
||||
writeOKFrame();
|
||||
} else if (cmd_frame[0] == CMD_SET_DEFAULT_FLOOD_SCOPE && len >= 1) {
|
||||
if (len >= 1+31+16) {
|
||||
int n = strlen((char *) &cmd_frame[1]);
|
||||
if (n > 0 && n < 31) {
|
||||
strcpy(_prefs.default_scope_name, (char *) &cmd_frame[1]);
|
||||
memcpy(_prefs.default_scope_key, &cmd_frame[1+31], 16);
|
||||
savePrefs();
|
||||
writeOKFrame();
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
|
||||
}
|
||||
} else {
|
||||
memset(_prefs.default_scope_name, 0, sizeof(_prefs.default_scope_name)); // set default scope to null
|
||||
memset(_prefs.default_scope_key, 0, sizeof(_prefs.default_scope_key));
|
||||
savePrefs();
|
||||
writeOKFrame();
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_GET_DEFAULT_FLOOD_SCOPE) {
|
||||
out_frame[0] = RESP_CODE_DEFAULT_FLOOD_SCOPE;
|
||||
if (strlen(_prefs.default_scope_name) > 0) {
|
||||
memcpy(&out_frame[1], _prefs.default_scope_name, 31);
|
||||
memcpy(&out_frame[1+31], _prefs.default_scope_key, 16);
|
||||
_serial->writeFrame(out_frame, 1+31+16);
|
||||
} else {
|
||||
_serial->writeFrame(out_frame, 1); // no name or key means null
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_CONTROL_DATA && len >= 2 && (cmd_frame[1] & 0x80) != 0) {
|
||||
auto resp = createControlData(&cmd_frame[1], len - 1);
|
||||
if (resp) {
|
||||
|
||||
Reference in New Issue
Block a user