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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user