///|
/// Provider-owned E15 manifest text for the deterministic CIA402 runner.
///|
priv struct Cia402RuntimeAdapterRule {
id : String
source_label : String
source_direction : String
source_payload_digest : Int?
classification : String
global_step_index : Int
protocol_label : String
object_id : String
from_role : String
from_device_id : String
to_role : String
to_device_id : String
terminal_label : String
reason : String
} derive(ToJson)
///|
priv struct Cia402RuntimeAdapterMapping {
id : String
application_id : String
asset_id : String
protocol_id : String
source_adapter_id : String
source_session_namespace : String
terminal_epoch_policy : String
rules : Array[Cia402RuntimeAdapterRule]
} derive(ToJson)
///|
priv struct Cia402RuntimeAdapterManifest {
schema : String
version : Int
manifest_id : String
provider_id : String
manifest_digest : String
mappings : Array[Cia402RuntimeAdapterMapping]
} derive(ToJson)
///|
pub fn cia402_protocol_runtime_adapter_manifest_text() -> String {
let source = cia402_runtime_adapter_manifest()
{ ..source, manifest_digest: cia402_runtime_adapter_manifest_digest(source) }
.to_json()
.stringify()
}
///|
fn cia402_runtime_adapter_manifest() -> Cia402RuntimeAdapterManifest {
{
schema: "isoproject.protocol-runtime-adapter-manifest.v1",
version: 1,
manifest_id: "cia402-deterministic-runtime-adapter",
provider_id: "mokomoking2501/fieldbus_core/cia402_scenario_loop",
manifest_digest: "",
mappings: [
{
id: "axis-control-cia402-axis-authority",
application_id: "axis-control",
asset_id: "cia402-enable-fault-reset",
protocol_id: "AxisAuthority",
source_adapter_id: "cia402-deterministic-runner",
source_session_namespace: "cia402",
terminal_epoch_policy: "terminal-closes-axis-authority;reset-begins-next-recovery-epoch",
rules: cia402_runtime_adapter_rules(),
},
],
}
}
///|
fn cia402_runtime_adapter_rules() -> Array[Cia402RuntimeAdapterRule] {
[
cia402_runtime_adapter_rule(
"edge-0-enable",
"cia402.controlword.write",
"tx",
Some(0x0006),
"exchange",
0,
"axis.lifecycle.enable",
"axis.lifecycle",
"controller",
"cell-0",
"drive",
"axis-1",
"",
"shutdown controlword realizes AxisAuthority enable",
),
cia402_runtime_adapter_rule(
"edge-1-status-ack",
"cia402.statusword.read",
"rx",
Some(0x0021),
"exchange",
1,
"axis.statusword.ack",
"axis.statusword",
"drive",
"axis-1",
"controller",
"cell-0",
"",
"ready-to-switch-on status realizes AxisAuthority acknowledgement",
),
cia402_runtime_adapter_rule(
"config-mode",
"cia402.mode.write",
"tx",
Some(0x08),
"ignored-configuration",
-1,
"",
"",
"",
"",
"",
"",
"",
"mode selection is profile configuration outside AxisAuthority",
),
cia402_runtime_adapter_rule(
"edge-2-target",
"cia402.target_position.write",
"tx",
Some(607_000),
"exchange",
2,
"axis.target_position.command",
"axis.target_position",
"controller",
"cell-0",
"drive",
"axis-1",
"",
"target write realizes AxisAuthority command",
),
cia402_runtime_adapter_rule(
"edge-3-actual",
"cia402.actual_position.read",
"rx",
Some(606_400),
"exchange",
3,
"axis.actual_position.signal",
"axis.actual_position",
"drive",
"axis-1",
"controller",
"cell-0",
"",
"actual position read realizes AxisAuthority signal",
),
cia402_runtime_adapter_rule(
"terminal-fault",
"cia402.fault.detected",
"rx",
Some(1),
"terminal",
-1,
"",
"",
"",
"",
"",
"",
"axis.lifecycle.fault",
"fault closes the current AxisAuthority epoch",
),
cia402_runtime_adapter_rule(
"fault-drop-metadata",
"drop",
"fault",
None,
"ignored-fault-metadata",
-1,
"",
"",
"",
"",
"",
"",
"",
"fault injection metadata is not a role action",
),
cia402_runtime_adapter_rule(
"recovery-reset-command",
"cia402.controlword.write",
"tx",
Some(0x0080),
"ignored-recovery",
-1,
"",
"",
"",
"",
"",
"",
"",
"fault reset begins the next recovery epoch",
),
cia402_runtime_adapter_rule(
"recovery-reset-status",
"cia402.statusword.read",
"rx",
Some(0x0040),
"ignored-recovery",
-1,
"",
"",
"",
"",
"",
"",
"",
"reset status belongs to the next recovery epoch",
),
]
}
///|
fn cia402_runtime_adapter_rule(
id : String,
source_label : String,
source_direction : String,
source_payload_digest : Int?,
classification : String,
global_step_index : Int,
protocol_label : String,
object_id : String,
from_role : String,
from_device_id : String,
to_role : String,
to_device_id : String,
terminal_label : String,
reason : String,
) -> Cia402RuntimeAdapterRule {
{
id,
source_label,
source_direction,
source_payload_digest,
classification,
global_step_index,
protocol_label,
object_id,
from_role,
from_device_id,
to_role,
to_device_id,
terminal_label,
reason,
}
}
///|
fn cia402_runtime_adapter_manifest_digest(
manifest : Cia402RuntimeAdapterManifest,
) -> String {
let text = cia402_runtime_adapter_manifest_canonical_text(manifest)
let mut digest = @core.SimDigest::empty(seed=5_510).mix(text.length())
for char in text {
digest = digest.mix(char.to_int())
}
digest.state_digest.to_string() + ":" + digest.event_count.to_string()
}
///|
fn cia402_runtime_adapter_manifest_canonical_text(
manifest : Cia402RuntimeAdapterManifest,
) -> String {
let builder = StringBuilder::new()
cia402_manifest_write_field(builder, "schema", manifest.schema)
cia402_manifest_write_field(builder, "version", manifest.version.to_string())
cia402_manifest_write_field(builder, "manifest_id", manifest.manifest_id)
cia402_manifest_write_field(builder, "provider_id", manifest.provider_id)
let mappings = manifest.mappings.copy()
mappings.sort_by((left, right) => {
cia402_manifest_mapping_key(left).compare(
cia402_manifest_mapping_key(right),
)
})
cia402_manifest_write_field(
builder,
"mapping_count",
mappings.length().to_string(),
)
for mapping in mappings {
cia402_manifest_write_field(builder, "mapping.id", mapping.id)
cia402_manifest_write_field(
builder,
"mapping.application_id",
mapping.application_id,
)
cia402_manifest_write_field(builder, "mapping.asset_id", mapping.asset_id)
cia402_manifest_write_field(
builder,
"mapping.protocol_id",
mapping.protocol_id,
)
cia402_manifest_write_field(
builder,
"mapping.source_adapter_id",
mapping.source_adapter_id,
)
cia402_manifest_write_field(
builder,
"mapping.source_session_namespace",
mapping.source_session_namespace,
)
cia402_manifest_write_field(
builder,
"mapping.terminal_epoch_policy",
mapping.terminal_epoch_policy,
)
let rules = mapping.rules.copy()
rules.sort_by((left, right) => {
cia402_manifest_rule_key(left).compare(cia402_manifest_rule_key(right))
})
cia402_manifest_write_field(
builder,
"mapping.rule_count",
rules.length().to_string(),
)
for rule in rules {
cia402_manifest_write_field(builder, "rule.id", rule.id)
cia402_manifest_write_field(
builder,
"rule.source_label",
rule.source_label,
)
cia402_manifest_write_field(
builder,
"rule.source_direction",
rule.source_direction,
)
cia402_manifest_write_field(
builder,
"rule.source_payload_digest",
match rule.source_payload_digest {
Some(value) => "some:" + value.to_string()
None => "none"
},
)
cia402_manifest_write_field(
builder,
"rule.classification",
rule.classification,
)
cia402_manifest_write_field(
builder,
"rule.global_step_index",
rule.global_step_index.to_string(),
)
cia402_manifest_write_field(
builder,
"rule.protocol_label",
rule.protocol_label,
)
cia402_manifest_write_field(builder, "rule.object_id", rule.object_id)
cia402_manifest_write_field(builder, "rule.from_role", rule.from_role)
cia402_manifest_write_field(
builder,
"rule.from_device_id",
rule.from_device_id,
)
cia402_manifest_write_field(builder, "rule.to_role", rule.to_role)
cia402_manifest_write_field(
builder,
"rule.to_device_id",
rule.to_device_id,
)
cia402_manifest_write_field(
builder,
"rule.terminal_label",
rule.terminal_label,
)
cia402_manifest_write_field(builder, "rule.reason", rule.reason)
}
}
builder.to_string()
}
///|
fn cia402_manifest_mapping_key(mapping : Cia402RuntimeAdapterMapping) -> String {
cia402_manifest_key_part(mapping.id) +
cia402_manifest_key_part(mapping.application_id) +
cia402_manifest_key_part(mapping.asset_id) +
cia402_manifest_key_part(mapping.protocol_id) +
cia402_manifest_key_part(mapping.source_adapter_id)
}
///|
fn cia402_manifest_rule_key(rule : Cia402RuntimeAdapterRule) -> String {
cia402_manifest_key_part(rule.id) +
cia402_manifest_key_part(rule.source_label) +
cia402_manifest_key_part(rule.source_direction) +
cia402_manifest_key_part(
match rule.source_payload_digest {
Some(value) => "some:" + value.to_string()
None => "none"
},
)
}
///|
fn cia402_manifest_write_field(
builder : StringBuilder,
name : String,
value : String,
) -> Unit {
builder.write_string(cia402_manifest_key_part(name))
builder.write_string(cia402_manifest_key_part(value))
builder.write_char('\n')
}
///|
fn cia402_manifest_key_part(value : String) -> String {
value.length().to_string() + ":" + value
}