Files
MeshCore/test/fixtures/morse_trace_cli.cpp
T
mikecarper 0be4c7488c Add bounded Morse receive and negotiated RS232 autosleep
Add native narrow-band CW capture, ACK-first remote sessions, retained LoRa-readable pages, checked restoration and transport-safe progress. Add stock-compatible negotiated heartbeat/autosleep and recovery. Include host regressions and identity-bound HIL runners; keep unverified faster tuning HIL-only and document outstanding hardware validation.
2026-10-13 01:24:39 -07:00

90 lines
4.9 KiB
C++

#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
struct TraceRadio : TestRadio {
mesh::MorseRssiTrace trace;
bool fail_read=false;
uint32_t total_override=0;
size_t morseTraceLength() const override { return trace.length(); }
uint32_t morseTraceTotal() const override { return total_override ? total_override : trace.total(); }
bool morseTraceTruncated() const override { return trace.truncated(); }
bool readMorseTrace(size_t offset,mesh::MorseRssiTraceEntry& out) const override {
return !fail_read && trace.read(offset,out);
}
};
static void sparse_ring_and_decoder_hook() {
mesh::MorseRssiTrace trace;
trace.sample(-110,0,8); trace.sample(-110,520,0); trace.sample(-80,521,5);
assert(trace.length()==0); // no learning, idle/noise, or debounce-only history
trace.sample(-80,525,3); trace.sample(-76,527,3);
assert(trace.length()==1);
mesh::MorseRssiTraceEntry row;
assert(trace.read(0,row) && row.millis==525 && row.rssi_dbm==-80 && row.flags==3);
trace.sample(-110,570,0); assert(trace.length()==2);
trace.sample(-110,60570,0); assert(trace.length()==3); // quiet anchor keeps deltas bounded
trace.sample(-110,200000,0);
assert(trace.length()==1 && trace.truncated() && trace.total()==4);
assert(trace.read(0,row) && row.millis==200000);
assert(!trace.read(1,row) && !trace.read(size_t(-1),row));
trace.clear(); assert(!trace.length() && !trace.total() && !trace.truncated());
mesh::MorseRx rx; rx.setTrace(&trace);
assert(rx.start(25,60000,100)==mesh::MorseRxResult::Started);
for (uint32_t time=100; time<620; ++time) rx.sample(-110,time);
assert(trace.length()==0);
for (uint32_t time=620; time<668; ++time) rx.sample(-80,time);
for (uint32_t time=668; time<1004; ++time) rx.sample(-110,time);
rx.stop(1004);
assert(trace.length()==2 && rx.text()[0]=='E');
const auto retained=trace.total(); rx.sample(-80,1005); assert(trace.total()==retained);
assert(rx.start(25,60000,2000)==mesh::MorseRxResult::Started && !trace.length());
}
#endif
int main() {
char reply[157]={};
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
sparse_ring_and_decoder_hook();
TraceRadio radio; radio.rx_supported=true;
assert(mesh::handleMorseCommand(&radio,"morse trace",reply,sizeof(reply)));
assert(std::string(reply).find("> 000/000 t=0 n=END x=0 ")==0);
for (size_t entry=0; entry<mesh::MorseRssiTrace::Capacity+10; ++entry)
radio.trace.sample(entry%2 ? -110 : -80,uint32_t(entry*48),entry%2 ? 0 : 3);
assert(radio.trace.length()==512 && radio.trace.total()==522 && radio.trace.truncated());
mesh::MorseRssiTraceEntry row;
for (size_t entry=0; entry<512; ++entry) {
assert(radio.trace.read(entry,row) && row.millis==(entry+10)*48);
}
size_t offset=0;
while (offset<radio.trace.length()) {
const auto command=std::string("morse trace ")+std::to_string(offset);
uint8_t guarded[161]; memset(guarded,0xa5,sizeof(guarded)); memcpy(guarded,"AB|",3);
assert(mesh::handleMorseCommand(&radio,command.c_str(),reinterpret_cast<char*>(guarded+3),157));
assert(!memcmp(guarded,"AB|",3) && guarded[160]==0xa5);
const std::string page(reinterpret_cast<char*>(guarded+3));
assert(page.find("t=522")!=std::string::npos && page.find("x=1")!=std::string::npos);
assert(page.size()<157);
const auto marker=page.find("n="); assert(marker!=std::string::npos);
if (page.substr(marker+2,3)=="END") break;
const auto next=std::stoul(page.substr(marker+2,3));
assert(next>offset && next<=offset+8); offset=next;
}
for (const char* command : {"morse trace -1","morse trace 513","morse trace 1x","morse trace 4294967296","morse trace 1 2"}) {
assert(mesh::handleMorseCommand(&radio,command,reply,sizeof(reply)) && !strncmp(reply,"Error:",6));
}
assert(mesh::handleMorseCommand(&radio,"morse trace 512",reply,sizeof(reply)) && strstr(reply,"n=END"));
radio.fail_read=true;
assert(mesh::handleMorseCommand(&radio,"morse trace",reply,sizeof(reply)) && strstr(reply,"trace changed"));
radio.fail_read=false; radio.total_override=0xffffffffU;
assert(mesh::handleMorseCommand(&radio,"morse trace",reply,sizeof(reply)) && strstr(reply,"t=4294967295"));
char small[8]; memset(small,'X',sizeof(small));
assert(mesh::handleMorseCommand(&radio,"morse trace",small,sizeof(small)) && small[7]==0);
mesh::usable=false;
assert(mesh::handleMorseCommand(&radio,"morse trace",reply,sizeof(reply)) && strncmp(reply,"Error:",6));
mesh::MorseReplyHandoff handoff; const uint8_t actor[32]={1};
handoff.beginCommand(actor); assert(handoff.stage(902100,25,60000,100)); handoff.endCommand();
assert(!mesh::handleMorseReplyCommand(handoff,&radio,"morse\ttrace 0",reply,sizeof(reply),100));
assert(handoff.pending() && !radio.rx_starts && !radio.starts);
#else
TestRadio radio; radio.rx_supported=true;
assert(mesh::handleMorseCommand(&radio,"morse trace",reply,sizeof(reply)) && !strncmp(reply,"Error:",6));
assert(!radio.rx_starts && !radio.starts);
#endif
}