///|
/// Local MoonECAT CiA 402 adapter for offline Isochronon conformance fixtures.
///|
pub fn package_id() -> String {
"fieldbus_core/moonecat_cia402_adapter"
}
///|
pub(all) struct MoonEcatCia402Asset {
object_id : String
label : String
index : UInt
subindex : Byte
channel : String
source_path : String
source_symbol : String
behavior : String
} derive(Eq, Debug)
///|
pub fn moonecat_cia402_assets() -> Array[MoonEcatCia402Asset] {
[
{
object_id: "axis.controlword",
label: "cia402.controlword.write",
index: @profile_cia402.cia402_controlword_index,
subindex: b'\x00',
channel: "sdo/rxpdo",
source_path: "MoonECAT/runtime/run.mbt",
source_symbol: "derive_startup_outputs_with_commands",
behavior: "writes 0x0006 to 0x6040:0 when DS402 channels expose a 16-bit controlword in RxPDO",
},
{
object_id: "axis.statusword",
label: "cia402.statusword.read",
index: @profile_cia402.cia402_statusword_index,
subindex: b'\x00',
channel: "sdo/txpdo",
source_path: "MoonECAT/protocol/integration_test.mbt",
source_symbol: "sdo_upload_retry 0x6041",
behavior: "uploads 0x6041:0 statusword through CoE SDO retry fixtures and maps it in TxPDO fixtures",
},
{
object_id: "axis.mode",
label: "cia402.mode.write",
index: @profile_cia402.cia402_mode_of_operation_index,
subindex: b'\x00',
channel: "sdo/rxpdo",
source_path: "MoonECAT/runtime/run.mbt",
source_symbol: "preferred_ds402_mode_seed",
behavior: "selects 0x08 profile position mode when 0x607A:0 target position is present in RxPDO",
},
{
object_id: "axis.target_position",
label: "cia402.target_position.write",
index: @profile_cia402.cia402_target_position_index,
subindex: b'\x00',
channel: "rxpdo",
source_path: "MoonECAT/mailbox/mailbox_test.mbt",
source_symbol: "SiiPdoEntry 0x607A",
behavior: "records 0x607A:0 target position as a 32-bit RxPDO entry",
},
{
object_id: "axis.actual_position",
label: "cia402.actual_position.read",
index: @profile_cia402.cia402_actual_position_index,
subindex: b'\x00',
channel: "txpdo",
source_path: "MoonECAT/mailbox/mailbox_test.mbt",
source_symbol: "SiiPdoEntry 0x6064",
behavior: "records 0x6064:0 actual position as a 32-bit TxPDO entry",
},
{
object_id: "axis.fault",
label: "cia402.fault.detected",
index: @profile_cia402.cia402_fault_index,
subindex: b'\x00',
channel: "profile-event",
source_path: "MoonECAT/runtime/run.mbt",
source_symbol: "RunFault",
behavior: "normalizes MoonECAT runtime fault surface to a profile-level axis.fault event; MoonECAT does not currently expose 0x603F directly",
},
]
}
///|
pub fn moonecat_cia402_bindings() -> Array[@isocontract.ObjectBinding] {
@profile_cia402.cia402_coe_bindings()
}
///|
pub fn moonecat_cia402_contracts() -> @isocontract.ContractRegistry {
@profile_cia402.cia402_object_contracts()
}
///|
pub fn moonecat_cia402_protocol() -> @protocol_ast.GlobalProtocol {
@profile_cia402.cia402_enable_fault_reset_protocol()
}
///|
pub fn moonecat_cia402_observer_backend() -> @protocol_ast.ObserverBackend {
@protocol_ast.ObserverBackend::new(
registry=moonecat_cia402_contracts(),
protocol=moonecat_cia402_protocol(),
roles=[@protocol_ast.role(name="controller")],
)
}
///|
pub fn moonecat_cia402_trace_fixture() -> @trace.TraceLog {
let log = @trace.TraceLog::new()
log.append(
adapter_event(1, "cia402.controlword.write", @trace.Tx, 0L, Some(0x0006)),
)
log.append(
adapter_event(2, "cia402.statusword.read", @trace.Rx, 10L, Some(0x0021)),
)
log.append(adapter_event(3, "cia402.mode.write", @trace.Tx, 20L, Some(0x08)))
log.append(
adapter_event(
4,
"cia402.target_position.write",
@trace.Tx,
30L,
Some(607_000),
),
)
log.append(
adapter_event(
5,
"cia402.actual_position.read",
@trace.Rx,
40L,
Some(606_400),
),
)
log.append(adapter_event(6, "cia402.fault.detected", @trace.Rx, 50L, Some(1)))
log.append(
adapter_event(7, "cia402.controlword.write", @trace.Tx, 60L, Some(0x0080)),
)
log.append(
adapter_event(8, "cia402.statusword.read", @trace.Rx, 70L, Some(0x0040)),
)
log
}
///|
pub fn moonecat_cia402_observer_report() -> @protocol_ast.ConformanceReport {
moonecat_cia402_observer_backend().check_trace(
moonecat_cia402_trace_fixture(),
)
}
///|
fn adapter_event(
event_id : Int,
label : String,
direction : @trace.TraceDirection,
time_ns : Int64,
payload_digest : Int?,
) -> @trace.TraceEvent {
@trace.TraceEvent::make(
event_id~,
parent_id=None,
vtime=@core.VTime::from_ns(time_ns),
clock_domain="sim",
raw_ns=time_ns,
node_id="controller",
medium_id="trace",
channel_id=None,
direction~,
payload_digest~,
rng_step=event_id,
seed=402,
backend=@core.SimNative,
label~,
)
}