sync with arduino/dev

This commit is contained in:
liquidraver committed 2026-03-24 20:36:36 +01:00
1 parent e2f13e2292
commit 8dd6f149f8
8 files changed
+159 -22

No files matched your search

+84 -4
View File
@@ -73,6 +73,7 @@ LOG_MODULE_REGISTER(zephcore_companion, CONFIG_ZEPHCORE_MAIN_LOG_LEVEL);
#define CMD_GET_AUTOADD_CONFIG 0x3B
#define CMD_GET_ALLOWED_REPEAT_FREQ 0x3C
#define CMD_SET_PATH_HASH_MODE 0x3D
#define CMD_SEND_CHANNEL_DATA 0x3E
/* Response packet types */
#define PACKET_OK 0x00
@@ -102,6 +103,9 @@ LOG_MODULE_REGISTER(zephcore_companion, CONFIG_ZEPHCORE_MAIN_LOG_LEVEL);
#define PACKET_STATS 0x18
#define PACKET_AUTOADD_CONFIG 0x19
#define PACKET_ALLOWED_REPEAT_FREQ 0x1A
#define PACKET_CHANNEL_DATA_RECV 0x1B
#define MAX_CHANNEL_DATA_LENGTH (MAX_FRAME_SIZE - 9)
#define MAX_SIGN_DATA_LEN (8 * 1024)
@@ -355,8 +359,8 @@ size_t CompanionMesh::serializeContact(uint8_t *buf, const ContactInfo &c, uint8
static bool isChannelMessage(const uint8_t *buf)
{
// Channel messages have PACKET_CHANNEL_MSG_V3 (0x11) or PACKET_CHANNEL_MSG_RECV (0x08)
return buf[0] == PACKET_CHANNEL_MSG_V3 || buf[0] == PACKET_CHANNEL_MSG_RECV;
// Channel messages have PACKET_CHANNEL_MSG_V3 (0x11) or PACKET_CHANNEL_MSG_RECV (0x08) or PACKET_CHANNEL_DATA_RECV (0x1B)
return buf[0] == PACKET_CHANNEL_MSG_V3 || buf[0] == PACKET_CHANNEL_MSG_RECV || buf[0] == PACKET_CHANNEL_DATA_RECV;
}
void CompanionMesh::queueOfflineMessage(const uint8_t *data, size_t len)
@@ -745,6 +749,41 @@ void CompanionMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh
sendPush(PUSH_CODE_MSG_WAITING);
}
void CompanionMesh::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) {
LOG_WRN("onChannelDataRecv: dropping payload_len=%d exceeds frame limit=%d",
(int)data_len, (int)MAX_CHANNEL_DATA_LENGTH);
return;
}
uint8_t frame[MAX_FRAME_SIZE];
int i = 0;
frame[i++] = PACKET_CHANNEL_DATA_RECV;
frame[i++] = pkt ? (int8_t)(pkt->getSNR() * 4) : 0;
frame[i++] = 0; // reserved1
frame[i++] = 0; // reserved2
uint8_t channel_idx = findChannelIdx(channel);
frame[i++] = channel_idx;
frame[i++] = (pkt && pkt->isRouteFlood()) ? pkt->path_len : 0xFF;
frame[i++] = (uint8_t)(data_type & 0xFF);
frame[i++] = (uint8_t)(data_type >> 8);
frame[i++] = (uint8_t)data_len;
int copy_len = (int)data_len;
if (copy_len > 0) {
memcpy(&frame[i], data, copy_len);
i += copy_len;
}
LOG_INF("onChannelDataRecv: frame_len=%d channel_idx=%d data_type=%d",
i, channel_idx, (int)data_type);
queueOfflineMessage(frame, i);
sendPush(PUSH_CODE_MSG_WAITING);
}
uint8_t CompanionMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp,
const uint8_t *data, uint8_t len, uint8_t *reply)
{
@@ -1772,7 +1811,7 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
// If repeat requested, validate frequency against allowed bands
if (repeat && !isValidClientRepeatFreq(freq)) {
sendPacketError(ERR_ILLEGAL_ARG);
} else if (freq >= 300000 && freq <= 2500000 &&
} else if (freq >= 150000 && freq <= 2500000 &&
bw >= 7000 && bw <= 500000 &&
sf >= 5 && sf <= 12 &&
cr >= 5 && cr <= 8) {
@@ -1874,7 +1913,7 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
#endif
static const uint8_t fw_build[12] = FIRMWARE_BUILD_DATE;
static const uint8_t model[40] = CONFIG_ZEPHCORE_BOARD_NAME;
static const uint8_t version[20] = "v1.14.0-zephyr";
static const uint8_t version[20] = "v1.14.1-zephyr";
uint8_t rsp[82];
rsp[0] = PACKET_DEVICE_INFO;
rsp[1] = 10; // FIRMWARE_VER_CODE - v10 = path_hash_mode support
@@ -2606,6 +2645,47 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
}
return true;
case CMD_SEND_CHANNEL_DATA: {
if (len < 4) {
sendPacketError(ERR_ILLEGAL_ARG);
return true;
}
int i = 1;
uint8_t channel_idx = data[i++];
uint8_t path_len = data[i++];
if (!mesh::Packet::isValidPathLen(path_len) && path_len != OUT_PATH_UNKNOWN) {
LOG_WRN("CMD_SEND_CHANNEL_DATA invalid path size: %d", path_len);
sendPacketError(ERR_ILLEGAL_ARG);
return true;
}
uint8_t path[MAX_PATH_SIZE];
if (path_len != OUT_PATH_UNKNOWN) {
i += mesh::Packet::writePath(path, &data[i], path_len);
}
uint16_t data_type = ((uint16_t)data[i]) | (((uint16_t)data[i + 1]) << 8);
i += 2;
const uint8_t *payload = &data[i];
int payload_len = (len > (size_t)i) ? (int)(len - i) : 0;
ChannelDetails channel;
if (!getChannel(channel_idx, channel)) {
sendPacketError(ERR_NOT_FOUND);
} else if (data_type == DATA_TYPE_RESERVED) {
sendPacketError(ERR_ILLEGAL_ARG);
} else if (payload_len > MAX_CHANNEL_DATA_LENGTH) {
LOG_WRN("CMD_SEND_CHANNEL_DATA payload too long: %d > %d", payload_len, MAX_CHANNEL_DATA_LENGTH);
sendPacketError(ERR_ILLEGAL_ARG);
} else if (sendGroupData(channel.channel, path, path_len, data_type, payload, payload_len)) {
sendPacketOk();
} else {
sendPacketError(ERR_TABLE_FULL);
}
return true;
}
case CMD_SEND_ANON_REQ:
if (len >= 1 + PUB_KEY_SIZE + 1) {
ContactInfo *contact = lookupContactByPubKey(&data[1], PUB_KEY_SIZE);
+2
View File
@@ -230,6 +230,8 @@ protected:
uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override;
void onSendTimeout() override;
void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, const char *text) override;
void onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
const uint8_t *data, size_t data_len) override;
uint8_t onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, uint8_t len, uint8_t *reply) override;
void onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) override;
+1 -1
View File
@@ -25,7 +25,7 @@
#include "RepeaterDataStore.h"
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.14.0-zephyr"
#define FIRMWARE_VERSION "v1.14.1-zephyr"
#endif
#ifndef FIRMWARE_BUILD_DATE
+54 -6
View File
@@ -388,12 +388,28 @@ int BaseChatMesh::searchChannelsByHash(const uint8_t *hash, mesh::GroupChannel d
void BaseChatMesh::onGroupDataRecv(mesh::Packet *packet, uint8_t type, const mesh::GroupChannel &channel,
uint8_t *data, size_t len)
{
uint8_t txt_type = data[4];
if (type == PAYLOAD_TYPE_GRP_TXT && len > 5 && (txt_type >> 2) == 0) {
uint32_t timestamp;
memcpy(&timestamp, data, 4);
data[len] = 0;
onChannelMessageRecv(channel, packet, timestamp, (const char *)&data[5]);
if (type == PAYLOAD_TYPE_GRP_TXT) {
uint8_t txt_type = data[4];
if (len > 5 && (txt_type >> 2) == 0) {
uint32_t timestamp;
memcpy(&timestamp, data, 4);
data[len] = 0;
onChannelMessageRecv(channel, packet, timestamp, (const char *)&data[5]);
}
} else if (type == PAYLOAD_TYPE_GRP_DATA) {
if (len < 3) {
LOG_DBG("onGroupDataRecv: dropping short group data payload len=%d", (int)len);
return;
}
uint16_t data_type = ((uint16_t)data[0]) | (((uint16_t)data[1]) << 8);
uint8_t data_len = data[2];
size_t available_len = len - 3;
if (data_len > available_len) {
LOG_DBG("onGroupDataRecv: dropping malformed group data type=%d len=%d available=%d",
(int)data_type, (int)data_len, (int)available_len);
return;
}
onChannelDataRecv(channel, packet, data_type, &data[3], data_len);
}
}
@@ -505,6 +521,38 @@ bool BaseChatMesh::sendGroupMessage(uint32_t timestamp, mesh::GroupChannel &chan
return false;
}
bool BaseChatMesh::sendGroupData(mesh::GroupChannel &channel, uint8_t *path, uint8_t path_len,
uint16_t data_type, const uint8_t *data, int data_len)
{
if (data_len < 0) {
LOG_DBG("sendGroupData: invalid negative data_len=%d", data_len);
return false;
}
if (data_len > MAX_GROUP_DATA_LENGTH) {
LOG_DBG("sendGroupData: data_len=%d exceeds max=%d", data_len, MAX_GROUP_DATA_LENGTH);
return false;
}
uint8_t temp[3 + MAX_GROUP_DATA_LENGTH];
temp[0] = (uint8_t)(data_type & 0xFF);
temp[1] = (uint8_t)(data_type >> 8);
temp[2] = (uint8_t)data_len;
if (data_len > 0) memcpy(&temp[3], data, data_len);
mesh::Packet *pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_DATA, channel, temp, 3 + data_len);
if (pkt == nullptr) {
LOG_DBG("sendGroupData: unable to create group datagram, data_len=%d", data_len);
return false;
}
if (path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(channel, pkt);
} else {
sendDirect(pkt, path, path_len);
}
return true;
}
bool BaseChatMesh::shareContactZeroHop(const ContactInfo &contact)
{
int plen = getBlobByKey(contact.id.pub_key, PUB_KEY_SIZE, temp_buf);
+4
View File
@@ -133,6 +133,8 @@ protected:
virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0;
virtual void onSendTimeout() = 0;
virtual void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, const char *text) = 0;
virtual void onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
const uint8_t *data, size_t data_len) {}
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;
@@ -168,6 +170,8 @@ public:
uint32_t &est_timeout);
bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel &channel, const char *sender_name,
const char *text, int text_len);
bool sendGroupData(mesh::GroupChannel &channel, uint8_t *path, uint8_t path_len,
uint16_t data_type, const uint8_t *data, int data_len);
int sendLogin(const ContactInfo &recipient, const char *password, uint32_t &est_timeout);
int sendAnonReq(const ContactInfo &recipient, const uint8_t *data, uint8_t len, uint32_t &tag, uint32_t &est_timeout);
int sendRequest(const ContactInfo &recipient, uint8_t req_type, uint32_t &tag, uint32_t &est_timeout);
+11 -11
View File
@@ -137,7 +137,7 @@ void CommonCLI::loadPrefs(const char* path) {
_prefs->airtime_factor *= 10.0f;
}
_prefs->airtime_factor = constrain(_prefs->airtime_factor, 0.0f, 99.0f);
_prefs->freq = constrain(_prefs->freq, 400.0f, 2500.0f);
_prefs->freq = constrain(_prefs->freq, 150.0f, 2500.0f);
_prefs->bw = constrain(_prefs->bw, 7.8f, 500.0f);
_prefs->sf = constrain(_prefs->sf, (uint8_t)5, (uint8_t)12);
_prefs->cr = constrain(_prefs->cr, (uint8_t)5, (uint8_t)8);
@@ -377,12 +377,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
uint8_t sf = num > 2 ? atoi(parts[2]) : 0;
uint8_t cr = num > 3 ? atoi(parts[3]) : 0;
int temp_timeout_mins = num > 4 ? atoi(parts[4]) : 0;
if (freq >= 300.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 &&
if (freq >= 150.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 &&
cr >= 5 && cr <= 8 && bw >= 7.0f && bw <= 500.0f && temp_timeout_mins > 0) {
_callbacks->applyTempRadioParams(freq, bw, sf, cr, temp_timeout_mins);
snprintf(reply, CLI_REPLY_SIZE, "OK - temp params for %d mins", temp_timeout_mins);
} else {
strcpy(reply, "Error: freq 300-2500, bw 7-500, sf 5-12, cr 5-8, timeout>0");
strcpy(reply, "Error: freq 150-2500, bw 7-500, sf 5-12, cr 5-8, timeout>0");
}
} else if (memcmp(command, "password ", 9) == 0) {
StrHelper::strncpy(_prefs->password, &command[9], sizeof(_prefs->password));
@@ -499,7 +499,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else {
snprintf(reply, CLI_REPLY_SIZE, "> %.3f", (double)adc_mult);
}
} else if (memcmp(config, "rxboost", 7) == 0) {
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
snprintf(reply, CLI_REPLY_SIZE, "> %d", (int)_prefs->rx_boost);
} else if (memcmp(config, "rxduty", 6) == 0) {
snprintf(reply, CLI_REPLY_SIZE, "> %d", (int)_prefs->rx_duty_cycle);
@@ -617,7 +617,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
float bw = num > 1 ? strtof(parts[1], nullptr) : 0.0f;
uint8_t sf = num > 2 ? atoi(parts[2]) : 0;
uint8_t cr = num > 3 ? atoi(parts[3]) : 0;
if (freq >= 300.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 &&
if (freq >= 150.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 &&
cr >= 5 && cr <= 8 && bw >= 7.0f && bw <= 500.0f) {
_prefs->sf = sf;
_prefs->cr = cr;
@@ -626,7 +626,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_callbacks->savePrefs();
strcpy(reply, "OK - reboot to apply");
} else {
strcpy(reply, "Error: freq 300-2500, bw 7-500, sf 5-12, cr 5-8");
strcpy(reply, "Error: freq 150-2500, bw 7-500, sf 5-12, cr 5-8");
}
} else if (memcmp(config, "lat ", 4) == 0) {
_prefs->node_lat = atof(&config[4]);
@@ -744,12 +744,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
}
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) {
float f = atof(&config[5]);
if (f >= 400.0f && f <= 2500.0f) {
if (f >= 150.0f && f <= 2500.0f) {
_prefs->freq = f;
savePrefs();
strcpy(reply, "OK - reboot to apply");
} else {
strcpy(reply, "Error: range 400-2500 MHz");
strcpy(reply, "Error: range 150-2500 MHz");
}
} else if (memcmp(config, "adc.multiplier ", 15) == 0) {
_prefs->adc_multiplier = atof(&config[15]);
@@ -764,12 +764,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_prefs->adc_multiplier = 0.0f;
strcpy(reply, "Error: unsupported by this board");
}
} else if (memcmp(config, "rxboost ", 8) == 0) {
int val = atoi(&config[8]);
} else if (memcmp(config, "radio.rxgain ", 13) == 0) {
int val = atoi(&config[13]);
if (val == 0 || val == 1) {
_prefs->rx_boost = (uint8_t)val;
savePrefs();
snprintf(reply, CLI_REPLY_SIZE, "OK - rxboost=%d (reboot to apply)", _prefs->rx_boost);
snprintf(reply, CLI_REPLY_SIZE, "OK - radio.rxgain=%d (reboot to apply)", _prefs->rx_boost);
} else {
strcpy(reply, "Error: must be 0 or 1");
}
+2
View File
@@ -12,6 +12,8 @@
#define TXT_TYPE_PLAIN 0 // a plain text message
#define TXT_TYPE_CLI_DATA 1 // a CLI command
#define TXT_TYPE_SIGNED_PLAIN 2 // plain text, signed by sender
#define DATA_TYPE_RESERVED 0x0000 // reserved for future use
#define DATA_TYPE_DEV 0xFFFF // developer namespace for experimenting with group/channel datagrams
class StrHelper {
public:
+1
View File
@@ -22,6 +22,7 @@
#define MAX_PACKET_PAYLOAD 184
#define MAX_PATH_SIZE 64
#define MAX_TRANS_UNIT 255
#define MAX_GROUP_DATA_LENGTH (MAX_PACKET_PAYLOAD - CIPHER_BLOCK_SIZE - 3)
#define MESH_DEBUG_PRINT(...)
#define MESH_DEBUG_PRINTLN(...)