D2: E87 wire messages (S3F17/F18 + F23/F24 + F25/F26 + F27/F28)
Adds the Carrier Management wire surface that drives the FSMs from D1:
S3F17 / S3F18 CarrierAction (host issues ProceedWithCarrier /
CancelCarrier / BindCarrierID / etc.; CommandParameter
list is reused from S2F41).
S3F23 / S3F24 PortGroupChangeReport (equipment notifies host of port
group composition changes).
S3F25 / S3F26 CarrierTransfer (host instructs source -> target port
transfer).
S3F27 / S3F28 CancelCarrier (host cancels an outstanding carrier op).
Two new ack enums in messages_helpers.hpp:
CarrierActionAck — CAACK byte; covers the common error responses
(CarrierIDUnknown, Inaccessible, ActionInProgress).
PortGroupAck — PGACK byte (Accept / Error).
Round-trip tests for all four pairs. Server-side dispatch + the
CarrierStore + LoadPortStore that the FSMs key into land in D3/D4.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1246,6 +1246,110 @@ messages:
|
||||
- {name: mapercd, shape: {kind: scalar, item_type: BINARY_BYTE}}
|
||||
- {name: errtext, shape: {kind: scalar, item_type: ASCII}}
|
||||
|
||||
# =====================================================================
|
||||
# S3 — E87 Carrier Management.
|
||||
#
|
||||
# CARRIERID is an ASCII identifier (per E87-0716 §10.2 typically up to
|
||||
# 40 chars). CAACK is the host/equipment ack byte for carrier-action
|
||||
# requests, modelled here as CarrierActionAck. PORTID is U1, SLOTID
|
||||
# is U1. We carry only the most common subset of S3 here; richer
|
||||
# forms (E14 generic ObjectService) are YAML extension points.
|
||||
# =====================================================================
|
||||
|
||||
# S3F17 / S3F18 — CarrierAction. Host instructs equipment to perform
|
||||
# a carrier-level operation (ProceedWithCarrier, CancelCarrier,
|
||||
# CancelCarrierAtPort, BindCarrierID, ResetCarrier, ...). The list of
|
||||
# parameters is action-specific; we carry it as a parallel name/value
|
||||
# list mirroring S2F41's CommandParameter shape.
|
||||
- id: S3F17
|
||||
stream: 3
|
||||
function: 17
|
||||
w: true
|
||||
builder: s3f17_carrier_action
|
||||
parser: parse_s3f17
|
||||
body:
|
||||
kind: list
|
||||
struct_name: CarrierActionRequest
|
||||
fields:
|
||||
- {name: dataid, shape: {kind: scalar, item_type: U4}}
|
||||
- {name: carrieraction, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: carrierid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- name: params
|
||||
shape:
|
||||
kind: list_of
|
||||
element:
|
||||
kind: list
|
||||
struct_name: CommandParameter
|
||||
external_struct: true
|
||||
fields:
|
||||
- {name: name, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: value, shape: {kind: scalar, item_type: ITEM}}
|
||||
|
||||
- id: S3F18
|
||||
stream: 3
|
||||
function: 18
|
||||
builder: s3f18_carrier_action_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: CarrierActionAck, param: caack}
|
||||
|
||||
# S3F23 / S3F24 — Port Group Change Report (equipment notifies host of
|
||||
# a port-grouping change; E87-0716 §10.4).
|
||||
- id: S3F23
|
||||
stream: 3
|
||||
function: 23
|
||||
w: true
|
||||
builder: s3f23_port_group_change_report
|
||||
parser: parse_s3f23
|
||||
body:
|
||||
kind: list
|
||||
struct_name: PortGroupChangeReport
|
||||
fields:
|
||||
- {name: ctngrpid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- name: portids
|
||||
shape: {kind: list_of, element: {kind: scalar, item_type: U1}}
|
||||
|
||||
- id: S3F24
|
||||
stream: 3
|
||||
function: 24
|
||||
builder: s3f24_port_group_change_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: PortGroupAck, param: pgack}
|
||||
|
||||
# S3F25 / S3F26 — Carrier Transfer (host instructs equipment to move
|
||||
# a carrier between source and target ports).
|
||||
- id: S3F25
|
||||
stream: 3
|
||||
function: 25
|
||||
w: true
|
||||
builder: s3f25_carrier_transfer
|
||||
parser: parse_s3f25
|
||||
body:
|
||||
kind: list
|
||||
struct_name: CarrierTransferRequest
|
||||
fields:
|
||||
- {name: carrierid, shape: {kind: scalar, item_type: ASCII}}
|
||||
- {name: source_portid, shape: {kind: scalar, item_type: U1}}
|
||||
- {name: target_portid, shape: {kind: scalar, item_type: U1}}
|
||||
|
||||
- id: S3F26
|
||||
stream: 3
|
||||
function: 26
|
||||
builder: s3f26_carrier_transfer_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: CarrierActionAck, param: caack}
|
||||
|
||||
# S3F27 / S3F28 — Cancel Carrier (host cancels a carrier operation).
|
||||
- id: S3F27
|
||||
stream: 3
|
||||
function: 27
|
||||
w: true
|
||||
builder: s3f27_cancel_carrier
|
||||
parser: parse_s3f27
|
||||
body: {kind: scalar, item_type: ASCII, param: carrierid}
|
||||
|
||||
- id: S3F28
|
||||
stream: 3
|
||||
function: 28
|
||||
builder: s3f28_cancel_carrier_ack
|
||||
body: {kind: scalar, item_type: BINARY_BYTE, enum: CarrierActionAck, param: caack}
|
||||
|
||||
# =====================================================================
|
||||
# S14 — Object services (E94 ControlJob create/delete).
|
||||
#
|
||||
|
||||
@@ -171,4 +171,22 @@ enum class MapDataAck : uint8_t { // S12F8 MAPER
|
||||
AbortNoMap = 3,
|
||||
};
|
||||
|
||||
// E87 §10.2 carrier-action ack code (CAACK). Same byte used by S3F18,
|
||||
// S3F26 (carrier transfer), and S3F28 (cancel carrier).
|
||||
enum class CarrierActionAck : uint8_t {
|
||||
Accept = 0,
|
||||
Invalid = 1,
|
||||
ParameterInvalid = 2,
|
||||
CarrierIDUnknown = 3,
|
||||
CarrierActionInvalid = 4,
|
||||
CarrierInaccessible = 5,
|
||||
CarrierActionInProgress = 6,
|
||||
};
|
||||
|
||||
// E87 §10.4 port-group change ack code.
|
||||
enum class PortGroupAck : uint8_t {
|
||||
Accept = 0,
|
||||
Error = 1,
|
||||
};
|
||||
|
||||
} // namespace secsgem::gem
|
||||
|
||||
@@ -737,3 +737,55 @@ TEST_CASE("S12F19 Map Error Send round-trip") {
|
||||
CHECK(parsed->errtext == "unrecognized MID");
|
||||
CHECK_FALSE(m.reply_expected);
|
||||
}
|
||||
|
||||
// ---- S3 E87 Carrier Management -----------------------------------------
|
||||
|
||||
TEST_CASE("S3F17 / S3F18 CarrierAction round-trip") {
|
||||
std::vector<CommandParameter> params{
|
||||
{"PORTID", s2::Item::u1(uint8_t{1})},
|
||||
};
|
||||
auto m = s3f17_carrier_action(/*dataid=*/3, "ProceedWithCarrier",
|
||||
"CAR-001", params);
|
||||
CHECK(m.stream == 3);
|
||||
CHECK(m.function == 17);
|
||||
CHECK(m.reply_expected);
|
||||
|
||||
auto parsed = parse_s3f17(m);
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK(parsed->dataid == 3);
|
||||
CHECK(parsed->carrieraction == "ProceedWithCarrier");
|
||||
CHECK(parsed->carrierid == "CAR-001");
|
||||
REQUIRE(parsed->params.size() == 1);
|
||||
CHECK(parsed->params[0].name == "PORTID");
|
||||
|
||||
CHECK(*ack_byte(s3f18_carrier_action_ack(CarrierActionAck::Accept)) == 0);
|
||||
CHECK(*ack_byte(s3f18_carrier_action_ack(CarrierActionAck::CarrierIDUnknown)) == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("S3F23 / S3F24 PortGroupChangeReport round-trip") {
|
||||
auto m = s3f23_port_group_change_report("GROUP-A", {1, 2, 3});
|
||||
auto parsed = parse_s3f23(m);
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK(parsed->ctngrpid == "GROUP-A");
|
||||
REQUIRE(parsed->portids.size() == 3);
|
||||
CHECK(parsed->portids[1] == 2);
|
||||
CHECK(*ack_byte(s3f24_port_group_change_ack(PortGroupAck::Accept)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("S3F25 / S3F26 CarrierTransfer round-trip") {
|
||||
auto m = s3f25_carrier_transfer("CAR-001", /*source=*/1, /*target=*/2);
|
||||
auto parsed = parse_s3f25(m);
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK(parsed->carrierid == "CAR-001");
|
||||
CHECK(parsed->source_portid == 1);
|
||||
CHECK(parsed->target_portid == 2);
|
||||
CHECK(*ack_byte(s3f26_carrier_transfer_ack(CarrierActionAck::Accept)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("S3F27 / S3F28 CancelCarrier round-trip") {
|
||||
auto m = s3f27_cancel_carrier("CAR-001");
|
||||
auto parsed = parse_s3f27(m);
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK(*parsed == "CAR-001");
|
||||
CHECK(*ack_byte(s3f28_cancel_carrier_ack(CarrierActionAck::Accept)) == 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user