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());
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        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());
        }
Beispiel #8
0
        /// <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);
        }