/// <summary> /// /// </summary> /// <param name="canMessageType">The CAN message type that you want to generate code for</param> /// <param name="n">Number of spaces per indent</param> /// <param name="o">Indent offset</param> /// <returns></returns> public static string GenerateCanMessageTypeCode(CanMessageType canMessageType, int o, int n = 4) { StringBuilder stringBuilder = new StringBuilder(); //stringBuilder.AppendLine(n * (0 + o), $""); stringBuilder.AppendLine(n * (0 + o), $"public static CanMessageType {canMessageType.Name} = new CanMessageType(new List<CanSignalType>{{"); foreach (var signal in canMessageType.Signals.Values) { stringBuilder.AppendLine(n * (2 + o), $"CanSignalTypes.{ signal.QualifiedName.Replace(".", "__")},"); } stringBuilder.AppendLine(n * (1 + o), $"}})"); stringBuilder.AppendLine(n * (0 + o), $"{{"); stringBuilder.AppendLine(n * (1 + o), $"Comment = \"{canMessageType.Comment }\","); stringBuilder.AppendLine(n * (1 + o), $"DLC = {canMessageType.DLC.ToString() },"); stringBuilder.AppendLine(n * (1 + o), $"Id = {canMessageType.Id.ToString() },"); stringBuilder.AppendLine(n * (1 + o), $"Name = \"{canMessageType.Name }\","); stringBuilder.AppendLine(n * (1 + o), $"QualifiedName = \"{canMessageType.QualifiedName }\","); stringBuilder.AppendLine(n * (1 + o), $"SendingNode = \"{canMessageType.SendingNode }\","); stringBuilder.AppendLine(n * (0 + o), $"}};"); stringBuilder.AppendLine(n * (0 + o), $""); return(stringBuilder.ToString()); }
/// <summary> /// Use this function to read a .dbc CAN database file. /// </summary> /// <param name="fullFilePath">Fulle path to the .dbc file</param> /// <returns>CanDataBasType object with all the relevant information from the .dbc file</returns> public static CanDatabaseType OpenCanDB(string fullFilePath) { CanDatabaseType canDatabaseType = new CanDatabaseType(); canDatabaseType.Name = Path.GetFileNameWithoutExtension(fullFilePath); // Read the file line by line. //System.IO.StreamReader file = new System.IO.StreamReader(fullFilePath); var canDbFile = File.ReadAllLines(fullFilePath).ToList(); List <String> .Enumerator enumerator = canDbFile.GetEnumerator(); while (enumerator.MoveNext()) { if (enumerator.Current.StartsWith("BU_")) { var nodes = ParseDbcNodeDefinition(enumerator.Current); foreach (var node in nodes) { canDatabaseType.Nodes.Add(node); } } if (enumerator.Current.StartsWith("BO_")) { CanMessageType temp = ParseDbcMessageDefinition(enumerator); canDatabaseType.CanMessageTypes.Add(temp.Id, temp); } if (enumerator.Current.StartsWith("CM_")) { ParseDbcCommentField(enumerator.Current, canDatabaseType.CanMessageTypes); } if (enumerator.Current.StartsWith("BA_DEF_")) { ParseDbcAttributeDefinition(enumerator.Current, canDatabaseType); } if (enumerator.Current.StartsWith("SIG_VALTYPE_")) { ParseDbcTypeDefinition(enumerator.Current, canDatabaseType.CanMessageTypes); } } foreach (var message in canDatabaseType.CanMessageTypes.Values) { message.QualifiedName = message.Name; //message.QualifiedName = canDatabaseType.Name + "." + message.Name; foreach (var signal in message.Signals.Values) { //signal.QualifiedName = canDatabaseType.Name + "." + signal.QualifiedName; } } return(canDatabaseType); }
/// <summary> /// Handles one CAN message definitioni line from a .dbc file and recursively /// calls ParseDbcMessageDefinition to handle CAN signal definition, which will /// cause the enumerator to advance. /// </summary> /// <param name="enumerator">An enumerators that is used to step through the /// .dbc file line by line.</param> /// <returns>A new CanMessageType object with most fields and all signals populated.</returns> protected static CanMessageType ParseDbcMessageDefinition(List <String> .Enumerator enumerator) { // Field to be populated and returned CanMessageType canMessageType = new CanMessageType(); string line = enumerator.Current; var segments = line.Split(' '); Debug.Assert(segments.Length == 5); int id; if (Int32.TryParse(segments[1], out id)) { canMessageType.Id = id; } // TODO: Handle the else-part. What should we do if the parsing fails? string name = segments[2].TrimEnd(':'); canMessageType.Name = name; int DLC; if (Int32.TryParse(segments[3], out DLC)) { canMessageType.DLC = DLC; } // TODO: Handle the else-part. What should we do if the parsing fails? string SendingNode = segments[4]; canMessageType.SendingNode = SendingNode; while (enumerator.MoveNext()) { if (!enumerator.Current.TrimStart(' ').StartsWith("SG_")) { break; } CanSignalType temp = ParseDcbSignalDefinition(enumerator.Current); canMessageType.Signals.Add(temp.Name, temp); } foreach (var signal in canMessageType.Signals.Values) { signal.QualifiedName = canMessageType.Name + "." + signal.Name; } return(canMessageType); }
protected static void ParseDbcCommentField(string line, Dictionary <int, CanMessageType> canMessageTypes) { // Format: CM_ [<BU_|BO_|SG_> [CAN-ID] [SignalName]] "<CommentText>"; var segments = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string comment; int messageId; switch (segments[1]) { case "BU_": string node = segments[2]; comment = segments[3].TrimEnd(';').Trim('\"'); // TODO: Implement node collection and add this information break; case "BO_": comment = segments[3].TrimEnd(';').Trim('\"'); if (Int32.TryParse(segments[2], out messageId)) { CanMessageType canMessage = canMessageTypes[messageId]; canMessage.Comment = comment; } break; case "SG_": string signalName = segments[3]; comment = segments[4].TrimEnd(';').Trim('\"'); if (Int32.TryParse(segments[2], out messageId)) { CanMessageType canMessage = canMessageTypes[messageId]; CanSignalType canSignal = canMessage.Signals[signalName]; canSignal.Comment = comment; } break; } }
public static string GenerateMessageCode(CanMessageType canMessageType, int o, int n = 4) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(n * (0 + o), $""); stringBuilder.AppendLine(n * (0 + o), $"public class {canMessageType.Name }Message : CanMessageExtended<{canMessageType.Name }Message>"); stringBuilder.AppendLine(n * (0 + o), $"{{"); stringBuilder.AppendLine(n * (1 + o), $"public {canMessageType.Name }Message() : base()"); stringBuilder.AppendLine(n * (1 + o), $"{{"); stringBuilder.AppendLine(n * (2 + o), $"MessageType = CanMessageTypes.{canMessageType.Name};"); stringBuilder.AppendLine(n * (2 + o), $"Id = {canMessageType.Id};"); stringBuilder.AppendLine(n * (1 + o), $"}}"); // TODO: Implement support for IEEE floats foreach (var CanSignalType in canMessageType.Signals.Values) { string type = CanSignalType.GetTypeName(); string floatException = ""; // This is used to append 'f' for float literals if (CanSignalType.Type == SignalType.Float) { floatException = "f"; } // Check if any scaling or offsetting is performed. If so, then it only makes sense // to treat it as float. string originalType = type; if (CanSignalType.Offset != 0 || CanSignalType.ScaleFactor != 1) { type = "float"; } string boolException1 = ""; string boolException2 = ""; if (type == "bool") { boolException1 = "!= 0"; boolException2 = "? 1 : 0"; } stringBuilder.AppendLine(n * (1 + o), $"public {type} {CanSignalType.Name}()"); stringBuilder.AppendLine(n * (1 + o), $"{{"); stringBuilder.AppendLine(n * (2 + o), $"// Get bits from raw data storage and cast"); stringBuilder.AppendLine(n * (2 + o), $"{originalType} tempValue1 = ({originalType})(ExtractBits(CanSignalTypes.{CanSignalType.QualifiedName.Replace(".", "__")}) {boolException1});"); stringBuilder.AppendLine(n * (2 + o), $"{type} tempValue2 = ({type}) tempValue1;"); stringBuilder.AppendLine(n * (2 + o), $"// Apply inverse transform to restore actual value"); if (CanSignalType.ScaleFactor != 1) { stringBuilder.AppendLine(n * (2 + o), $"tempValue2 {CanSignalType.GetMultiplierOperator()}{floatException};"); } if (CanSignalType.Offset != 0) { stringBuilder.AppendLine(n * (2 + o), $"tempValue2 {CanSignalType.GetAdditionOperator() }{floatException};"); } stringBuilder.AppendLine(n * (2 + o), $"return tempValue2;"); stringBuilder.AppendLine(n * (1 + o), $"}}"); stringBuilder.AppendLine(n * (1 + o), $""); stringBuilder.AppendLine(n * (1 + o), $"public void {CanSignalType.Name}({type} value)"); stringBuilder.AppendLine(n * (1 + o), $"{{"); stringBuilder.AppendLine(n * (2 + o), $"// Scale and offset value according to signal specification"); if (CanSignalType.Offset != 0) { stringBuilder.AppendLine(n * (2 + o), $"value {CanSignalType.GetSubtractionOperator() }{floatException};"); } if (CanSignalType.ScaleFactor != 1) { stringBuilder.AppendLine(n * (2 + o), $"value {CanSignalType.GetDivisionOperator() }{floatException};"); } stringBuilder.AppendLine(n * (2 + o), $"// Cast to integer and prepare for sending"); stringBuilder.AppendLine(n * (2 + o), $"this.InsertBits(CanSignalTypes.{CanSignalType.QualifiedName.Replace(".", "__")}, (UInt64)(value {boolException2}));"); stringBuilder.AppendLine(n * (1 + o), $"}}"); } //stringBuilder.AppendLine(n * (1 + o), $""); stringBuilder.AppendLine(n * (0 + o), $"}}"); stringBuilder.AppendLine(n * (0 + o), $""); return(stringBuilder.ToString()); }