A DBC parser and CAN signal codec toolkit written in MoonBit.
Dependencies
let source =
#|BO_ 256 Powertrain: 8 ECU
#| SG_ EngineSpeed : 0|16@1+ (0.125,0) [0|8000] "rpm" Dashboard
let result = @moondbc.parse(source)
if result.is_valid() {
let message = result.database.find_message(256U).unwrap()
let signal = message.find_signal("EngineSpeed").unwrap()
let speed = signal.decode(b"\x40\x1f\x00\x00\x00\x00\x00\x00").unwrap()
println("\{message.name}: \{speed} rpm")
}let trace = result.database.decode_trace(
"(1697042645.123456) can0 100##1401F000000000000",
)
let csv = trace.to_csv().unwrap()let parsed = @moondbc.parse_with_source_map(source)
let layout = parsed.analyze_frame_layout(256U).unwrap()
let first_bit = layout.find_cell(0, 0).unwrap()
for owner in first_bit.owners {
println("\{owner.signal_name} bit \{owner.signal_bit}")
}git clone https://github.com/cn-cheems/MoonDBC.git
cd MoonDBC
moon updatemoon run cmd/main
moon run cmd/codegen
moon check --target wasm --deny-warn
moon test --target wasm --deny-warnmoon install moonbit-community/warren
warren dev --browser-entry workbenchmoon run --target native cmd/moondbc -- check examples/vehicle.dbc
moon run --target native cmd/moondbc -- list examples/vehicle.dbc
moon run --target native cmd/moondbc -- decode examples/vehicle.dbc examples/vehicle.log
moon run --target native cmd/moondbc -- summary examples/vehicle.dbc examples/vehicle.log
moon run --target native cmd/moondbc -- encode examples/vehicle.dbc 100 EngineSpeed=1000 CoolantTemp=85 Gear=1
moon run --target native cmd/moondbc -- format examples/vehicle.dbc
moon run --target native cmd/moondbc -- format --check examples/vehicle.dbc
moon run --target native cmd/moondbc -- diff examples/vehicle.dbc examples/vehicle-v2.dbc
moon run --target native cmd/moondbc -- generate examples/vehicle.dbc > vehicle_constants.mbt
moon run --target native cmd/moondbc -- generate-codecs examples/vehicle.dbc > vehicle_codecs.mbtpub(all) enum CanLogTextError {
CanLogInvalidFieldCount(Int)
CanLogInvalidTimestamp(String)
CanLogInvalidInterface(String)
CanLogMissingFdFlags
CanLogInvalidFdFlags(String)
CanLogFdFlagsOutOfRange(Int)
CanLogTimestampWithoutInterface
CanLogFrameTextError(CanFrameTextError)
} derive(Eq, Debug)pub(all) struct CommentSourceLocation {
target : DbcCommentTarget
declaration : SourceSpan
} derive(Eq, Debug)pub(all) struct CompatibilityReport {
changes : Array[ClassifiedChange]
breaking_count : Int
non_breaking_count : Int
informational_count : Int
} derive(Eq, Debug)pub(all) struct Database {
version : String?
nodes : Array[String]
messages : Array[Message]
value_tables : Array[ValueTable]
global_value_tables : Array[GlobalValueTable]
environment_variables : Array[EnvironmentVariable]
signal_groups : Array[SignalGroup]
comments : Array[DbcComment]
attributes : DbcAttributes
} derive(Eq, Debug)fn Database::analyze_frame_layout(self : Database, message_id : UInt) -> Result[FrameLayoutAnalysis, FrameLayoutError]fn Database::attribute_value(self : Database, name : StringView, target : DbcAttributeTarget) -> DbcAttributeValue?fn Database::decode_can_frame(self : Database, frame : CanFrame) -> Result[DecodedMessage, FrameDecodeError]fn Database::decode_can_payload(self : Database, frame_id : UInt, is_extended_frame : Bool, payload : BytesView) -> Result[DecodedMessage, FrameDecodeError]fn Database::decode_frame(self : Database, message_id : UInt, payload : BytesView) -> Result[DecodedMessage, FrameDecodeError]fn Database::encode_can_frame(self : Database, frame_id : UInt, is_extended_frame : Bool, assignments : Array[SignalAssignment]) -> Result[CanFrame, FrameEncodeError]fn Database::encode_frame(self : Database, message_id : UInt, assignments : Array[SignalAssignment]) -> Result[Bytes, FrameEncodeError]fn Database::find_signal_group(self : Database, message_id : UInt, name : StringView) -> SignalGroup?fn Database::find_value_table(self : Database, message_id : UInt, signal_name : StringView) -> ValueTable?pub(all) enum DatabaseChange {
VersionChangedChange(String?, String?)
NodesChangedChange(Array[String], Array[String])
CommentAddedChange(DbcComment)
CommentRemovedChange(DbcComment)
CommentModifiedChange(DbcCommentTarget, String, String)
MessageAddedChange(Message)
MessageRemovedChange(Message)
MessageMetadataChangedChange(UInt, MessageMetadata, MessageMetadata)
SignalAddedChange(UInt, Signal)
SignalRemovedChange(UInt, Signal)
SignalModifiedChange(UInt, String, Signal, Signal)
ValueTableAddedChange(ValueTable)
ValueTableRemovedChange(ValueTable)
ValueTableModifiedChange(UInt, String, ValueTable, ValueTable)
GlobalValueTableAddedChange(GlobalValueTable)
GlobalValueTableRemovedChange(GlobalValueTable)
GlobalValueTableModifiedChange(String, GlobalValueTable, GlobalValueTable)
EnvironmentVariableAddedChange(EnvironmentVariable)
EnvironmentVariableRemovedChange(EnvironmentVariable)
EnvironmentVariableModifiedChange(String, EnvironmentVariable, EnvironmentVariable)
SignalGroupAddedChange(SignalGroup)
SignalGroupRemovedChange(SignalGroup)
SignalGroupModifiedChange(UInt, String, SignalGroup, SignalGroup)
AttributesChangedChange(DbcAttributes, DbcAttributes)
} derive(Eq, Debug)pub(all) struct DbcAttributeAssignment {
name : String
target : DbcAttributeTarget
value : DbcAttributeValue
} derive(Eq, Debug)fn DbcAttributeAssignment::not_equal(x : DbcAttributeAssignment, y : DbcAttributeAssignment) -> Boolpub(all) struct DbcAttributeDefinition {
name : String
scope : DbcAttributeScope
value_type : DbcAttributeType
} derive(Eq, Debug)fn DbcAttributeDefinition::not_equal(x : DbcAttributeDefinition, y : DbcAttributeDefinition) -> Boolpub(all) struct DbcAttributes {
definitions : Array[DbcAttributeDefinition]
defaults : Array[DbcAttributeDefault]
assignments : Array[DbcAttributeAssignment]
} derive(Eq, Debug)pub(all) struct DbcSourceMap {
messages : Array[MessageSourceLocation]
signals : Array[SignalSourceLocation]
comments : Array[CommentSourceLocation]
value_tables : Array[ValueTableSourceLocation]
global_value_tables : Array[GlobalValueTableSourceLocation]
environment_variables : Array[EnvironmentVariableSourceLocation]
signal_groups : Array[SignalGroupSourceLocation]
} derive(Eq, Debug)fn DbcSourceMap::find_signal(self : DbcSourceMap, message_id : UInt, signal_name : StringView) -> SourceSpan?fn DbcSourceMap::find_signal_group(self : DbcSourceMap, message_id : UInt, name : StringView) -> SourceSpan?fn DbcSourceMap::find_value_table(self : DbcSourceMap, message_id : UInt, signal_name : StringView) -> SourceSpan?pub(all) enum DbcWriteError {
DbcWriteInvalidToken(String, String)
DbcWriteInvalidQuotedText(String, String)
DbcWriteInvalidPayloadSize(UInt, Int)
DbcWriteNonFiniteSignalNumber(UInt, String, String)
DbcWriteNegativeMultiplexValue(UInt, String, Int)
DbcWriteInvalidMultiplexRange(UInt, String, Int, Int)
DbcWriteEmptyValueTable(UInt, String)
DbcWriteEmptyGlobalValueTable(String)
DbcWriteDuplicateTransmitter(UInt, String)
DbcWriteInvalidMessageIdentifier(UInt)
DbcWriteInvalidAttribute(String)
DbcWriteInvalidSignalGroup(UInt, String)
DbcWriteInvalidEnvironmentVariable(String)
} derive(Eq, Debug)pub(all) struct DecodedMessage {
id : UInt
is_extended_frame : Bool
name : String
signals : Array[DecodedSignal]
} derive(Eq, Debug)pub(all) struct DecodedTraceFrame {
line : Int
timestamp : String?
interface_name : String?
fd_flags : Byte?
frame : CanFrame
decoded : DecodedMessage
} derive(Eq, Debug)pub(all) enum EncodeError {
EncodeInvalidLayout(Int, Int)
EncodeFrameTooShort(Int, Int)
ValueKindMismatch(ValueKind, RawValue)
SignalValueTypeMismatch(SignalValueType, RawValue)
RawValueOutOfRange(RawValue, Int)
InvalidFactor(Double)
NonFinitePhysicalValue(Double)
PhysicalValueOutOfRange(Double, Double, Double)
PhysicalRawOutOfRange(Double, Int)
} derive(Eq, Debug)pub(all) struct EnvironmentVariableSourceLocation {
name : String
declaration : SourceSpan
} derive(Eq, Debug)fn EnvironmentVariableSourceLocation::not_equal(x : EnvironmentVariableSourceLocation, y : EnvironmentVariableSourceLocation) -> Boolpub(all) enum FrameDecodeError {
UnknownMessage(UInt)
InvalidCanFrameIdentifier(UInt, Bool)
UnknownCanMessage(UInt, Bool)
PayloadTooShort(Int, Int)
MissingMultiplexer
MultipleMultiplexers
SignalDecodeFailed(String, DecodeError)
} derive(Eq, Debug)pub(all) enum FrameEncodeError {
FrameEncodeUnknownMessage(UInt)
FrameEncodeInvalidCanIdentifier(UInt, Bool)
FrameEncodeUnknownCanMessage(UInt, Bool)
FrameEncodeInvalidPayloadSize(Int)
FrameEncodeUnknownSignal(String)
FrameEncodeDuplicateSignal(String)
FrameEncodeMissingSignal(String)
FrameEncodeInactiveSignal(String, Int)
FrameEncodeInactiveRangeSignal(String)
FrameEncodeMissingMultiplexer
FrameEncodeMultipleMultiplexers
FrameSignalEncodeFailed(String, EncodeError)
FrameMultiplexerDecodeFailed(String, DecodeError)
} derive(Eq, Debug)pub(all) struct FrameLayoutAnalysis {
message_id : UInt
payload_size : Int
cells : Array[FrameLayoutCell]
issues : Array[FrameLayoutIssue]
} derive(Eq, Debug)fn FrameLayoutAnalysis::find_cell(self : FrameLayoutAnalysis, byte_index : Int, bit_in_byte : Int) -> FrameLayoutCell?pub(all) struct FrameLayoutCell {
absolute_bit : Int
byte_index : Int
bit_in_byte : Int
kind : FrameLayoutCellKind
owners : Array[FrameLayoutOwner]
} derive(Eq, Debug)pub(all) enum FrameLayoutIssue {
LayoutInvalidPayloadSize(Int)
LayoutInvalidSignal(String, Int, Int, SourceSpan?)
LayoutSignalOutsidePayload(String, SourceSpan?)
LayoutConflictingSignals(String, String, Array[Int], SourceSpan?, SourceSpan?)
} derive(Eq, Debug)pub(all) struct FrameLayoutOwner {
signal_index : Int
signal_name : String
signal_bit : Int
multiplex : MultiplexRole
source : SourceSpan?
} derive(Eq, Debug)pub(all) struct GlobalValueTable {
name : String
entries : Array[ValueDescription]
} derive(Eq, Debug)pub(all) struct GlobalValueTableSourceLocation {
name : String
declaration : SourceSpan
} derive(Eq, Debug)fn GlobalValueTableSourceLocation::not_equal(x : GlobalValueTableSourceLocation, y : GlobalValueTableSourceLocation) -> Boolpub(all) struct LocatedDatabaseChange {
change : DatabaseChange
before : SourceSpan?
after : SourceSpan?
} derive(Eq, Debug)pub(all) struct LocatedValidationIssue {
issue : ValidationIssue
source : SourceSpan?
} derive(Eq, Debug)fn LocatedValidationIssue::not_equal(x : LocatedValidationIssue, y : LocatedValidationIssue) -> Boolfn Message::decode_frame(self : Message, payload : BytesView) -> Result[DecodedMessage, FrameDecodeError]fn Message::encode_frame(self : Message, assignments : Array[SignalAssignment]) -> Result[Bytes, FrameEncodeError]pub(all) struct MessageSourceLocation {
message_id : UInt
declaration : SourceSpan
} derive(Eq, Debug)pub(all) enum MultiplexRole {
Plain
Multiplexer
Multiplexed(Int)
MultiplexedRanges(String, Array[MultiplexRange])
} derive(Eq, Debug)pub(all) struct ParseResult {
database : Database
diagnostics : Array[Diagnostic]
} derive(Eq, Debug)pub(all) struct Signal {
name : String
start_bit : Int
bit_length : Int
byte_order : ByteOrder
value_kind : ValueKind
value_type : SignalValueType
factor : Double
offset : Double
minimum : Double
maximum : Double
unit : String
receivers : Array[String]
multiplex : MultiplexRole
} derive(Eq, Debug)fn Signal::encode(self : Signal, payload : BytesView, physical : Double) -> Result[Bytes, EncodeError]fn Signal::encode_raw(self : Signal, payload : BytesView, value : RawValue) -> Result[Bytes, EncodeError]pub(all) struct SignalGroupSourceLocation {
message_id : UInt
name : String
declaration : SourceSpan
} derive(Eq, Debug)fn SignalGroupSourceLocation::not_equal(x : SignalGroupSourceLocation, y : SignalGroupSourceLocation) -> Boolpub(all) struct SignalSourceLocation {
message_id : UInt
signal_name : String
declaration : SourceSpan
} derive(Eq, Debug)pub(all) struct SourceParseResult {
database : Database
diagnostics : Array[Diagnostic]
source_map : DbcSourceMap
} derive(Eq, Debug)fn SourceParseResult::analyze_frame_layout(self : SourceParseResult, message_id : UInt) -> Result[FrameLayoutAnalysis, FrameLayoutError]fn SourceParseResult::diff_with_locations(self : SourceParseResult, newer : SourceParseResult) -> Array[LocatedDatabaseChange]fn SourceParseResult::locate_validation_issues(self : SourceParseResult) -> Array[LocatedValidationIssue]pub(all) struct TraceDecodeResult {
frames : Array[DecodedTraceFrame]
diagnostics : Array[TraceDiagnostic]
} derive(Eq, Debug)pub(all) enum TraceError {
TraceFrameTextError(CanFrameTextError)
TraceCanLogTextError(CanLogTextError)
TraceFrameDecodeError(FrameDecodeError)
} derive(Eq, Debug)pub(all) enum ValidationIssue {
InvalidMessageIdentifierIssue(UInt)
DuplicateMessageIdIssue(UInt)
InvalidPayloadSizeIssue(UInt, Int)
DuplicateSignalNameIssue(UInt, String)
InvalidSignalLayoutIssue(UInt, String, Int, Int)
InvalidSignalValueTypeIssue(UInt, String, SignalValueType, Int)
FloatingMultiplexerIssue(UInt, String, SignalValueType)
SignalOutsidePayloadIssue(UInt, String)
InvalidScaleIssue(UInt, String, Double, Double)
InvalidPhysicalRangeIssue(UInt, String, Double, Double)
MultipleMultiplexersIssue(UInt)
MissingMultiplexerIssue(UInt, String)
MultiplexSelectorOutOfRangeIssue(UInt, String, Int)
InvalidMultiplexRangeIssue(UInt, String, Int, Int)
UnknownMultiplexSelectorIssue(UInt, String, String)
OverlappingSignalsIssue(UInt, String, String)
DuplicateCommentIssue(DbcCommentTarget)
UnknownCommentNodeIssue(String)
UnknownCommentMessageIssue(UInt)
UnknownCommentSignalIssue(UInt, String)
UnknownCommentEnvironmentIssue(String)
DuplicateMessageTransmitterIssue(UInt, String)
DuplicateAttributeDefinitionIssue(String)
DuplicateAttributeDefaultIssue(String)
DuplicateAttributeAssignmentIssue(String, DbcAttributeTarget)
UnknownAttributeDefinitionIssue(String)
InvalidAttributeTargetIssue(String, DbcAttributeTarget)
AttributeScopeMismatchIssue(String, DbcAttributeTarget)
InvalidAttributeValueIssue(String)
DuplicateSignalGroupIssue(UInt, String)
InvalidSignalGroupIssue(UInt, String)
UnknownSignalGroupMessageIssue(UInt, String)
UnknownSignalGroupMemberIssue(UInt, String, String)
DuplicateGlobalValueTableIssue(String)
InvalidGlobalValueTableIssue(String)
DuplicateEnvironmentVariableIssue(String)
InvalidEnvironmentVariableIssue(String)
} derive(Eq, Debug)pub(all) struct ValueTable {
message_id : UInt
signal_name : String
entries : Array[ValueDescription]
} derive(Eq, Debug)pub(all) struct ValueTableSourceLocation {
message_id : UInt
signal_name : String
declaration : SourceSpan
} derive(Eq, Debug)fn ValueTableSourceLocation::not_equal(x : ValueTableSourceLocation, y : ValueTableSourceLocation) -> Boolfn run_decode_cli(dbc_path : String, dbc_source : StringView, trace_path : String, trace_source : StringView) -> CliOutputfn run_diff_cli(before_path : String, before_source : StringView, after_path : String, after_source : StringView) -> CliOutputfn run_summary_cli(dbc_path : String, dbc_source : StringView, trace_path : String, trace_source : StringView) -> CliOutputInstall
Download zipA DBC parser and CAN signal codec toolkit written in MoonBit.
Dependencies