1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Exceptions;
10 using Antmicro.Renode.Utilities;
11 using Antmicro.Renode.Utilities.Packets;
12 
13 namespace Antmicro.Renode.Core.CAN
14 {
15     public class CANMessageFrame
16     {
CANMessageFrame(uint id, byte[] data, bool extendedFormat = false, bool remoteFrame = false, bool fdFormat = false, bool bitRateSwitch = false)17         public CANMessageFrame(uint id, byte[] data, bool extendedFormat = false, bool remoteFrame = false, bool fdFormat = false, bool bitRateSwitch = false)
18         {
19             Id = id;
20             Data = data;
21             ExtendedFormat = extendedFormat;
22             RemoteFrame = remoteFrame;
23             FDFormat = fdFormat;
24             BitRateSwitch = bitRateSwitch;
25         }
26 
ToString()27         public override string ToString()
28         {
29             return $"[Message: Data={DataAsHex}, Remote={RemoteFrame}, Extended={ExtendedFormat}, BitRateSwitch={BitRateSwitch}, FDFormat={FDFormat}, Id={Id}, DataLength={Data.Length}]";
30         }
31 
ToSocketCAN(bool useNetworkByteOrder)32         public byte[] ToSocketCAN(bool useNetworkByteOrder)
33         {
34             if(!FDFormat)
35             {
36                 if(Data.Length > ClassicalSocketCANFrame.MaxDataLength)
37                 {
38                     throw new RecoverableException($"Classical frame cannot exceed {ClassicalSocketCANFrame.MaxDataLength} bytes of data");
39                 }
40                 return ClassicalSocketCANFrame.FromCANMessageFrame(this).Encode(useNetworkByteOrder);
41             }
42 
43             if(Data.Length > FlexibleSocketCANFrame.MaxDataLength)
44             {
45                 throw new RecoverableException($"FD frame cannot exceed {FlexibleSocketCANFrame.MaxDataLength} bytes of data");
46             }
47             return FlexibleSocketCANFrame.FromCANMessageFrame(this).Encode(useNetworkByteOrder);
48         }
49 
TryFromSocketCAN(ISocketCANFrame frame, out CANMessageFrame message)50         public static bool TryFromSocketCAN(ISocketCANFrame frame, out CANMessageFrame message)
51         {
52             message = default(CANMessageFrame);
53 
54             if(frame is ClassicalSocketCANFrame classicalFrame)
55             {
56                 if(classicalFrame.errorMessageFrame)
57                 {
58                     return false;
59                 }
60 
61                 message = new CANMessageFrame(
62                     id: classicalFrame.id,
63                     data: classicalFrame.data.CopyAndResize(classicalFrame.length),
64                     extendedFormat: classicalFrame.extendedFrameFormat,
65                     remoteFrame: classicalFrame.remoteTransmissionRequest,
66                     fdFormat: false,
67                     bitRateSwitch: false
68                 );
69                 return true;
70             }
71 
72             if(frame is FlexibleSocketCANFrame fdFrame)
73             {
74                 if(fdFrame.errorMessageFrame)
75                 {
76                     return false;
77                 }
78 
79                 message = new CANMessageFrame(
80                     id: fdFrame.id,
81                     data: fdFrame.data.CopyAndResize(fdFrame.length),
82                     extendedFormat: fdFrame.extendedFrameFormat,
83                     remoteFrame: fdFrame.remoteTransmissionRequest,
84                     fdFormat: true,
85                     bitRateSwitch: fdFrame.bitRateSwitch
86                 );
87                 return true;
88             }
89 
90             return false;
91         }
92 
TryFromSocketCAN(IList<byte> data, out CANMessageFrame message, out int bytesUsed, bool useNetworkByteOrder)93         public static bool TryFromSocketCAN(IList<byte> data, out CANMessageFrame message, out int bytesUsed, bool useNetworkByteOrder)
94         {
95             if(data.TryDecodeAsSocketCANFrame(out var frame, useNetworkByteOrder))
96             {
97                 bytesUsed = frame.Size;
98                 return TryFromSocketCAN(frame, out message);
99             }
100 
101             message = default(CANMessageFrame);
102             bytesUsed = 0;
103             return false;
104         }
105 
106         public string DataAsHex => Misc.PrettyPrintCollectionHex(Data);
107 
108         public uint Id { get; }
109         public byte[] Data { get; }
110         public bool ExtendedFormat { get; }
111         public bool RemoteFrame { get; }
112         public bool FDFormat { get; }
113         public bool BitRateSwitch { get; }
114     }
115 }
116