HostHandler: senders for the AA tranche messages
tests / build-and-test (push) Failing after 34s

A host couldn't drive the new messages through the HostHandler class —
only the server side knew how to dispatch them.  Adds six new senders
plus a unit test that walks each through a real loopback connection:

  * send_legacy_remote_command  -> S2F21
  * send_event_report_request   -> S6F15
  * send_individual_report_request -> S6F19
  * send_annotated_report_request  -> S6F21
  * send_pp_load_inquire        -> S7F1
  * send_delete_pp              -> S7F17

Suite: 296 cases / 1571 assertions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 01:20:23 +02:00
parent 7c28e2589c
commit 29f646c7ca
3 changed files with 106 additions and 0 deletions
+55
View File
@@ -100,6 +100,20 @@ struct Recorder {
return gem::s16f6_pr_job_command_ack(gem::HostCmdAck::Accept);
if (msg.stream == 14 && msg.function == 9)
return gem::s14f10_create_control_job_ack("CJ-1", gem::ObjectAck::Success);
// New senders (Task 18): provide canned replies so the host's
// send_*_request transactions complete instead of timing out.
if (msg.stream == 2 && msg.function == 21)
return gem::s2f22_remote_command_ack(gem::HostCmdAck::Accept);
if (msg.stream == 6 && msg.function == 15)
return gem::s6f16_event_report_data({0, 300, {}});
if (msg.stream == 6 && msg.function == 19)
return gem::s6f20_individual_report_data({});
if (msg.stream == 6 && msg.function == 21)
return gem::s6f22_annotated_report_data({});
if (msg.stream == 7 && msg.function == 1)
return gem::s7f2_pp_load_grant(gem::ProcessProgramAck::Accept);
if (msg.stream == 7 && msg.function == 17)
return gem::s7f18_delete_pp_ack(gem::ProcessProgramAck::Accept);
// Unhandled — leave the host to time out on T3.
return std::nullopt;
};
@@ -254,6 +268,47 @@ TEST_CASE("HostHandler: E40/E94 job creation senders produce correct wire") {
pump_until(w.io, [&] { return cmd_ack; });
}
TEST_CASE("HostHandler: new senders produce correct wire shapes") {
// Wires up the host + equipment, installs the handler, fires each
// new sender, and verifies the (stream, function) of the request
// the equipment received. The equipment auto-acks each via Recorder.
Wired w;
Recorder rec;
w.equipment->set_message_handler(rec.handler());
w.handler->install();
w.host->start();
w.equipment->start();
bool selected = false;
w.host->set_selected_handler([&] { selected = true; });
pump_until(w.io, [&] { return selected; });
auto run_one = [&](auto fire, uint8_t want_stream, uint8_t want_fn) {
bool done = false;
fire([&](std::error_code ec, const s2::Message&) {
REQUIRE_FALSE(ec);
done = true;
});
pump_until(w.io, [&] { return done; });
REQUIRE_FALSE(rec.last.empty());
CHECK(rec.last.back().stream == want_stream);
CHECK(rec.last.back().function == want_fn);
};
run_one([&](auto cb) { w.handler->send_legacy_remote_command("PAUSE", cb); },
2, 21);
run_one([&](auto cb) { w.handler->send_event_report_request(300, cb); }, 6, 15);
run_one([&](auto cb) { w.handler->send_individual_report_request(1, cb); },
6, 19);
run_one([&](auto cb) { w.handler->send_annotated_report_request(1, cb); },
6, 21);
run_one([&](auto cb) {
w.handler->send_pp_load_inquire("RECIPE-X", 4096, cb);
}, 7, 1);
run_one([&](auto cb) {
w.handler->send_delete_pp({"RECIPE-X", "RECIPE-Y"}, cb);
}, 7, 17);
}
TEST_CASE("HostHandler: inbound S5F1 alarm auto-acks with S5F2") {
Wired w;
// Equipment side stays silent on inbound; we only need the host to