mirror of
https://github.com/Colorado-Mesh/meshcore-bot-firmware.git
synced 2026-08-11 16:20:29 +00:00
411 lines
20 KiB
Diff
411 lines
20 KiB
Diff
diff --git a/examples/companion_radio/BotCommands.cpp b/examples/companion_radio/BotCommands.cpp
|
|
index 2c206a9..6222be5 100644
|
|
--- a/examples/companion_radio/BotCommands.cpp
|
|
+++ b/examples/companion_radio/BotCommands.cpp
|
|
@@ -62,7 +62,7 @@ bool parseUInt(const char* text, size_t len, size_t* pos, uint16_t* value) {
|
|
}
|
|
|
|
bool isSupportedSides(uint16_t sides) {
|
|
- return sides == 4 || sides == 6 || sides == 8 || sides == 10 || sides == 12 || sides == 16 || sides == 20;
|
|
+ return sides >= 2 && sides <= 1000;
|
|
}
|
|
|
|
bool parseDice(const BotCommand& command, uint16_t* count, uint16_t* sides) {
|
|
@@ -97,11 +97,57 @@ uint16_t rollOnce(uint32_t* state, uint16_t sides) {
|
|
return (uint16_t)((*state >> 16) % sides) + 1;
|
|
}
|
|
|
|
+void appendPathHex(char* output, size_t output_len, size_t* pos, const uint8_t* path, size_t path_len) {
|
|
+ static const char hex[] = "0123456789abcdef";
|
|
+ for (size_t i = 0; i < path_len; i++) {
|
|
+ if (*pos + 2 < output_len) {
|
|
+ output[*pos] = hex[path[i] >> 4];
|
|
+ output[*pos + 1] = hex[path[i] & 0x0F];
|
|
+ }
|
|
+ *pos += 2;
|
|
+ }
|
|
+ if (output_len > 0) output[*pos < output_len ? *pos : output_len - 1] = 0;
|
|
+}
|
|
+
|
|
+void formatQuarters(int8_t quarters, char* output, size_t output_len) {
|
|
+ if (!output || output_len == 0) return;
|
|
+ int value = quarters;
|
|
+ const char* sign = value < 0 ? "-" : "";
|
|
+ if (value < 0) value = -value;
|
|
+ snprintf(output, output_len, "%s%d.%02d", sign, value / 4, (value % 4) * 25);
|
|
+}
|
|
+
|
|
+BotCommandResult executeMagic8(const BotCommandContext& context, char* output, size_t output_len) {
|
|
+ static const char* responses[] = {
|
|
+ "It is certain", "Looks good", "Ask again later", "Cannot predict now", "Doubtful", "Very likely",
|
|
+ "Signs point yes", "No", "Reply hazy", "Absolutely"
|
|
+ };
|
|
+ uint32_t seed = context.random_seed ? context.random_seed : 1;
|
|
+ seed = seed * 1664525UL + 1013904223UL;
|
|
+ return writeFormatted(output, output_len, "Magic 8-ball: %s", responses[(seed >> 16) % (sizeof(responses) / sizeof(responses[0]))]);
|
|
+}
|
|
+
|
|
+BotCommandResult executePath(const BotCommandContext& context, char* output, size_t output_len) {
|
|
+ if (!context.path || context.path_len == 0 || context.path_hash_count == 0) return writeText(output, output_len, "Path unavailable");
|
|
+ if (!output || output_len == 0) return makeResult(BOT_COMMAND_RESULT_NO_SPACE, 0);
|
|
+
|
|
+ size_t byte_len = (size_t)context.path_hash_size * context.path_hash_count;
|
|
+ char snr[8];
|
|
+ formatQuarters(context.path_snr_quarters, snr, sizeof(snr));
|
|
+ int written = snprintf(output, output_len, "Path %uh x %uB snr %s: ", (unsigned)context.path_hash_count,
|
|
+ (unsigned)context.path_hash_size, snr);
|
|
+ if (written < 0) return makeResult(BOT_COMMAND_RESULT_NO_SPACE, 0);
|
|
+ size_t pos = (size_t)written;
|
|
+ appendPathHex(output, output_len, &pos, context.path, byte_len);
|
|
+ size_t actual = boundedStrLen(output, output_len);
|
|
+ return makeResult(pos >= output_len ? BOT_COMMAND_RESULT_TRUNCATED : BOT_COMMAND_RESULT_OK, actual);
|
|
+}
|
|
+
|
|
BotCommandResult executeDice(const BotCommand& command, const BotCommandContext& context, char* output, size_t output_len) {
|
|
uint16_t count = 1;
|
|
uint16_t sides = 6;
|
|
if (!parseDice(command, &count, &sides)) {
|
|
- return writeText(output, output_len, "Usage: !roll [d6|d20|2d6], sides: d4 d6 d8 d10 d12 d16 d20");
|
|
+ return writeText(output, output_len, "Usage: roll [N|dN|NdN], max 10 dice, sides 2-1000");
|
|
}
|
|
|
|
uint32_t state = context.random_seed ^ ((uint32_t)count << 16) ^ sides;
|
|
@@ -141,7 +187,7 @@ BotCommandResult executeCommand(const BotCommand& command, const BotCommandConte
|
|
size_t output_len) {
|
|
switch (command.id) {
|
|
case BOT_COMMAND_HELP:
|
|
- return writeText(output, output_len, "Commands: !ping !test !hello !about !roll [d20|2d6] !status !channels");
|
|
+ return writeText(output, output_len, "Commands: ping t hello about roll stats version path magic8 status channels");
|
|
case BOT_COMMAND_PING:
|
|
return writeText(output, output_len, "Pong!");
|
|
case BOT_COMMAND_TEST:
|
|
@@ -164,8 +210,22 @@ BotCommandResult executeCommand(const BotCommand& command, const BotCommandConte
|
|
context.testing_channel[0] ? context.testing_channel : "#testing",
|
|
context.emergency_channel[0] ? context.emergency_channel : "#emergency",
|
|
context.public_channel[0] ? context.public_channel : "Public", (unsigned)context.channel_count);
|
|
+ case BOT_COMMAND_VERSION:
|
|
+ return writeFormatted(output, output_len, "Firmware %s built %s", context.firmware_version[0] ? context.firmware_version : "unknown",
|
|
+ context.firmware_build_date[0] ? context.firmware_build_date : "unknown");
|
|
+ case BOT_COMMAND_STATS:
|
|
+ return writeFormatted(output, output_len, "Bot seen %lu ok %lu sent %lu fail %lu sup %lu pend %lu rf rx/tx %lu/%lu err %lu q %u",
|
|
+ (unsigned long)context.observed_messages, (unsigned long)context.eligible_messages,
|
|
+ (unsigned long)context.sent_messages, (unsigned long)context.send_failures,
|
|
+ (unsigned long)context.suppressed_responses, (unsigned long)context.pending_responses,
|
|
+ (unsigned long)context.packets_recv, (unsigned long)context.packets_sent,
|
|
+ (unsigned long)context.packets_recv_errors, (unsigned)context.queue_depth);
|
|
+ case BOT_COMMAND_MAGIC8:
|
|
+ return executeMagic8(context, output, output_len);
|
|
+ case BOT_COMMAND_PATH:
|
|
+ return executePath(context, output, output_len);
|
|
case BOT_COMMAND_UNKNOWN:
|
|
- return writeText(output, output_len, "Unknown command. Try !help");
|
|
+ return writeText(output, output_len, "Unknown command. Try help");
|
|
default:
|
|
return makeResult(BOT_COMMAND_RESULT_NOT_HANDLED, 0);
|
|
}
|
|
diff --git a/examples/companion_radio/BotPrefs.cpp b/examples/companion_radio/BotPrefs.cpp
|
|
index 1d0810a..0eff075 100644
|
|
--- a/examples/companion_radio/BotPrefs.cpp
|
|
+++ b/examples/companion_radio/BotPrefs.cpp
|
|
@@ -294,27 +294,51 @@ const char* commandName(BotCommandId command_id) {
|
|
case BOT_COMMAND_DICE: return "roll";
|
|
case BOT_COMMAND_STATUS: return "status";
|
|
case BOT_COMMAND_CHANNELS: return "channels";
|
|
+ case BOT_COMMAND_VERSION: return "version";
|
|
+ case BOT_COMMAND_STATS: return "stats";
|
|
+ case BOT_COMMAND_MAGIC8: return "magic8";
|
|
+ case BOT_COMMAND_PATH: return "path";
|
|
case BOT_COMMAND_UNKNOWN: return "unknown";
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
+bool namesEqual(const char* name, size_t len, const char* expected) {
|
|
+ size_t expected_len = boundedStrLen(expected, BOT_MAX_COMMAND_NAME_LEN + 1);
|
|
+ if (len != expected_len) return false;
|
|
+ for (size_t i = 0; i < len; i++) {
|
|
+ if (tolower((unsigned char)name[i]) != tolower((unsigned char)expected[i])) return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
bool commandIdForName(const char* name, BotCommandId* command_id) {
|
|
if (!name || !command_id) return false;
|
|
+ size_t len = boundedStrLen(name, BOT_MAX_COMMAND_NAME_LEN + 1);
|
|
+ if (namesEqual(name, len, "t")) {
|
|
+ *command_id = BOT_COMMAND_TEST;
|
|
+ return true;
|
|
+ }
|
|
+ if (namesEqual(name, len, "dice")) {
|
|
+ *command_id = BOT_COMMAND_DICE;
|
|
+ return true;
|
|
+ }
|
|
+ if (namesEqual(name, len, "ver")) {
|
|
+ *command_id = BOT_COMMAND_VERSION;
|
|
+ return true;
|
|
+ }
|
|
+ if (namesEqual(name, len, "8ball") || namesEqual(name, len, "eightball")) {
|
|
+ *command_id = BOT_COMMAND_MAGIC8;
|
|
+ return true;
|
|
+ }
|
|
+ if (namesEqual(name, len, "p") || namesEqual(name, len, "decode") || namesEqual(name, len, "route")) {
|
|
+ *command_id = BOT_COMMAND_PATH;
|
|
+ return true;
|
|
+ }
|
|
for (uint8_t id = BOT_COMMAND_HELP; id <= BOT_COMMAND_UNKNOWN; id++) {
|
|
const char* candidate = commandName((BotCommandId)id);
|
|
if (candidate[0] == 0) continue;
|
|
- size_t len = boundedStrLen(name, BOT_MAX_COMMAND_NAME_LEN + 1);
|
|
- size_t candidate_len = boundedStrLen(candidate, BOT_MAX_COMMAND_NAME_LEN + 1);
|
|
- if (len != candidate_len) continue;
|
|
- bool match = true;
|
|
- for (size_t i = 0; i < len; i++) {
|
|
- if (tolower((unsigned char)name[i]) != tolower((unsigned char)candidate[i])) {
|
|
- match = false;
|
|
- break;
|
|
- }
|
|
- }
|
|
- if (match) {
|
|
+ if (namesEqual(name, len, candidate)) {
|
|
*command_id = (BotCommandId)id;
|
|
return true;
|
|
}
|
|
diff --git a/examples/companion_radio/BotTypes.h b/examples/companion_radio/BotTypes.h
|
|
index 98d4a58..5eb71c6 100644
|
|
--- a/examples/companion_radio/BotTypes.h
|
|
+++ b/examples/companion_radio/BotTypes.h
|
|
@@ -9,6 +9,9 @@
|
|
#define BOT_MAX_COMMAND_ARGS_LEN 79
|
|
#define BOT_MAX_CHANNEL_NAME_LEN 23
|
|
#define BOT_MAX_SENDER_NAME_LEN 31
|
|
+#define BOT_MAX_FIRMWARE_VERSION_LEN 19
|
|
+#define BOT_MAX_BUILD_DATE_LEN 15
|
|
+#define BOT_MAX_PATH_BYTES 64
|
|
#define BOT_GROUP_RESPONSE_PREFIX_RESERVE (BOT_MAX_SENDER_NAME_LEN + 2)
|
|
#define BOT_MAX_GROUP_RESPONSE_LEN (BOT_MAX_TEXT_LEN - BOT_GROUP_RESPONSE_PREFIX_RESERVE)
|
|
#define BOT_COMMAND_COOLDOWN_MILLIS 5000UL
|
|
@@ -43,10 +46,16 @@
|
|
#define BOT_COMMAND_MASK_DICE (1UL << BOT_COMMAND_DICE)
|
|
#define BOT_COMMAND_MASK_STATUS (1UL << BOT_COMMAND_STATUS)
|
|
#define BOT_COMMAND_MASK_CHANNELS (1UL << BOT_COMMAND_CHANNELS)
|
|
+#define BOT_COMMAND_MASK_VERSION (1UL << BOT_COMMAND_VERSION)
|
|
+#define BOT_COMMAND_MASK_STATS (1UL << BOT_COMMAND_STATS)
|
|
+#define BOT_COMMAND_MASK_MAGIC8 (1UL << BOT_COMMAND_MAGIC8)
|
|
+#define BOT_COMMAND_MASK_PATH (1UL << BOT_COMMAND_PATH)
|
|
#define BOT_COMMAND_MASK_UNKNOWN (1UL << BOT_COMMAND_UNKNOWN)
|
|
#define BOT_COMMAND_MASK_ALL (BOT_COMMAND_MASK_HELP | BOT_COMMAND_MASK_PING | BOT_COMMAND_MASK_TEST | \
|
|
BOT_COMMAND_MASK_HELLO | BOT_COMMAND_MASK_ABOUT | BOT_COMMAND_MASK_DICE | \
|
|
- BOT_COMMAND_MASK_STATUS | BOT_COMMAND_MASK_CHANNELS | BOT_COMMAND_MASK_UNKNOWN)
|
|
+ BOT_COMMAND_MASK_STATUS | BOT_COMMAND_MASK_CHANNELS | BOT_COMMAND_MASK_VERSION | \
|
|
+ BOT_COMMAND_MASK_STATS | BOT_COMMAND_MASK_MAGIC8 | BOT_COMMAND_MASK_PATH | \
|
|
+ BOT_COMMAND_MASK_UNKNOWN)
|
|
#define BOT_PREFS_SERIALIZED_SIZE 294
|
|
|
|
enum BotChannelKind : uint8_t {
|
|
@@ -74,6 +83,10 @@ enum BotCommandId : uint8_t {
|
|
BOT_COMMAND_DICE,
|
|
BOT_COMMAND_STATUS,
|
|
BOT_COMMAND_CHANNELS,
|
|
+ BOT_COMMAND_VERSION,
|
|
+ BOT_COMMAND_STATS,
|
|
+ BOT_COMMAND_MAGIC8,
|
|
+ BOT_COMMAND_PATH,
|
|
BOT_COMMAND_UNKNOWN
|
|
};
|
|
|
|
@@ -116,8 +129,13 @@ struct BotMessage {
|
|
uint8_t sender_key_prefix_len;
|
|
bool text_truncated;
|
|
uint32_t sender_timestamp;
|
|
+ uint8_t path_len;
|
|
+ uint8_t path_hash_size;
|
|
+ uint8_t path_hash_count;
|
|
+ int8_t packet_snr_quarters;
|
|
char text[BOT_MAX_TEXT_LEN + 1];
|
|
size_t text_len;
|
|
+ const uint8_t* path;
|
|
};
|
|
|
|
struct BotCommand {
|
|
@@ -141,6 +159,8 @@ struct BotCommandContext {
|
|
char testing_channel[BOT_MAX_CHANNEL_NAME_LEN + 1];
|
|
char emergency_channel[BOT_MAX_CHANNEL_NAME_LEN + 1];
|
|
char public_channel[BOT_MAX_CHANNEL_NAME_LEN + 1];
|
|
+ char firmware_version[BOT_MAX_FIRMWARE_VERSION_LEN + 1];
|
|
+ char firmware_build_date[BOT_MAX_BUILD_DATE_LEN + 1];
|
|
uint32_t uptime_seconds;
|
|
uint16_t battery_millivolts;
|
|
uint32_t storage_used_kb;
|
|
@@ -150,8 +170,30 @@ struct BotCommandContext {
|
|
uint32_t eligible_messages;
|
|
uint32_t sent_messages;
|
|
uint32_t send_failures;
|
|
+ uint32_t suppressed_responses;
|
|
+ uint32_t pending_responses;
|
|
+ uint32_t emergency_forwards;
|
|
+ uint32_t emergency_forward_failures;
|
|
+ uint32_t packets_recv;
|
|
+ uint32_t packets_sent;
|
|
+ uint32_t packets_recv_errors;
|
|
+ uint32_t flood_recv;
|
|
+ uint32_t flood_sent;
|
|
+ uint32_t direct_recv;
|
|
+ uint32_t direct_sent;
|
|
+ uint32_t tx_airtime_seconds;
|
|
+ uint32_t rx_airtime_seconds;
|
|
uint32_t random_seed;
|
|
+ int16_t noise_floor;
|
|
+ int8_t last_rssi;
|
|
+ int8_t last_snr_quarters;
|
|
+ uint8_t queue_depth;
|
|
uint8_t channel_count;
|
|
+ uint8_t path_len;
|
|
+ uint8_t path_hash_size;
|
|
+ uint8_t path_hash_count;
|
|
+ int8_t path_snr_quarters;
|
|
+ const uint8_t* path;
|
|
};
|
|
|
|
struct BotCommandResult {
|
|
@@ -232,10 +274,10 @@ struct BotStats {
|
|
uint32_t send_failures;
|
|
};
|
|
|
|
-static_assert(sizeof(BotMessage) <= 248, "BotMessage RAM budget exceeded");
|
|
+static_assert(sizeof(BotMessage) <= 264, "BotMessage RAM budget exceeded");
|
|
static_assert(sizeof(BotCommand) <= 120, "BotCommand RAM budget exceeded");
|
|
static_assert(sizeof(BotResponse) <= 184, "BotResponse RAM budget exceeded");
|
|
-static_assert(sizeof(BotCommandContext) <= 192, "BotCommandContext RAM budget exceeded");
|
|
+static_assert(sizeof(BotCommandContext) <= 312, "BotCommandContext RAM budget exceeded");
|
|
static_assert(sizeof(BotCommandResult) <= 16, "BotCommandResult RAM budget exceeded");
|
|
static_assert(sizeof(BotCommandCooldown) <= 8, "BotCommandCooldown RAM budget exceeded");
|
|
static_assert(sizeof(BotKnownBotEntry) <= 24, "BotKnownBotEntry RAM budget exceeded");
|
|
diff --git a/examples/companion_radio/FirmwareBot.cpp b/examples/companion_radio/FirmwareBot.cpp
|
|
index de44fb9..8cdf764 100644
|
|
--- a/examples/companion_radio/FirmwareBot.cpp
|
|
+++ b/examples/companion_radio/FirmwareBot.cpp
|
|
@@ -119,12 +119,16 @@ BotWriteResult normalizeText(const char* input, size_t input_len, char* output,
|
|
BotCommandId commandIdForName(const char* name, size_t len) {
|
|
if (namesEqual(name, len, "help") || namesEqual(name, len, "cmd") || namesEqual(name, len, "commands")) return BOT_COMMAND_HELP;
|
|
if (namesEqual(name, len, "ping")) return BOT_COMMAND_PING;
|
|
- if (namesEqual(name, len, "test")) return BOT_COMMAND_TEST;
|
|
+ if (namesEqual(name, len, "test") || namesEqual(name, len, "t")) return BOT_COMMAND_TEST;
|
|
if (namesEqual(name, len, "hello") || namesEqual(name, len, "hi")) return BOT_COMMAND_HELLO;
|
|
if (namesEqual(name, len, "about")) return BOT_COMMAND_ABOUT;
|
|
if (namesEqual(name, len, "dice") || namesEqual(name, len, "roll")) return BOT_COMMAND_DICE;
|
|
if (namesEqual(name, len, "status")) return BOT_COMMAND_STATUS;
|
|
if (namesEqual(name, len, "channels")) return BOT_COMMAND_CHANNELS;
|
|
+ if (namesEqual(name, len, "version") || namesEqual(name, len, "ver")) return BOT_COMMAND_VERSION;
|
|
+ if (namesEqual(name, len, "stats")) return BOT_COMMAND_STATS;
|
|
+ if (namesEqual(name, len, "magic8") || namesEqual(name, len, "8ball") || namesEqual(name, len, "eightball")) return BOT_COMMAND_MAGIC8;
|
|
+ if (namesEqual(name, len, "path") || namesEqual(name, len, "p") || namesEqual(name, len, "decode") || namesEqual(name, len, "route")) return BOT_COMMAND_PATH;
|
|
return BOT_COMMAND_UNKNOWN;
|
|
}
|
|
|
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
|
index ec6a780..895be4b 100644
|
|
--- a/examples/companion_radio/MyMesh.cpp
|
|
+++ b/examples/companion_radio/MyMesh.cpp
|
|
@@ -835,7 +835,7 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
|
}
|
|
|
|
void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_name, const char *text,
|
|
- uint32_t sender_timestamp) {
|
|
+ uint32_t sender_timestamp, const mesh::Packet *packet) {
|
|
BotMessage message;
|
|
memset(&message, 0, sizeof(message));
|
|
size_t channel_len = botBoundedStrLen(channel_name, BOT_MAX_CHANNEL_NAME_LEN);
|
|
@@ -845,6 +845,13 @@ void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_n
|
|
message.channel_name[channel_len] = 0;
|
|
}
|
|
message.sender_timestamp = sender_timestamp;
|
|
+ if (packet && packet->isRouteFlood() && packet->path_len <= 0xFF && mesh::Packet::isValidPathLen((uint8_t)packet->path_len)) {
|
|
+ message.path_len = (uint8_t)packet->path_len;
|
|
+ message.path_hash_size = packet->getPathHashSize();
|
|
+ message.path_hash_count = packet->getPathHashCount();
|
|
+ message.packet_snr_quarters = (int8_t)(packet->getSNR() * 4);
|
|
+ message.path = packet->path;
|
|
+ }
|
|
|
|
const char *body = text;
|
|
size_t body_len = botBoundedStrLen(text, BOT_MAX_TEXT_LEN);
|
|
@@ -867,10 +874,14 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
|
context.eligible_messages = bot_stats.eligible_messages;
|
|
context.sent_messages = bot_stats.sent_messages;
|
|
context.send_failures = bot_stats.send_failures;
|
|
- if (command_id == BOT_COMMAND_DICE) {
|
|
+ context.suppressed_responses = bot_stats.suppressed_responses;
|
|
+ context.pending_responses = bot_stats.pending_responses;
|
|
+ context.emergency_forwards = bot_stats.emergency_forwards;
|
|
+ context.emergency_forward_failures = bot_stats.emergency_forward_failures;
|
|
+ if (command_id == BOT_COMMAND_DICE || command_id == BOT_COMMAND_MAGIC8) {
|
|
getRNG()->random((uint8_t *)&context.random_seed, sizeof(context.random_seed));
|
|
}
|
|
- if (command_id == BOT_COMMAND_STATUS) {
|
|
+ if (command_id == BOT_COMMAND_STATUS || command_id == BOT_COMMAND_STATS) {
|
|
context.battery_millivolts = board.getBattMilliVolts();
|
|
context.storage_used_kb = _store->getStorageUsedKb();
|
|
context.storage_total_kb = _store->getStorageTotalKb();
|
|
@@ -881,6 +892,25 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
|
if (getChannel(i, channel) && channel.name[0]) context.channel_count++;
|
|
}
|
|
}
|
|
+ if (command_id == BOT_COMMAND_VERSION) {
|
|
+ StrHelper::strzcpy(context.firmware_version, FIRMWARE_VERSION, sizeof(context.firmware_version));
|
|
+ StrHelper::strzcpy(context.firmware_build_date, FIRMWARE_BUILD_DATE, sizeof(context.firmware_build_date));
|
|
+ }
|
|
+ if (command_id == BOT_COMMAND_STATS) {
|
|
+ context.queue_depth = (uint8_t)_mgr->getOutboundTotal();
|
|
+ context.noise_floor = (int16_t)_radio->getNoiseFloor();
|
|
+ context.last_rssi = (int8_t)radio_driver.getLastRSSI();
|
|
+ context.last_snr_quarters = (int8_t)(radio_driver.getLastSNR() * 4);
|
|
+ context.tx_airtime_seconds = getTotalAirTime() / 1000;
|
|
+ context.rx_airtime_seconds = getReceiveAirTime() / 1000;
|
|
+ context.packets_recv = radio_driver.getPacketsRecv();
|
|
+ context.packets_sent = radio_driver.getPacketsSent();
|
|
+ context.flood_sent = getNumSentFlood();
|
|
+ context.direct_sent = getNumSentDirect();
|
|
+ context.flood_recv = getNumRecvFlood();
|
|
+ context.direct_recv = getNumRecvDirect();
|
|
+ context.packets_recv_errors = radio_driver.getPacketsRecvErrors();
|
|
+ }
|
|
}
|
|
|
|
bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
|
@@ -1024,6 +1054,13 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
|
|
|
BotCommandContext context;
|
|
buildBotCommandContext(context, command.id);
|
|
+ if (command.id == BOT_COMMAND_PATH) {
|
|
+ context.path_len = message.path_len;
|
|
+ context.path_hash_size = message.path_hash_size;
|
|
+ context.path_hash_count = message.path_hash_count;
|
|
+ context.path_snr_quarters = message.packet_snr_quarters;
|
|
+ context.path = message.path;
|
|
+ }
|
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
|
BotCommandResult result = BotCommands::executeCommand(command, context, response, sizeof(response));
|
|
if (result.code == BOT_COMMAND_RESULT_NOT_HANDLED || result.code == BOT_COMMAND_RESULT_NO_SPACE || result.text_len == 0) {
|
|
@@ -1232,7 +1269,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
|
|
if (_ui) _ui->newMsg(path_len, channel_name, text, offline_queue_len);
|
|
#endif
|
|
#if CMESH_BOT_ENABLED
|
|
- observeBotChannelMessage(channel_idx, channel_name, text, timestamp);
|
|
+ observeBotChannelMessage(channel_idx, channel_name, text, timestamp, pkt);
|
|
#endif
|
|
}
|
|
|
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
|
index 6f8d432..e25f9a5 100644
|
|
--- a/examples/companion_radio/MyMesh.h
|
|
+++ b/examples/companion_radio/MyMesh.h
|
|
@@ -209,7 +209,7 @@ private:
|
|
void observeBotDirectMessage(const ContactInfo &from, uint32_t sender_timestamp, const uint8_t *sender_prefix,
|
|
size_t sender_prefix_len, const char *text);
|
|
void observeBotChannelMessage(uint8_t channel_idx, const char *channel_name, const char *text,
|
|
- uint32_t sender_timestamp);
|
|
+ uint32_t sender_timestamp, const mesh::Packet *packet);
|
|
void recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx);
|
|
bool observeKnownBotResponse(const BotMessage &message, bool authoritative_sender);
|
|
void buildBotCommandContext(BotCommandContext &context, BotCommandId command_id);
|