public static string GenerateCanSignalTypeCode(CanSignalType canSignalType, int o, int n = 4) { var signal = canSignalType; StringBuilder stringBuilder = new StringBuilder(); //stringBuilder.AppendLine(n * (0 + o), $""); stringBuilder.AppendLine(n * (0 + o), $"public static readonly CanSignalType {signal.QualifiedName.Replace(".", "__")} = new CanSignalType"); stringBuilder.AppendLine(n * (0 + o), $"{{"); stringBuilder.AppendLine(n * (1 + o), $"Encoding = SignalEncoding.{signal.Encoding},"); stringBuilder.AppendLine(n * (1 + o), $"Type = SignalType.{signal.Type },"); stringBuilder.AppendLine(n * (1 + o), $"Length = {signal.Length },"); stringBuilder.AppendLine(n * (1 + o), $"MaxValue = {signal.MaxValue },"); stringBuilder.AppendLine(n * (1 + o), $"MinValue = {signal.MinValue },"); stringBuilder.AppendLine(n * (1 + o), $"Offset = {signal.Offset },"); stringBuilder.AppendLine(n * (1 + o), $"ScaleFactor = {signal.ScaleFactor },"); stringBuilder.AppendLine(n * (1 + o), $"StartBit = {signal.StartBit },"); stringBuilder.AppendLine(n * (1 + o), $"Comment = \"{signal.Comment }\","); stringBuilder.AppendLine(n * (1 + o), $"Name = \"{signal.Name }\","); stringBuilder.AppendLine(n * (1 + o), $"QualifiedName = \"{signal.QualifiedName }\","); stringBuilder.AppendLine(n * (1 + o), $"Unit = \"{signal.Unit }\","); stringBuilder.AppendLine(n * (0 + o), $"}};"); stringBuilder.AppendLine(n * (0 + o), $""); return(stringBuilder.ToString()); }
public static string GetDivisionOperator(this CanSignalType canSignalType) { if (canSignalType.ScaleFactor < 1) { return("*= " + (1 / canSignalType.ScaleFactor).ToString()); } return("/= " + canSignalType.ScaleFactor.ToString()); }
public static string GetSubtractionOperator(this CanSignalType canSignalType) { if (canSignalType.ScaleFactor < 1) { return("+= " + (-canSignalType.Offset).ToString()); } return("-= " + canSignalType.Offset.ToString()); }
/// <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 GetTypeName(this CanSignalType canSignalType) { int numberOfBits = canSignalType.Length; if (numberOfBits == 1) { return("bool"); } switch (canSignalType.Type) { case SignalType.Invalid: throw new NotImplementedException(); break; case SignalType.Signed: // TODO: Add support for booleans if (numberOfBits <= 8) { return("sbyte"); } else if (numberOfBits <= 16) { return("Int16"); } else if (numberOfBits <= 32) { return("Int32"); } else if (numberOfBits <= 64) { return("Int64"); } throw new Exception($"Too many bits in {canSignalType.QualifiedName}: {canSignalType.ToString()}"); break; case SignalType.Unsigned: if (numberOfBits <= 8) { return("byte"); } else if (numberOfBits <= 16) { return("UInt16"); } else if (numberOfBits <= 32) { return("UInt32"); } else if (numberOfBits <= 64) { return("UInt64"); } throw new Exception($"Too many bits in {canSignalType.QualifiedName}: {canSignalType.ToString()}"); break; case SignalType.Float: return("float"); break; case SignalType.Double: return("double"); break; } throw new Exception($"Type not identifyable in {canSignalType.QualifiedName}"); }
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()); }
/// <summary> /// Handles one signal definition line from a .dbc file and returns a new CanSignalType /// object with multiple fields populated. Not all information if available in one line, /// which is why not all fields are populated at once. /// </summary> /// <param name="line">The line from a .dbc file to be parsed.</param> /// <returns>CanSignalType object with multiple fields populated.</returns> protected static CanSignalType ParseDcbSignalDefinition(string line) { // Field to be populated and returned CanSignalType canSignalType = new CanSignalType(); // Split at white space var segments = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Debug.Assert(segments.Length == 8 || segments.Length == 9); string name = segments[1]; canSignalType.Name = name; // Skip signal multiplexing definition, if any var elementsAfterColon = segments.SkipWhile(word => !word.Equals(":")); // This enumerator is used to handle the different var signalDefinitionEnumerator = elementsAfterColon.GetEnumerator(); // Skip first element sing it contains the colon character signalDefinitionEnumerator.MoveNext(); signalDefinitionEnumerator.MoveNext(); // Parse bit definition // <StartBit>|<Length>@<Endianness><Signed> // Example: 40|8@1+ { var bitDefinition = signalDefinitionEnumerator.Current; var segments2 = bitDefinition.Split(new char[] { '|', '@' }); Debug.Assert(segments2.Length == 3); int startBit; if (Int32.TryParse(segments2[0], out startBit)) { canSignalType.StartBit = startBit; } int numberOfBits; if (Int32.TryParse(segments2[1], out numberOfBits)) { canSignalType.Length = numberOfBits; } bool littleEndian = true; bool signed = false; switch (segments2[2]) { case "0-": littleEndian = false; // aka Motorola signed = true; break; case "0+": littleEndian = false; // aka Motorola signed = false; break; case "1-": littleEndian = true; // aka Intel signed = true; break; case "1+": littleEndian = true; // aka Intel signed = false; break; } canSignalType.Encoding = littleEndian ? SignalEncoding.Intel : SignalEncoding.Motorola; canSignalType.Type = signed ? SignalType.Signed : SignalType.Unsigned; } signalDefinitionEnumerator.MoveNext(); // Parse scale factor and offset // Format: (<Factor>,<Offset>) // Example: (0.5,5) { var scaleOffset = signalDefinitionEnumerator.Current .TrimStart('(') .TrimEnd(')') .Split(','); Debug.Assert(scaleOffset.Length == 2); double scale; if (Double.TryParse(scaleOffset[0], out scale)) { canSignalType.ScaleFactor = scale; } // TODO: Handle the else-part. What should we do if the parsing fails? double offset; if (Double.TryParse(scaleOffset[1], out offset)) { canSignalType.Offset = offset; } // TODO: Handle the else-part. What should we do if the parsing fails? } signalDefinitionEnumerator.MoveNext(); // Parse minimum and maximum value // Format: [<Min>|<Max>] // Example: [5|132.5] { var minMax = signalDefinitionEnumerator.Current .TrimStart('[') .TrimEnd(']') .Split('|'); Debug.Assert(minMax.Length == 2); double minimum; if (Double.TryParse(minMax[0], out minimum)) { canSignalType.MinValue = minimum; } // TODO: Handle the else-part. What should we do if the parsing fails? double maximum; if (Double.TryParse(minMax[1], out maximum)) { canSignalType.MaxValue = maximum; } // TODO: Handle the else-part. What should we do if the parsing fails? } signalDefinitionEnumerator.MoveNext(); // Parse unit // Format: "<Unit>" // Example: "degC" { string unit = signalDefinitionEnumerator.Current .Trim('\"'); canSignalType.Unit = unit; } signalDefinitionEnumerator.MoveNext(); // Parse receiving nodes // Format: [ReceivingNodes] // Example: Front_Node,AMS,Rear_Node { var nodes = signalDefinitionEnumerator.Current.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); canSignalType.ReceivingNodes.AddRange(nodes); } canSignalType.CalculateBitMask(); return(canSignalType); }