A deterministic, dependency-free CAN 2.0 and CAN-FD toolkit for MoonBit.
moon check --target all --deny-warn
moon test --target all --deny-warnlet frame = @moonbit_canbus.data_frame(0x120, [0x2A]) catch {
_ => panic()
}
let wire = @moonbit_canbus.encode_frame(frame)
let restored = @moonbit_canbus.decode_frame(wire) catch {
_ => panic()
}
assert_true(@moonbit_canbus.frame_equal(frame, restored))moon run src/cmd/canctl -- demo
moon run src/cmd/canctl -- decode 01000000012303102030moon run src/cmd/bench| 层次 | 主要模块 | 责任 |
|---|---|---|
| Frame / wire | frame.mbt, frame_codec.mbt, wire.mbt, wire_codec.mbt | 帧不变量、DLC、CRC、bit stuffing 和可移植编码 |
| Transport | transport.mbt, isotp_engine.mbt, transport_queue.mbt | ISO-TP、队列、时序与边界处理 |
| Database | dbc.mbt, dbc_extended.mbt, dbc_runtime.mbt, dbc_serializer.mbt | DBC 解析、信号运行时和 schema 工具 |
| Diagnostics | diagnostic.mbt, uds_stack.mbt, diagnostic_session.mbt, diagnostic_codec.mbt | UDS 服务、会话状态和 DTC 报文 |
| Network | filter.mbt, can_network.mbt, routing.mbt, simulation.mbt | 过滤、网关、多节点网络和确定性仿真 |
| Analysis | trace.mbt, trace_tools.mbt, metrics.mbt, latency.mbt | 日志、指标、延迟和质量分析 |
moon fmt
moon check --target all --deny-warn
moon test --target all --deny-warn
moon infopub suberror AdmissionError {
InvalidRule
NoMatchingRule
ProtocolNotAllowed
PayloadTooLarge
RemoteNotAllowed
RateExceeded
TimestampReversed
} derive(Debug)pub suberror CanOpenError {
InvalidNodeId
InvalidCobId
InvalidIndex
InvalidSdoPayload
InvalidDataLength
} derive(Debug)pub suberror CanTextError {
InvalidHeader
InvalidFieldCount
InvalidTimestamp
InvalidPayload
} derive(Debug)pub suberror CanTimingError {
InvalidClock
InvalidBitrate
InvalidSamplePoint
NoTimingCandidate
} derive(Debug)pub suberror DbcError {
InvalidMessageLine(String)
InvalidSignalLine(String)
InvalidNumber(String)
}pub suberror DbcExtendedError {
InvalidMessage
InvalidSignal
InvalidNumber
MissingMessage
InvalidRange
} derive(Debug)pub suberror DbcRuntimeError {
InvalidSignalLayout
PayloadTooShort
PayloadTooLong
DuplicateSignal
MissingSignalValue
ValueOutOfRange
} derive(Debug)pub suberror DbcSchemaError {
DuplicateMessageId
InvalidIdentifier
EmptyMessageName
InvalidDlc
InvalidSignalLayout
OverlappingSignals
} derive(Debug)pub suberror DtcCodecError {
InvalidCode
InvalidPayload
InvalidRecordLength
CapacityExceeded
} derive(Debug)pub suberror FrameCodecError {
UnsupportedVersion
Truncated
InvalidFlags
InvalidPayloadLength
InvalidHex
} derive(Debug)pub suberror IsoTpError {
InvalidFrameSize
PayloadTooLarge
TruncatedPacket
InvalidFirstFrame
UnexpectedConsecutive
SequenceMismatch
LengthMismatch
UnsupportedFlowStatus
} derive(Debug)pub suberror J1939Error {
InvalidPriority
InvalidPgn
InvalidAddress
InvalidPayloadLength
InvalidSequence
TransferTooLarge
} derive(Debug)pub suberror NetworkError {
InvalidNodeId
DuplicateNode
UnknownNode
InvalidTimestamp
QueueFull
} derive(Debug)pub suberror SchedulerError {
InvalidPeriod
InvalidDeadline
DuplicateTask
UnknownTask
} derive(Debug)pub suberror TraceError {
NonMonotonicTimestamp
InvalidLine
InvalidTimestamp
InvalidFrame
} derive(Debug)pub suberror UdsError {
InvalidIdentifier
InvalidAddressFormat
EmptyPayload
InvalidBlockCounter
InvalidLength
} derive(Debug)pub suberror UdsSessionError {
InvalidTransition
SecurityRequired
ResponseTimeout
UnexpectedResponse
} derive(Debug)pub suberror WireCodecError {
InvalidEof
InvalidCrc
InvalidControl
InvalidDlc
InvalidFrameBits
} derive(Debug)pub suberror WireError {
InvalidStuffedBit
}pub struct AdmissionDecision {
accepted : Bool
rule_name : String
reason : String
}pub struct AdmissionPolicy {
rules : Array[AdmissionRule]
accepted_count : Int
rejected_count : Int
last_timestamp_us : UInt64?
}fn AdmissionPolicy::evaluate(self : AdmissionPolicy, frame : Frame, timestamp_us : UInt64) -> AdmissionDecision raise AdmissionErrorpub struct AdmissionRule {
name : String
filter : Filter
max_payload : Int
allow_fd : Bool
allow_remote : Bool
min_interval_us : UInt64
last_seen_us : UInt64?
}pub struct BusHealth {
state : BusHealthState
utilization : Double
drop_rate : Double
error_rate : Double
recommendations : Array[String]
}pub(all) enum ByteOrder {
BigEndian
LittleEndian
}pub struct CanBitTiming {
clock_hz : UInt
bitrate : UInt
prescaler : UInt
time_quanta : UInt
propagation_segment : UInt
phase_segment_1 : UInt
phase_segment_2 : UInt
sample_point_percent : Double
}pub struct CanNetwork {
timeout_us : UInt64
now_us : UInt64
nodes : Array[NetworkNode]
queue : FrameQueue
delivered : Int
}fn CanNetwork::add_node(self : CanNetwork, node_id : Byte, name : String, timestamp_us : UInt64) -> Unit raise NetworkErrorfn CanNetwork::heartbeat(self : CanNetwork, node_id : Byte, timestamp_us : UInt64) -> Unit raise NetworkErrorfn CanNetwork::offline_nodes(self : CanNetwork, timestamp_us : UInt64) -> Array[String] raise NetworkErrorfn CanNetwork::poll(self : CanNetwork, timestamp_us : UInt64) -> Array[NetworkDelivery] raise NetworkErrorfn CanNetwork::send(self : CanNetwork, sender : Byte, frame : Frame, timestamp_us : UInt64) -> UInt raise NetworkErrorpub(all) enum CanOpenCobType {
Nmt
Sync
Emergency
Pdo1Transmit
Pdo1Receive
Pdo2Transmit
Pdo2Receive
Pdo3Transmit
Pdo3Receive
Pdo4Transmit
Pdo4Receive
SdoTransmit
SdoReceive
Heartbeat
} derive(Debug)pub(all) enum CanOpenNmtCommand {
Start
Stop
EnterPreOperational
ResetNode
ResetCommunication
}pub enum CanOpenSdoCommand {
DownloadInitiate(index~ : UInt, sub_index~ : Byte, data~ : Array[Byte])
UploadInitiate(index~ : UInt, sub_index~ : Byte)
DownloadSegment(toggle~ : Bool, data~ : Array[Byte], last~ : Bool)
UploadSegment(toggle~ : Bool)
Abort(index~ : UInt, sub_index~ : Byte, code~ : UInt)
}fn CanScheduler::add(self : CanScheduler, name : String, frame : Frame, first_due_us : UInt64, period_us : UInt64, deadline_us : UInt64, count : Int) -> Unit raise SchedulerErrorfn CanScheduler::tick(self : CanScheduler, timestamp_us : UInt64) -> Array[SchedulerTick] raise SchedulerErrorpub struct CanTask {
name : String
frame : Frame
next_due_us : UInt64
period_us : UInt64
deadline_us : UInt64
remaining : Int
priority : Int
}fn DbcDatabase::decode_frame(self : DbcDatabase, frame : Frame) -> DecodedMessage? raise DbcRuntimeErrorpub struct DbcSchemaChange {
id : UInt
kind : String
before : String?
after : String?
}pub struct DbcSchemaReport {
message_count : Int
signal_count : Int
unique_identifier_count : Int
maximum_required_bytes : Int
}pub struct DecodedSignal {
name : String
raw : UInt
physical : Double
unit : String
}pub struct Filter {
id : UInt
mask : UInt
extended : Bool?
}pub struct FrameAnalysis {
unique_ids : Int
changed_payloads : Int
repeated_payloads : Int
average_payload : Double
minimum_gap_us : UInt64?
maximum_gap_us : UInt64?
}pub enum FrameClass {
ClassicData
ClassicRemote
CanFdData
SimulationError
}fn FrameQueue::enqueue(self : FrameQueue, channel : Byte, frame : Frame, enqueued_us : UInt64, deadline_us : UInt64) -> UInt raise QueueErrorfn FrameQueue::take_channel(self : FrameQueue, channel : Byte, limit : Int) -> Array[QueueItem] raise QueueErrorpub struct FrameReport {
valid : Bool
violations : Array[FrameViolation]
wire_bits : Int
stuffed_bits : Int
}pub enum FrameViolation {
IdentifierRange
ClassicPayloadRange
FdPayloadRange
RemoteCarriesData
FdControlOnClassic
InvalidErrorShape
NonCanonicalDlc
} derive(Debug)pub struct IsoTpConfig {
frame_bytes : Int
block_size : Byte
separation_time : Byte
}pub struct IsoTpReceiver {
config : IsoTpConfig
total_length : Int
payload : Array[Byte]
next_sequence : Byte
block_count : Int
}pub struct J1939Id {
priority : Byte
data_page : Bool
pdu_format : Byte
pdu_specific : Byte
source_address : Byte
}pub struct LatencySample {
sequence : UInt
created_us : UInt64
completed_us : UInt64
payload_bytes : Int
}pub struct LatencyStats {
count : Int
minimum_us : UInt64?
maximum_us : UInt64?
average_us : Double
p95_us : UInt64?
jitter_us : UInt64
payload_bytes : Int
}pub struct LatencyWindow {
capacity : Int
next_sequence : UInt
samples : Array[LatencySample]
last_completed_us : UInt64?
}fn LatencyWindow::record(self : LatencyWindow, created_us : UInt64, completed_us : UInt64, payload_bytes : Int) -> UInt raise LatencyErrorfn Message::encode_frame(self : Message, values : Map[String, Double], extended? : Bool) -> Frame raise DbcRuntimeErrorpub struct NetworkNode {
node_id : Byte
name : String
last_seen_us : UInt64
online : Bool
transmitted : Int
received : Int
}fn NodeRegistry::record_transmission(self : NodeRegistry, node_id : Byte) -> Unit raise NodeRegistryErrorfn NodeRegistry::register(self : NodeRegistry, node_id : Byte, name : String, filter : Filter) -> Unit raise NodeRegistryErrorpub struct PdoMapEntry {
index : UInt
sub_index : Byte
bit_offset : Int
bit_length : Int
}fn PdoMapping::add(self : PdoMapping, index : UInt, sub_index : Byte, bit_length : Int) -> Unit raise PdoErrorpub struct PdoValue {
index : UInt
sub_index : Byte
value : UInt
}pub struct Pgn {
number : UInt
name : String
data_length : Int
}pub struct QueueItem {
sequence : UInt
channel : Byte
frame : Frame
enqueued_us : UInt64
deadline_us : UInt64
}pub struct Signal {
name : String
start_bit : Int
size : Int
little_endian : Bool
signed : Bool
factor : Double
offset : Double
minimum : Double
maximum : Double
unit : String
}pub struct Simulation {
now_us : UInt64
bus : VirtualBus
events : Array[ScheduledFrame]
publishers : Array[PeriodicPublisher]
trace : Trace
scheduled : Int
delivered : Int
dropped : Int
arbitration_bits : UInt64
bitrate_kbps : UInt
}fn Simulation::add_periodic(self : Simulation, source : String, frame : Frame, first_timestamp_us : UInt64, period_us : UInt64, count : Int) -> Unit raise SimulationErrorfn Simulation::schedule(self : Simulation, timestamp_us : UInt64, frame : Frame, source? : String) -> Unit raise SimulationErrorpub struct SimulationReport {
start_us : UInt64
end_us : UInt64
scheduled : Int
delivered : Int
dropped : Int
arbitration_bits : UInt64
}pub struct UdsResponseInfo {
positive : Bool
response_service : Byte
payload : Array[Byte]
negative_code : Byte?
}pub enum UdsService {
DiagnosticSessionControl
EcuReset
ReadDataByIdentifier
WriteDataByIdentifier
ReadMemoryByAddress
WriteMemoryByAddress
RoutineControl
SecurityAccess
CommunicationControl
ClearDiagnosticInformation
ReadDtcInformation
RequestDownload
TransferData
RequestTransferExit
TesterPresent
}pub struct UdsSession {
state : UdsSessionState
unlocked : Bool
last_activity_us : UInt64
p2_timeout_us : UInt64
pending_service : UdsService?
}fn UdsSession::accept(self : UdsSession, request : DiagnosticRequest, payload : Array[Byte], timestamp_us : UInt64) -> UdsResponseInfo raise UdsSessionErrorfn UdsSession::begin(self : UdsSession, request : DiagnosticRequest, timestamp_us : UInt64) -> DiagnosticRequest raise UdsSessionErrorfn UdsSession::change_state(self : UdsSession, target : UdsSessionState) -> Unit raise UdsSessionErrorpub enum UdsSessionState {
DefaultSession
ProgrammingSession
ExtendedDiagnosticSession
SafetySystemDiagnosticSession
LockedSession
} derive(Debug)fn admission_rule(name : String, filter : Filter, max_payload? : Int, allow_fd? : Bool, allow_remote? : Bool, min_interval_us? : UInt64) -> AdmissionRule raise AdmissionErrorfn assess_bus_health(metrics : FrameMetrics, dropped : Int, duration_us : UInt64, bitrate_kbps : UInt) -> BusHealthfn calculate_bit_timing(clock_hz : UInt, bitrate : UInt, sample_point_percent : Double) -> CanBitTiming raise CanTimingErrorfn canopen_emergency(error_code : UInt, error_register : Byte, manufacturer_data : Array[Byte]) -> Array[Byte] raise CanOpenErrorfn canopen_sdo_download(index : UInt, sub_index : Byte, data : Array[Byte]) -> Array[Byte] raise CanOpenErrorfn canopen_sdo_download_command(index : UInt, sub_index : Byte, data : Array[Byte]) -> CanOpenSdoCommand raise CanOpenErrorfn canopen_sdo_download_segment(toggle : Bool, data : Array[Byte], last : Bool) -> CanOpenSdoCommand raise CanOpenErrorfn canopen_sdo_frame(node_id : Byte, transmit : Bool, payload : Array[Byte]) -> Frame raise CanOpenErrorfn counter_is_next(previous : Byte, current : Byte) -> Boolfn diagnostic_frame(request : DiagnosticRequest, id : UInt, extended? : Bool) -> Frame raise FrameErrorfn dtc_record(code : UInt, status : Byte, occurrence? : UInt, snapshot? : Array[Byte]) -> DtcRecord raise DtcCodecErrorfn fd_frame(id : UInt, data : Array[Byte], extended? : Bool, bitrate_switch? : Bool, error_state_indicator? : Bool) -> Frame raise FrameErrorfn fd_length_from_dlc(dlc : Byte) -> Intfn isotp_config(frame_bytes? : Int, block_size? : Byte, separation_time? : Byte) -> IsoTpConfig raise IsoTpErrorfn isotp_frames(tx_id : UInt, payload : Array[Byte], config : IsoTpConfig, extended? : Bool) -> Array[Frame] raise IsoTpErrorfn isotp_reassemble_frames(frames : Array[Frame], config : IsoTpConfig) -> Array[Byte] raise IsoTpErrorfn isotp_segment_checked(payload : Array[Byte], config : IsoTpConfig) -> Array[Array[Byte]] raise IsoTpErrorfn j1939_id(priority : Byte, data_page : Bool, pdu_format : Byte, pdu_specific : Byte, source_address : Byte) -> J1939Idfn j1939_reassemble_bam(packets : Array[Array[Byte]], total_length : Int) -> Array[Byte] raise J1939Errorfn parse_uds_response(request : DiagnosticRequest, payload : Array[Byte]) -> UdsResponseInfo raise UdsErrorfn payload_set_uint(data : Array[Byte], offset : Int, width : Int, value : UInt, order : ByteOrder) -> Array[Byte] raise PayloadErrorfn payload_uint(data : Array[Byte], offset : Int, width : Int, order : ByteOrder) -> UInt raise PayloadErrorfn read_memory(address : UInt, length : UInt, address_bytes? : Int, length_bytes? : Int) -> DiagnosticRequest raise UdsErrorfn request_download(data_format : Byte, address : UInt, length : UInt, address_bytes? : Int, length_bytes? : Int) -> DiagnosticRequest raise UdsErrorfn route_batch(gateway : CanGateway, frames : Array[Frame]) -> Array[RoutedFrame] raise RoutingErrorfn route_rule(name : String, filter : Filter, output_id? : UInt?, output_extended? : Bool?, prefix? : Array[Byte], strip_prefix? : Int) -> RouteRule raise RoutingErrorfn routine_control(routine_type : Byte, identifier : UInt, data? : Array[Byte]) -> DiagnosticRequest raise UdsErrorfn set_counter_nibble(data : Array[Byte], offset : Int, counter : Byte, high_nibble : Bool) -> Array[Byte] raise PayloadErrorfn signal(name : String, start_bit : Int, size : Int, little_endian? : Bool, signed? : Bool, factor? : Double, offset? : Double, minimum? : Double, maximum? : Double, unit? : String) -> Signalfn uds_negative_code_name(code : Byte) -> Stringfn write_memory(address : UInt, data : Array[Byte], address_bytes? : Int) -> DiagnosticRequest raise UdsErrorA deterministic, dependency-free CAN 2.0 and CAN-FD toolkit for MoonBit.