|
|
@@ -58,6 +58,7 @@
|
|
|
#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
|
|
|
|
|
|
// Stats sub-types for CMD_GET_STATS
|
|
|
#define STATS_TYPE_CORE 0
|
|
|
@@ -91,6 +92,9 @@
|
|
|
#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 MAX_CHANNEL_DATA_LENGTH (MAX_FRAME_SIZE - 9)
|
|
|
|
|
|
#define SEND_TIMEOUT_BASE_MILLIS 500
|
|
|
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
|
|
|
@@ -204,7 +208,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) {
|
|
|
@@ -564,6 +569,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) {
|
|
|
@@ -1041,7 +1081,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++];
|
|
|
@@ -1061,6 +1101,31 @@ 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;
|
|
|
+ uint16_t data_type = ((uint16_t)cmd_frame[i]) | (((uint16_t)cmd_frame[i + 1]) << 8);
|
|
|
+ i += 2;
|
|
|
+ uint8_t channel_idx = cmd_frame[i++];
|
|
|
+ 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 == 0) {
|
|
|
+ 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, 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
|