mirror of
https://github.com/meshtastic/firmware.git
synced 2026-09-23 06:45:24 -04:00
* logging: strip redundant punctuation, level prefixes, and 'successfully' from log strings The logger already appends a newline and prints the level tag, so trailing '.', '!', '...', literal \n, and 'Error:'/'Warning:' prefixes inside format strings are wasted flash bytes. Same for 'successfully' (the affirmative form already implies it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: tighten verbose log strings in modules, radio, platform, and system code Rewrite wordy log messages to terser equivalents - drop filler words (articles, 'attempting', 'due to', 'please'), use 'Can't X'/'X failed' phrasing, and abbreviate where the codebase already does (config, init, msg, BT). Format specifiers and argument lists are unchanged; distinctive greppable tokens are preserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: tighten verbose log strings in telemetry sensors and GPS Same terseness pass: drop filler, 'Can't X'/'X failed' phrasing, common abbreviations (temp, msg). Specifiers, arguments, and sensor-name prefixes unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: tighten verbose log strings in mesh core Same terseness pass over NodeDB, Router, MeshService, PhoneAPI, RadioInterface, NextHopRouter, and PacketHistory: 'X failed'/'Can't X' phrasing, imperative verbs, dropped filler. Specifiers and arguments unchanged; duplicate literals kept identical to preserve linker string dedup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: 'Unable to/Could not/Cannot' -> "Can't" in log strings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: clang-format rewrap after string shortening Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * logging: restore boot-logo trailing newline and progress-dot strings The terseness pass over-trimmed: the Meshtastic ASCII boot logo kept its blank line via a trailing \n, and three bare "." progress ticks were reduced to empty strings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBiZc9sfPrH1MZ2L3Fxgt1 * Update src/mesh/wifi/WiFiAPClient.cpp Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * logging: address review feedback on the terseness audit - Node/packet IDs use the repo's 0x%08x convention in NextHopRouter, NodeDB, AdminModule and CannedMessageModule. The sibling log in each if/else pair is converted too, so a pair isn't split across two formats. next_hop stays 0x%x - it's the last-byte relay hint, not a NodeNum. - RTC: the read-path and set-path "not found" warnings were byte-identical, so the linker deduped them and the log couldn't say which one fired. Split into "RTC read:" / "RTC set:". (The four sites live in mutually exclusive #ifdef branches, so the RTC family was never ambiguous.) - SCD4X getAmbientPressure()/setAmbientPressure() logged "altitude", and SCD30 getASC() logged "Can't send command" for a read. Both now name the operation they actually perform. - LOG_ERROR already carries the level: ". Error: %u" -> ", rc=%u" (matching the existing rc=%d house style) and "Error executing X()" -> "X() failed". - Typos and wording: "OTA partiton. (Reason" -> "OTA partition (reason", "CST3530 not response ~" -> "CST3530 no response", "Packet received with to: of 0" -> "to=0", HostMetrics "Error decoding" -> "Can't decode", and the dangling ": " on the NextHopRouter retransmission line. Printf specifier sequences are byte-identical on all 37 touched lines apart from the 6 deliberate %x/%u -> %08x node-ID widenings, all on uint32_t args. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
517 lines
20 KiB
C++
517 lines
20 KiB
C++
#ifdef SENSECAP_INDICATOR
|
|
|
|
#include "IndicatorSerial.h"
|
|
#include "concurrency/LockGuard.h"
|
|
#include "mesh/comms/UARTProxy.h"
|
|
#include <HardwareSerial.h>
|
|
#include <Throttle.h>
|
|
#include <pb_decode.h>
|
|
#include <pb_encode.h>
|
|
|
|
SensecapIndicator *sensecapIndicator;
|
|
|
|
SensecapIndicator::SensecapIndicator(HardwareSerial &serial) : OSThread("SensecapIndicator")
|
|
{
|
|
_serial = &serial;
|
|
// Twice the largest frame: the pump runs from the cooperative main
|
|
// loop, which can stall for tens of ms while data keeps arriving
|
|
_serial->setRxBufferSize(2 * PB_BUFSIZE);
|
|
_serial->setPins(SENSOR_RP2040_RXD, SENSOR_RP2040_TXD);
|
|
_serial->begin(SENSOR_BAUD_RATE);
|
|
LOG_DEBUG("Start indicator communication thread");
|
|
}
|
|
|
|
int32_t SensecapIndicator::runOnce()
|
|
{
|
|
// A requester is pumping the link itself and holds link_lock for up
|
|
// to its full request timeout; blocking on the lock here would stall
|
|
// every other thread of the cooperative main loop with it
|
|
if (requests_in_flight > 0)
|
|
return (10);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
pump();
|
|
// Keep probing until the co-processor has answered the handshake: it
|
|
// may boot slower than we do, or reboot on its watchdog. Without this
|
|
// the bridge would stay dead for the rest of the session.
|
|
if (!handshake_done)
|
|
probe_link();
|
|
// Diagnostics for the map-tile transfers: a resync or a decode failure
|
|
// means a response was corrupted on the wire, a timeout means it never
|
|
// arrived. Printed at most once every two seconds, and only when
|
|
// something went wrong.
|
|
if ((link_resyncs || link_decode_fail || link_timeouts) && !Throttle::isWithinTimespanMs(last_link_report, 2000)) {
|
|
last_link_report = millis();
|
|
LOG_WARN("link: resync=%u decode_fail=%u timeout=%u", (unsigned)link_resyncs, (unsigned)link_decode_fail,
|
|
(unsigned)link_timeouts);
|
|
link_resyncs = link_decode_fail = link_timeouts = 0;
|
|
}
|
|
return (10);
|
|
}
|
|
|
|
// Send a ping, rate limited. The co-processor answers with a pong carrying
|
|
// the protocol version it speaks. Caller holds link_lock.
|
|
void SensecapIndicator::probe_link()
|
|
{
|
|
// last_probe 0 means we have not probed at all yet, which must not throttle
|
|
if (last_probe != 0 && Throttle::isWithinTimespanMs(last_probe, 250))
|
|
return;
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_ping_tag;
|
|
msg.data.ping = meshtastic_InterdeviceVersion_INTERDEVICE_VERSION_CURRENT;
|
|
stamp_request(msg);
|
|
send_uplink_unlocked(msg);
|
|
last_probe = millis();
|
|
}
|
|
|
|
// Read whatever is available on the link and process complete packets
|
|
void SensecapIndicator::pump()
|
|
{
|
|
size_t space_left = PB_BUFSIZE - pb_rx_size;
|
|
pb_rx_size += serial_check((char *)pb_rx_buf + pb_rx_size, space_left);
|
|
check_packet();
|
|
}
|
|
|
|
// Pump the link until `flag` goes true, a nack arrives, or the timeout
|
|
// expires
|
|
bool SensecapIndicator::wait_response(const bool &flag, uint32_t timeout_ms)
|
|
{
|
|
uint32_t start = millis();
|
|
while (!flag) {
|
|
pump();
|
|
if (request_nacked)
|
|
return false; // the other side could not handle the request
|
|
if (!Throttle::isWithinTimespanMs(start, timeout_ms)) {
|
|
link_timeouts++;
|
|
return false;
|
|
}
|
|
delay(1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// assign the next correlation id to a request, skipping the unsolicited 0
|
|
uint32_t SensecapIndicator::stamp_request(meshtastic_InterdeviceMessage &request)
|
|
{
|
|
if (++next_request_id == 0)
|
|
next_request_id = 1;
|
|
request.id = next_request_id;
|
|
expected_id = next_request_id;
|
|
request_nacked = false;
|
|
// Start the response for this request from an aligned buffer. A byte run
|
|
// lost mid-response (a UART overflow during a 4KB chunk) leaves the
|
|
// assembly misaligned, and without this that poison would outlive the
|
|
// request and cascade into the following chunks of the same tile. The
|
|
// link is single-outstanding and stale responses are dropped by id, so
|
|
// nothing worth keeping is ever pending here (at most a partial NMEA
|
|
// sentence, which self-heals).
|
|
pb_rx_size = 0;
|
|
return next_request_id;
|
|
}
|
|
|
|
// callers hold link_lock: the co-processor has completed the handshake and
|
|
// speaks our protocol version. Fails fast instead of timing out per request.
|
|
bool SensecapIndicator::link_ready()
|
|
{
|
|
return handshake_done && link_compatible;
|
|
}
|
|
|
|
// The co-processor reported the protocol version it speaks, in a pong or in
|
|
// the unsolicited ping it sends when it has booted. Anything else than ours
|
|
// means its firmware does not match this build, and every request would be
|
|
// misinterpreted. Caller holds link_lock.
|
|
void SensecapIndicator::note_handshake(uint32_t peer_version)
|
|
{
|
|
bool compatible = peer_version == meshtastic_InterdeviceVersion_INTERDEVICE_VERSION_CURRENT;
|
|
bool changed = !handshake_done || compatible != link_compatible;
|
|
if (changed) {
|
|
if (compatible)
|
|
LOG_INFO("RP2040 link up, interdevice protocol v%u", (unsigned)peer_version);
|
|
else
|
|
LOG_ERROR("RP2040 speaks interdevice protocol v%u, this firmware speaks v%u. Flash the matching "
|
|
"indicator_rp2040 firmware; sensors, GPS and SD card stay disabled",
|
|
(unsigned)peer_version, (unsigned)meshtastic_InterdeviceVersion_INTERDEVICE_VERSION_CURRENT);
|
|
}
|
|
link_compatible = compatible;
|
|
handshake_done = true;
|
|
}
|
|
|
|
bool SensecapIndicator::i2c_transact(uint8_t address, const uint8_t *wbuf, size_t wlen, size_t rlen, meshtastic_I2CResult *result,
|
|
uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_i2c_transaction_tag;
|
|
msg.data.i2c_transaction.address = address;
|
|
msg.data.i2c_transaction.read_len = rlen;
|
|
if (wlen > sizeof(msg.data.i2c_transaction.write_data.bytes))
|
|
return false;
|
|
msg.data.i2c_transaction.write_data.size = wlen;
|
|
if (wlen)
|
|
memcpy(msg.data.i2c_transaction.write_data.bytes, wbuf, wlen);
|
|
|
|
stamp_request(msg);
|
|
i2c_result_ready = false;
|
|
if (!send_uplink_unlocked(msg))
|
|
return false;
|
|
|
|
if (!wait_response(i2c_result_ready, timeout_ms))
|
|
return false;
|
|
*result = i2c_result;
|
|
i2c_result_ready = false;
|
|
return true;
|
|
}
|
|
|
|
bool SensecapIndicator::file_request(meshtastic_InterdeviceMessage &request, meshtastic_FileTransfer *out, uint32_t timeout_ms)
|
|
{
|
|
stamp_request(request);
|
|
file_response_ready = false;
|
|
pending_file = out;
|
|
if (!send_uplink_unlocked(request) || !wait_response(file_response_ready, timeout_ms)) {
|
|
pending_file = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SensecapIndicator::file_read(const char *path, uint32_t offset, uint32_t length, meshtastic_FileTransfer *out,
|
|
uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_file_transfer_tag;
|
|
msg.data.file_transfer.operation = meshtastic_FileOperation_GET;
|
|
strncpy(msg.data.file_transfer.filepath, path, sizeof(msg.data.file_transfer.filepath) - 1);
|
|
msg.data.file_transfer.offset = offset;
|
|
msg.data.file_transfer.length = length;
|
|
return file_request(msg, out, timeout_ms);
|
|
}
|
|
|
|
bool SensecapIndicator::file_write(const char *path, uint32_t offset, const uint8_t *data, size_t len, bool create,
|
|
meshtastic_FileTransfer *out, uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_file_transfer_tag;
|
|
msg.data.file_transfer.operation = create ? meshtastic_FileOperation_POST : meshtastic_FileOperation_PUT;
|
|
strncpy(msg.data.file_transfer.filepath, path, sizeof(msg.data.file_transfer.filepath) - 1);
|
|
msg.data.file_transfer.offset = offset;
|
|
if (len > sizeof(msg.data.file_transfer.filedata.bytes))
|
|
return false;
|
|
msg.data.file_transfer.filedata.size = len;
|
|
memcpy(msg.data.file_transfer.filedata.bytes, data, len);
|
|
return file_request(msg, out, timeout_ms);
|
|
}
|
|
|
|
bool SensecapIndicator::file_remove(const char *path, meshtastic_FileTransfer *out, uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_file_transfer_tag;
|
|
msg.data.file_transfer.operation = meshtastic_FileOperation_DELETE;
|
|
strncpy(msg.data.file_transfer.filepath, path, sizeof(msg.data.file_transfer.filepath) - 1);
|
|
return file_request(msg, out, timeout_ms);
|
|
}
|
|
|
|
bool SensecapIndicator::list_directory(const char *path, uint32_t offset, meshtastic_DirectoryListing *out, uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_directory_listing_tag;
|
|
strncpy(msg.data.directory_listing.directory, path, sizeof(msg.data.directory_listing.directory) - 1);
|
|
msg.data.directory_listing.offset = offset;
|
|
|
|
stamp_request(msg);
|
|
dir_response_ready = false;
|
|
pending_dir = out;
|
|
if (!send_uplink_unlocked(msg) || !wait_response(dir_response_ready, timeout_ms)) {
|
|
pending_dir = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SensecapIndicator::sd_info(meshtastic_SdCardInfo *out, uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_get_sd_info_tag;
|
|
msg.data.get_sd_info = true;
|
|
|
|
stamp_request(msg);
|
|
sd_info_ready = false;
|
|
pending_sd_info = out;
|
|
if (!send_uplink_unlocked(msg) || !wait_response(sd_info_ready, timeout_ms)) {
|
|
pending_sd_info = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SensecapIndicator::sd_command(meshtastic_SdCommand command, meshtastic_SdCardInfo *out, uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false;
|
|
|
|
meshtastic_InterdeviceMessage &msg = tx_message;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.which_data = meshtastic_InterdeviceMessage_sd_command_tag;
|
|
msg.data.sd_command = command;
|
|
|
|
stamp_request(msg);
|
|
sd_info_ready = false;
|
|
pending_sd_info = out;
|
|
if (!send_uplink_unlocked(msg) || !wait_response(sd_info_ready, timeout_ms)) {
|
|
pending_sd_info = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SensecapIndicator::wait_ready(uint32_t timeout_ms)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
uint32_t start = millis();
|
|
while (!handshake_done) {
|
|
// The co-processor never sends anything unsolicited unless a GPS
|
|
// module is attached, so waiting passively would leave the bridge
|
|
// down forever on GPS-less units. Ping until it answers; the pong
|
|
// touches no peripherals on the other side and carries the
|
|
// protocol version it speaks. If it does not answer in time,
|
|
// runOnce keeps probing (a slow boot must not disable the bridge
|
|
// for the session), but no request is sent until it does.
|
|
probe_link();
|
|
pump();
|
|
if (handshake_done)
|
|
break;
|
|
if (!Throttle::isWithinTimespanMs(start, timeout_ms))
|
|
return false;
|
|
delay(1);
|
|
}
|
|
return link_compatible;
|
|
}
|
|
|
|
bool SensecapIndicator::send_uplink(const meshtastic_InterdeviceMessage &message)
|
|
{
|
|
InFlight busy(requests_in_flight);
|
|
concurrency::LockGuard guard(&link_lock);
|
|
if (!link_ready())
|
|
return false; // nothing is sent to a peer we do not speak the same protocol with
|
|
return send_uplink_unlocked(message);
|
|
}
|
|
|
|
// callers must hold link_lock: pb_tx_buf is shared
|
|
bool SensecapIndicator::send_uplink_unlocked(const meshtastic_InterdeviceMessage &message)
|
|
{
|
|
pb_tx_buf[0] = MT_MAGIC_0;
|
|
pb_tx_buf[1] = MT_MAGIC_1;
|
|
|
|
pb_ostream_t stream = pb_ostream_from_buffer(pb_tx_buf + MT_HEADER_SIZE, PB_BUFSIZE - MT_HEADER_SIZE);
|
|
if (!pb_encode(&stream, meshtastic_InterdeviceMessage_fields, &message)) {
|
|
LOG_DEBUG("pb_encode failed");
|
|
return false;
|
|
}
|
|
|
|
// Store the payload length in the header
|
|
pb_tx_buf[2] = stream.bytes_written / 256;
|
|
pb_tx_buf[3] = stream.bytes_written % 256;
|
|
|
|
bool rv = send((const char *)pb_tx_buf, MT_HEADER_SIZE + stream.bytes_written);
|
|
|
|
return rv;
|
|
}
|
|
|
|
size_t SensecapIndicator::serial_check(char *buf, size_t space_left)
|
|
{
|
|
int avail = _serial->available();
|
|
if (avail <= 0)
|
|
return 0;
|
|
if ((size_t)avail > space_left)
|
|
avail = space_left;
|
|
// bulk copy out of the driver's RX buffer; only reads what is available
|
|
return _serial->read((uint8_t *)buf, avail);
|
|
}
|
|
|
|
// Distance to the next byte that could start a frame. Skips the corrupt
|
|
// prefix while keeping anything that may be a frame queued behind it (a
|
|
// trailing lone MT_MAGIC_0 counts, its successor has not arrived yet).
|
|
static size_t scan_magic(const pb_byte_t *buf, size_t len)
|
|
{
|
|
for (size_t i = 1; i < len; i++) {
|
|
if (buf[i] == MT_MAGIC_0 && (i + 1 == len || buf[i + 1] == MT_MAGIC_1))
|
|
return i;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
void SensecapIndicator::check_packet()
|
|
{
|
|
// process everything buffered; one pump can deliver several frames
|
|
while (pb_rx_size >= MT_HEADER_SIZE) {
|
|
size_t payload_len = (size_t)(pb_rx_buf[2] << 8 | pb_rx_buf[3]);
|
|
if (pb_rx_buf[0] != MT_MAGIC_0 || pb_rx_buf[1] != MT_MAGIC_1 || payload_len + MT_HEADER_SIZE > PB_BUFSIZE) {
|
|
// Corrupt or false header: resync on the next magic instead of
|
|
// flushing, one bad byte must not cost the frames behind it
|
|
size_t skip = scan_magic(pb_rx_buf, pb_rx_size);
|
|
link_resyncs++;
|
|
LOG_DEBUG("Bad frame header, dropping %u bytes", (unsigned)skip);
|
|
memmove(pb_rx_buf, pb_rx_buf + skip, pb_rx_size - skip);
|
|
pb_rx_size -= skip;
|
|
continue;
|
|
}
|
|
|
|
if (payload_len + MT_HEADER_SIZE > pb_rx_size)
|
|
return; // frame not complete yet
|
|
|
|
handle_packet(payload_len);
|
|
}
|
|
}
|
|
|
|
bool SensecapIndicator::handle_packet(size_t payload_len)
|
|
{
|
|
meshtastic_InterdeviceMessage &message = rx_message;
|
|
memset(&message, 0, sizeof(message));
|
|
|
|
// Decode the protobuf and shift forward any remaining bytes in the buffer
|
|
// (which, if present, belong to the packet that we're going to process on the
|
|
// next loop)
|
|
pb_istream_t stream = pb_istream_from_buffer(pb_rx_buf + MT_HEADER_SIZE, payload_len);
|
|
bool status = pb_decode(&stream, meshtastic_InterdeviceMessage_fields, &message);
|
|
size_t remaining = pb_rx_size - MT_HEADER_SIZE - payload_len;
|
|
memmove(pb_rx_buf, pb_rx_buf + MT_HEADER_SIZE + payload_len, remaining);
|
|
pb_rx_size = remaining;
|
|
|
|
if (!status) {
|
|
link_decode_fail++;
|
|
LOG_DEBUG("Decoding failed");
|
|
return false;
|
|
}
|
|
packets_received++;
|
|
switch (message.which_data) {
|
|
case meshtastic_InterdeviceMessage_nmea_tag:
|
|
// send String to NMEA processing
|
|
uartProxy->stuff_buffer(message.data.nmea, strnlen(message.data.nmea, sizeof(message.data.nmea) - 1));
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_i2c_result_tag:
|
|
// response for the transaction i2c_transact() is waiting on
|
|
if (message.id == expected_id) {
|
|
i2c_result = message.data.i2c_result;
|
|
i2c_result_ready = true;
|
|
} else {
|
|
LOG_DEBUG("Drop stale i2c response id=0x%08x", message.id);
|
|
}
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_file_transfer_tag:
|
|
if (pending_file && message.id == expected_id) {
|
|
*pending_file = message.data.file_transfer;
|
|
pending_file = NULL;
|
|
file_response_ready = true;
|
|
} else {
|
|
LOG_DEBUG("Drop stale file response id=0x%08x", message.id);
|
|
}
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_directory_listing_tag:
|
|
if (pending_dir && message.id == expected_id) {
|
|
*pending_dir = message.data.directory_listing;
|
|
pending_dir = NULL;
|
|
dir_response_ready = true;
|
|
} else {
|
|
LOG_DEBUG("Drop stale listing response id=0x%08x", message.id);
|
|
}
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_ping_tag: {
|
|
// The co-processor pings us unsolicited (id 0) when it has booted,
|
|
// which is also how a reboot after its watchdog is noticed. It
|
|
// reports the version it speaks, so this completes the handshake
|
|
// just like a pong does.
|
|
if (message.id == 0) {
|
|
if (handshake_done)
|
|
LOG_WARN("RP2040 rebooted");
|
|
note_handshake(message.data.ping);
|
|
}
|
|
// answer regardless of state. tx_message is safe to reuse: a request
|
|
// in flight was already encoded into pb_tx_buf when it was sent
|
|
meshtastic_InterdeviceMessage &pong = tx_message;
|
|
memset(&pong, 0, sizeof(pong));
|
|
pong.id = message.id;
|
|
pong.which_data = meshtastic_InterdeviceMessage_pong_tag;
|
|
pong.data.pong = meshtastic_InterdeviceVersion_INTERDEVICE_VERSION_CURRENT;
|
|
send_uplink_unlocked(pong);
|
|
return true;
|
|
}
|
|
case meshtastic_InterdeviceMessage_pong_tag:
|
|
// the answer to our probe, carrying the version it speaks
|
|
note_handshake(message.data.pong);
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_nack_tag:
|
|
// A nack for the request in flight is definitive: resending it would
|
|
// only be refused again. An id of 0 means the co-processor could not
|
|
// even decode the frame, which may just as well have been an
|
|
// unrelated NMEA uplink, so that one only ends the wait (the caller
|
|
// may retry it as the transport failure it is).
|
|
if (message.id == expected_id) {
|
|
LOG_WARN("Request 0x%08x nacked by the co-processor", expected_id);
|
|
request_nacked = true;
|
|
} else if (message.id == 0) {
|
|
LOG_WARN("Co-processor can't decode a frame");
|
|
}
|
|
return true;
|
|
case meshtastic_InterdeviceMessage_sd_info_tag:
|
|
if (pending_sd_info && message.id == expected_id) {
|
|
*pending_sd_info = message.data.sd_info;
|
|
pending_sd_info = NULL;
|
|
sd_info_ready = true;
|
|
} else {
|
|
LOG_DEBUG("Drop stale sd info response id=0x%08x", message.id);
|
|
}
|
|
return true;
|
|
default:
|
|
// the other messages really only flow downstream
|
|
LOG_DEBUG("Got a message of unexpected type");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SensecapIndicator::send(const char *buf, size_t len)
|
|
{
|
|
size_t wrote = _serial->write(buf, len);
|
|
if (wrote == len)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
#endif // SENSECAP_INDICATOR
|