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 System.Linq; 10 using Antmicro.Renode.Utilities; 11 using Antmicro.Renode.Utilities.Packets; 12 13 namespace Antmicro.Renode.Core.CAN 14 { 15 public static class ISocketCANFrameExtentions 16 { 17 public static byte[] Encode<T>(this T @this, bool useNetworkByteOrder) where T : ISocketCANFrame 18 { 19 var frame = Packet.Encode<T>(@this); 20 if(useNetworkByteOrder) 21 { 22 @this.ByteSwap(frame); 23 } 24 return frame; 25 } 26 27 public static bool TryDecode<T>(this IList<byte> buffer, out T frame, bool useNetworkByteOrder) 28 where T : ISocketCANFrame 29 { 30 frame = default(T); 31 if(useNetworkByteOrder) 32 { 33 if(!buffer.TryGetByteSwappedData<T>(out var data)) 34 { 35 return false; 36 } 37 buffer = data; 38 } 39 40 return Packet.TryDecode<T>(buffer, out frame); 41 } 42 TryDecodeAsSocketCANFrame(this IList<byte> buffer, out ISocketCANFrame frame, bool useNetworkByteOrder)43 public static bool TryDecodeAsSocketCANFrame(this IList<byte> buffer, out ISocketCANFrame frame, bool useNetworkByteOrder) 44 { 45 if(!Packet.TryDecode<SocketCANFrameHeader>(buffer, out var header)) 46 { 47 frame = default(ISocketCANFrame); 48 return false; 49 } 50 51 if(header.extendedFrameLengthFrame) 52 { 53 return buffer.TryDecode<XLSocketCANFrame>(out frame, useNetworkByteOrder); 54 } 55 56 if(header.flexibleDataRateFrame) 57 { 58 return buffer.TryDecode<FlexibleSocketCANFrame>(out frame, useNetworkByteOrder); 59 } 60 61 return buffer.TryDecode<ClassicalSocketCANFrame>(out frame, useNetworkByteOrder); 62 } 63 64 public static bool TryGetByteSwappedData<T>(this IList<byte> buffer, out byte[] data) where T : ISocketCANFrame 65 { 66 var prototype = default(T); 67 if(buffer.Count < prototype.Size) 68 { 69 data = new byte[0]; 70 return false; 71 } 72 data = buffer.Take(prototype.Size).ToArray(); 73 prototype.ByteSwap(data); 74 return true; 75 } 76 ByteSwap(this ISocketCANFrame @this, byte[] frame)77 public static void ByteSwap(this ISocketCANFrame @this, byte[] frame) 78 { 79 if(frame.Length != @this.Size) 80 { 81 throw new ArgumentException($"Number of bytes in {nameof(frame)} must match the size of a SocketCAN structure", nameof(frame)); 82 } 83 foreach(var marker in @this.MultibyteFields) 84 { 85 Misc.EndiannessSwapInPlace(frame, marker.size, marker.offset, marker.size); 86 } 87 } 88 89 private static bool TryDecode<T>(this IList<byte> buffer, out ISocketCANFrame frame, bool useNetworkByteOrder) 90 where T : ISocketCANFrame 91 { 92 if(buffer.TryDecode<T>(out T tFrame, useNetworkByteOrder)) 93 { 94 frame = tFrame; 95 return true; 96 } 97 frame = default(ISocketCANFrame); 98 return false; 99 } 100 101 [LeastSignificantByteFirst] 102 private struct SocketCANFrameHeader 103 { 104 #pragma warning disable 649 105 [PacketField, Offset(doubleWords: 1, bytes: 1, bits: 2), Width(1)] 106 public bool flexibleDataRateFrame; 107 [PacketField, Offset(doubleWords: 1, bytes: 0, bits: 7), Width(1)] 108 public bool extendedFrameLengthFrame; 109 #pragma warning restore 649 110 111 public const int Size = 8; 112 } 113 } 114 115 public interface ISocketCANFrame 116 { 117 int Size { get; } 118 IEnumerable<FieldMarker> MultibyteFields { get; } 119 } 120 121 public struct FieldMarker 122 { CreateAntmicro.Renode.Core.CAN.FieldMarker123 public static FieldMarker Create(int size, int offset) => 124 new FieldMarker { size = size, offset = offset }; 125 126 public int size; 127 public int offset; 128 } 129 130 [LeastSignificantByteFirst] 131 public struct ClassicalSocketCANFrame : ISocketCANFrame 132 { FromCANMessageFrameAntmicro.Renode.Core.CAN.ClassicalSocketCANFrame133 public static ClassicalSocketCANFrame FromCANMessageFrame(CANMessageFrame msg) 134 { 135 return new ClassicalSocketCANFrame 136 { 137 id = msg.Id, 138 errorMessageFrame = false, 139 remoteTransmissionRequest = msg.RemoteFrame, 140 extendedFrameFormat = msg.ExtendedFormat, 141 length = msg.Data.Length, 142 data = msg.Data.CopyAndResize(MaxDataLength) 143 }; 144 } 145 ToStringAntmicro.Renode.Core.CAN.ClassicalSocketCANFrame146 public override string ToString() => $@"ClassicalSocketCANFrame {{ 147 id: 0x{id:X}, 148 errorMessageFrame: {errorMessageFrame}, 149 remoteTransmissionRequest: {remoteTransmissionRequest}, 150 extendedFrameFormat: {extendedFrameFormat}, 151 length: {length}, 152 data: {Misc.PrettyPrintCollectionHex(data)} 153 }}"; 154 155 public IEnumerable<FieldMarker> MultibyteFields => multibyteFields; 156 157 int ISocketCANFrame.Size => ClassicalSocketCANFrame.Size; 158 159 #pragma warning disable 649 160 // can_id 161 [PacketField, Offset(doubleWords: 0, bits: 0), Width(29)] 162 public uint id; 163 [PacketField, Offset(doubleWords: 0, bits: 29), Width(1)] 164 public bool errorMessageFrame; 165 [PacketField, Offset(doubleWords: 0, bits: 30), Width(1)] 166 public bool remoteTransmissionRequest; 167 [PacketField, Offset(doubleWords: 0, bits: 31), Width(1)] 168 public bool extendedFrameFormat; 169 170 // len 171 [PacketField, Offset(doubleWords: 1, bits: 0), Width(8)] 172 public int length; 173 174 // data 175 [PacketField, Offset(quadWords: 1), Width(MaxDataLength)] 176 public byte[] data; 177 #pragma warning restore 649 178 179 public const int MaxDataLength = 8; 180 public const int Size = MaxDataLength + 8; 181 182 private readonly static FieldMarker[] multibyteFields = new FieldMarker[] 183 { 184 FieldMarker.Create(size: 4, offset: 0) 185 }; 186 } 187 188 [LeastSignificantByteFirst] 189 public struct FlexibleSocketCANFrame : ISocketCANFrame 190 { FromCANMessageFrameAntmicro.Renode.Core.CAN.FlexibleSocketCANFrame191 public static FlexibleSocketCANFrame FromCANMessageFrame(CANMessageFrame msg) 192 { 193 return new FlexibleSocketCANFrame 194 { 195 id = msg.Id, 196 errorMessageFrame = false, 197 remoteTransmissionRequest = msg.RemoteFrame, 198 extendedFrameFormat = msg.ExtendedFormat, 199 length = msg.Data.Length, 200 bitRateSwitch = msg.BitRateSwitch, 201 errorStateIndicator = false, 202 flexibleDataRateFrame = true, 203 data = msg.Data.CopyAndResize(MaxDataLength) 204 }; 205 } 206 ToStringAntmicro.Renode.Core.CAN.FlexibleSocketCANFrame207 public override string ToString() => $@"FlexibleSocketCANFrame {{ 208 id: 0x{id:X}, 209 errorMessageFrame: {errorMessageFrame}, 210 remoteTransmissionRequest: {remoteTransmissionRequest}, 211 extendedFrameFormat: {extendedFrameFormat}, 212 length: {length}, 213 bitRateSwitch: {bitRateSwitch}, 214 errorStateIndicator: {errorStateIndicator}, 215 flexibleDataRateFrame: {flexibleDataRateFrame}, 216 data: {Misc.PrettyPrintCollectionHex(data)} 217 }}"; 218 219 public IEnumerable<FieldMarker> MultibyteFields => multibyteFields; 220 221 int ISocketCANFrame.Size => FlexibleSocketCANFrame.Size; 222 223 #pragma warning disable 649 224 // can_id 225 [PacketField, Offset(doubleWords: 0, bits: 0), Width(29)] 226 public uint id; 227 [PacketField, Offset(doubleWords: 0, bits: 29), Width(1)] 228 public bool errorMessageFrame; 229 [PacketField, Offset(doubleWords: 0, bits: 30), Width(1)] 230 public bool remoteTransmissionRequest; 231 [PacketField, Offset(doubleWords: 0, bits: 31), Width(1)] 232 public bool extendedFrameFormat; 233 234 // len 235 [PacketField, Offset(doubleWords: 1, bytes: 0), Width(8)] 236 public int length; 237 238 // flags 239 [PacketField, Offset(doubleWords: 1, bytes: 1, bits: 0), Width(1)] 240 public bool bitRateSwitch; 241 [PacketField, Offset(doubleWords: 1, bytes: 1, bits: 1), Width(1)] 242 public bool errorStateIndicator; 243 // should always be set for FD CAN frame 244 [PacketField, Offset(doubleWords: 1, bytes: 1, bits: 2), Width(1)] 245 public bool flexibleDataRateFrame; 246 247 // data 248 [PacketField, Offset(quadWords: 1), Width(MaxDataLength)] 249 public byte[] data; 250 #pragma warning restore 649 251 252 public const int MaxDataLength = 64; 253 public const int Size = MaxDataLength + 8; 254 255 private readonly static FieldMarker[] multibyteFields = new FieldMarker[] 256 { 257 FieldMarker.Create(size: 4, offset: 0) 258 }; 259 } 260 261 [LeastSignificantByteFirst] 262 public struct XLSocketCANFrame : ISocketCANFrame 263 { ToStringAntmicro.Renode.Core.CAN.XLSocketCANFrame264 public override string ToString() => $@"XLSocketCANFrame {{ 265 priority: 0x{priority:X}, 266 virtualCANNetworkId: 0x{virtualCANNetworkId:X}, 267 simpleExtendedContent: {simpleExtendedContent}, 268 extendedFrameLengthFrame: {extendedFrameLengthFrame}, 269 serviceDataUnit: 0x{serviceDataUnit:X}, 270 length: {length}, 271 acceptanceField: 0x{acceptanceField:X}, 272 data: {Misc.PrettyPrintCollectionHex(data)} 273 }}"; 274 275 public IEnumerable<FieldMarker> MultibyteFields => multibyteFields; 276 277 int ISocketCANFrame.Size => XLSocketCANFrame.Size; 278 279 #pragma warning disable 649 280 // prio 281 [PacketField, Offset(doubleWords: 0, bits: 0), Width(11)] 282 public uint priority; 283 [PacketField, Offset(doubleWords: 0, bits: 16), Width(8)] 284 public byte virtualCANNetworkId; 285 286 // flags 287 [PacketField, Offset(doubleWords: 1, bytes: 0, bits: 0), Width(1)] 288 public bool simpleExtendedContent; 289 [PacketField, Offset(doubleWords: 1, bytes: 0, bits: 7), Width(1)] 290 public bool extendedFrameLengthFrame; 291 292 // sdt 293 [PacketField, Offset(doubleWords: 1, bytes: 1, bits: 0), Width(8)] 294 public byte serviceDataUnit; 295 296 // len 297 [PacketField, Offset(doubleWords: 1, words: 1), Width(16)] 298 public int length; 299 300 // af 301 [PacketField, Offset(doubleWords: 2), Width(32)] 302 public uint acceptanceField; 303 304 // data 305 [PacketField, Offset(doubleWords: 3), Width(MaxDataLength)] 306 public byte[] data; 307 #pragma warning restore 649 308 309 public const int MaxDataLength = 2048; 310 public const int Size = MaxDataLength + 12; 311 312 private readonly static FieldMarker[] multibyteFields = new FieldMarker[] 313 { 314 FieldMarker.Create(size: 4, offset: 0), // prio 315 FieldMarker.Create(size: 2, offset: 6), // len 316 FieldMarker.Create(size: 4, offset: 8) // af 317 }; 318 } 319 } 320