Companion: say which profile raw and channel data arrived on
MeshCore Open TAK labels a MediaMesh photo or voice clip "Received via MediaMesh", "via main mesh" or both. Wadamesh standalones tell the app the profile in a frame byte stock firmware leaves reserved; a Cascade companion left it unset, so the app showed nothing. While radio2 is on (rx or rxtx): - PUSH_CODE_RAW_DATA (0x84) byte 3: 0xA0 primary, 0xA1 radio2 (stock 0xFF). - RESP_CODE_CHANNEL_DATA_RECV (0x1B) byte 2: the same (stock 0). With radio2 off, or for a packet from the UDP bridge, the stock values stay, so existing clients see no change. Test: test/test_companion_rx_via.py (in run-unit-tests); the two harnesses that compile these handlers get a stub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i5tJJtj95MB4oUgncCUe5
This commit is contained in:
7 files changed
+108
-4
No files matched your search
@@ -80,6 +80,7 @@ struct MyMesh {
|
||||
void onContactResponse(const ContactInfo&, const uint8_t*, uint8_t);
|
||||
void onControlDataRecv(mesh::Packet*);
|
||||
void onRawDataRecv(mesh::Packet*);
|
||||
uint8_t rxViaTag(const mesh::Packet*, uint8_t none) const { return none; }
|
||||
void onTraceRecv(mesh::Packet*,uint32_t,uint32_t,uint8_t,const uint8_t*,const uint8_t*,uint8_t);
|
||||
void clearBinaryTraceReply();
|
||||
void checkGuards() const {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Companion receive-profile byte: raw and channel data frames say which
|
||||
profile a packet arrived on (0xA0 primary, 0xA1 radio2) while radio2 is on,
|
||||
and keep the stock reserved value otherwise or for UDP-bridge ingress."""
|
||||
from pathlib import Path
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from test_replay_reset_integration import extract_braced
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
HARNESS = r'''
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <RadioProfiles.h>
|
||||
namespace mesh {
|
||||
struct Packet { uint8_t radio_origin = 0; bool udp_bridge_ingress = false; };
|
||||
struct Radio {
|
||||
RadioProfiles* p = nullptr;
|
||||
const RadioProfiles* profiles() const { return p; }
|
||||
};
|
||||
}
|
||||
struct MyMesh {
|
||||
mesh::Radio* _radio = nullptr;
|
||||
uint8_t rxViaTag(const mesh::Packet* pkt, uint8_t none) const;
|
||||
};
|
||||
@METHOD@
|
||||
int main() {
|
||||
mesh::RadioProfiles profiles;
|
||||
mesh::Radio radio;
|
||||
MyMesh mesh_;
|
||||
mesh::Packet primary, second, bridged;
|
||||
second.radio_origin = 1;
|
||||
bridged.radio_origin = 1; bridged.udp_bridge_ingress = true;
|
||||
|
||||
// No radio, no profiles, radio2 off: the stock reserved values.
|
||||
assert(mesh_.rxViaTag(&primary, 0xFF) == 0xFF);
|
||||
mesh_._radio = &radio;
|
||||
assert(mesh_.rxViaTag(&second, 0) == 0);
|
||||
radio.p = &profiles;
|
||||
profiles.secondary.mode = mesh::RadioProfileMode::Off;
|
||||
assert(mesh_.rxViaTag(&second, 0xFF) == 0xFF);
|
||||
assert(mesh_.rxViaTag(nullptr, 0) == 0);
|
||||
|
||||
// radio2 listening or sending: tagged by the profile it arrived on.
|
||||
for (auto mode : {mesh::RadioProfileMode::Rx, mesh::RadioProfileMode::RxTx}) {
|
||||
profiles.secondary.mode = mode;
|
||||
assert(mesh_.rxViaTag(&primary, 0xFF) == 0xA0);
|
||||
assert(mesh_.rxViaTag(&second, 0) == 0xA1);
|
||||
assert(mesh_.rxViaTag(&bridged, 0) == 0); // came over the UDP bridge, not a radio
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
class CompanionRxViaTest(unittest.TestCase):
|
||||
def test_rx_via_tag(self):
|
||||
source = (ROOT / 'examples/companion_radio/MyMesh.cpp').read_text(encoding='utf-8')
|
||||
method = extract_braced(source, 'uint8_t MyMesh::rxViaTag(')
|
||||
self.assertIn('rxViaTag(pkt, 0)', source) # channel data, reserved1
|
||||
self.assertIn('rxViaTag(packet, 0xFF)', source) # raw data, reserved
|
||||
with tempfile.TemporaryDirectory(prefix='companion-rx-via-') as directory:
|
||||
work = Path(directory)
|
||||
cpp = work / 'test.cpp'
|
||||
cpp.write_text(HARNESS.replace('@METHOD@', method), encoding='utf-8')
|
||||
flags = ['-fsanitize=address,undefined', '-fno-sanitize-recover=all'] if sys.platform.startswith('linux') else []
|
||||
binary = work / 'test.exe'
|
||||
compiled = subprocess.run([os.environ.get('CXX', 'g++'), '-std=c++17', '-Wall', '-Wextra', '-Werror',
|
||||
'-DWITH_UDP_BRIDGE', *flags, f'-I{ROOT / "src"}', str(cpp), '-o', str(binary)],
|
||||
capture_output=True, text=True, timeout=60)
|
||||
self.assertEqual(compiled.returncode, 0, compiled.stderr)
|
||||
checked = subprocess.run([str(binary)], capture_output=True, text=True, timeout=10)
|
||||
self.assertEqual(checked.returncode, 0, checked.stderr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -92,6 +92,7 @@ struct MyMesh {
|
||||
if(pending_route==route)pending_route=nullptr;
|
||||
}
|
||||
int findChannelIdxForPacket(const mesh::GroupChannel&,mesh::Packet*) const { return 0; }
|
||||
uint8_t rxViaTag(const mesh::Packet*,uint8_t none) const { return none; }
|
||||
int getOfflineQueueCapacity() const;
|
||||
Frame& offlineQueueFrameAt(int);
|
||||
bool addToOfflineQueue(const uint8_t*,int);
|
||||
|
||||
Reference in new issue
Block a user