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.Core.CAN;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 using Antmicro.Renode.Utilities.Packets;
15 
16 namespace Antmicro.Renode.Peripherals.CAN
17 {
18     public partial class S32K3XX_FlexCAN
19     {
PacketLengthToDataLengthCode(uint length)20         private static uint PacketLengthToDataLengthCode(uint length)
21         {
22             if(length <= 8)
23             {
24                 return (byte)length;
25             }
26 
27             switch(length)
28             {
29                 case 12:
30                     return 9;
31                 case 15:
32                     return 10;
33                 case 20:
34                     return 11;
35                 case 24:
36                     return 12;
37                 case 32:
38                     return 13;
39                 case 48:
40                     return 14;
41                 case 64:
42                     return 15;
43                 default:
44                     Logger.Log(LogLevel.Error, "{0} is invalid data length for CAN message", length);
45                     return 0;
46             }
47         }
48 
DataLengthCodeToPacketLength(uint dataLengthCode)49         private static uint DataLengthCodeToPacketLength(uint dataLengthCode)
50         {
51             switch(dataLengthCode)
52             {
53                 case 9:
54                     return 12;
55                 case 10:
56                     return 15;
57                 case 11:
58                     return 20;
59                 case 12:
60                     return 24;
61                 case 13:
62                     return 32;
63                 case 14:
64                     return 48;
65                 case 15:
66                     return 64;
67                 default:
68                     return dataLengthCode;
69             }
70         }
71 
72         private enum MessageBufferSize
73         {
74             _8bytes,
75             _16bytes,
76             _32bytes,
77             _64bytes
78         }
79 
80         private enum TxCode
81         {
82             Inactive,
83             Abort,
84             Data,
85             Remote,
86             TAnswer,
87         }
88 
89         private enum RxCode
90         {
91             Inactive,
92             Empty,
93             Full,
94             Overrun,
95             RAnswer,
96             Busy,
97         }
98 
99         private enum LegacyFilterFormat
100         {
101             A = 0b00, // One full ID (standard and extended) per ID filter table element
102             B = 0b01, // Two full standard IDs or two partial 14-bit (standard and extended) IDs per ID filter table element
103             C = 0b10, // Four partial 8-bit standard IDs per ID filter table element
104             D = 0b11, // All frames rejected
105         }
106 
107         private interface ILegacyRxFifoMatcher
108         {
IsMatching(CANMessageFrame frame)109             bool IsMatching(CANMessageFrame frame);
110         }
111 
112         private struct MessageBufferIteratorEntry
113         {
MessageBufferIteratorEntryAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferIteratorEntry114             public MessageBufferIteratorEntry(ulong offset, int region, MessageBufferStructure buffer)
115             {
116                 Offset = offset;
117                 Region = region;
118                 MessageBuffer = buffer;
119             }
120 
ToStringAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferIteratorEntry121             public override string ToString()
122             {
123                 return $@"{nameof(MessageBufferIteratorEntry)} {{
124     {nameof(Offset)}: 0x{Offset:X}
125     {nameof(Region)}: 0x{Region}
126     {nameof(MessageBuffer)}: {MessageBuffer}
127 }}";
128             }
129 
130             public ulong Offset { get; }
131             public int Region { get; }
132             public MessageBufferStructure MessageBuffer { get; }
133         }
134 
135 
136         private struct MessageBufferMatcher
137         {
MessageBufferMatcherAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferMatcher138             public MessageBufferMatcher(ulong mask)
139             {
140                 RawMask = mask;
141             }
142 
IsMatchingAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferMatcher143             public bool IsMatching(CANMessageFrame frame, MessageBufferStructure messageBuffer)
144             {
145                 if(MatchRTR && frame.RemoteFrame != messageBuffer.remoteTransmissionRequest)
146                 {
147                     return false;
148                 }
149 
150                 if(MatchIDE && frame.ExtendedFormat != messageBuffer.idExtendedBit)
151                 {
152                     return false;
153                 }
154 
155                 return (frame.Id & Mask) == (messageBuffer.Id & Mask);
156             }
157 
158             public ulong RawMask { get; }
159             public ulong Mask => RawMask & AddressMask;
160 
161             public bool MatchRTR => (RawMask & MatchRTRMask) > 0;
162             public bool MatchIDE => (RawMask & MatchIDEMask) > 0;
163 
164             private const ulong AddressMask = 0x3FFFFFFF;
165             private const ulong MatchRTRMask = 0x80000000;
166             private const ulong MatchIDEMask = 0x40000000;
167         }
168 
169         [LeastSignificantByteFirst]
170         private struct MessageBufferStructure
171         {
FetchMetadataAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure172             public static MessageBufferStructure FetchMetadata(IMultibyteWritePeripheral buffer, ulong offset)
173             {
174                 var data = buffer.ReadBytes((long)offset, (int)MetaSize);
175                 var structure = Packet.Decode<MessageBufferStructure>(data);
176                 return structure;
177             }
178 
ToStringAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure179             public override string ToString()
180             {
181                 return PrettyString;
182             }
183 
ToCANMessageFrameAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure184             public CANMessageFrame ToCANMessageFrame()
185             {
186                 return new CANMessageFrame(Id, Data.ToArray(), idExtendedBit, remoteTransmissionRequest, extendedDataLength, bitRateSwitch);
187             }
188 
FillReceivedFrameAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure189             public void FillReceivedFrame(IMultibyteWritePeripheral buffer, ulong offset, CANMessageFrame frame)
190             {
191                 Data = frame.Data;
192                 messageBufferCode = RxMessageCode != RxCode.Empty ? (byte)RxMessageBufferCode.Overrun : (byte)RxMessageBufferCode.Full;
193 
194                 var dataToBeWritten = Packet.Encode<MessageBufferStructure>(this);
195                 buffer.WriteBytes((long)offset, dataToBeWritten, 0, (int)MetaSize);
196                 buffer.WriteBytes((long)offset + MetaSize, data, 0, (int)data.Length);
197             }
198 
FetchDataAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure199             public void FetchData(IMultibyteWritePeripheral buffer, ulong offset)
200             {
201                 // NOTE: Data is stored in double words, therefore we have to make sure
202                 // we always use data length that is multiple of 4.
203                 data = buffer.ReadBytes((long)offset + MetaSize, (int)(DataLength + 3) & ~3);
204             }
205 
FinalizeAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.MessageBufferStructure206             public void Finalize(IMultibyteWritePeripheral buffer, ulong offset)
207             {
208                 switch(TxMessageCode)
209                 {
210                     case TxCode.Data:
211                         messageBufferCode = (byte)TxMessageBufferCode.Inactive;
212                         break;
213                     case TxCode.Remote:
214                         messageBufferCode = (byte)RxMessageBufferCode.Empty;
215                         break;
216                     case TxCode.TAnswer:
217                         messageBufferCode = (byte)RxMessageBufferCode.RAnswer;
218                         break;
219                     default:
220                         throw new Exception("Unreachable");
221                 }
222                 var data = Packet.Encode<MessageBufferStructure>(this);
223                 buffer.WriteBytes((long)offset, data, 0, (int)MetaSize);
224             }
225 
226             public string PrettyString => $@"{nameof(MessageBufferStructure)} {{
227     {nameof(timestamp)}: 0x{timestamp:X},
228     {nameof(dataLength)}: {dataLength},
229     {nameof(remoteTransmissionRequest)}: {remoteTransmissionRequest},
230     {nameof(idExtendedBit)}: {idExtendedBit},
231     {nameof(substituteRemoteRequest)}: {substituteRemoteRequest},
232     {nameof(messageBufferCode)}: {TxMessageCode?.ToString() ?? RxMessageCode.ToString()} (0x{messageBufferCode:X}),
233     {nameof(errorStateIndicator)}: {errorStateIndicator},
234     {nameof(bitRateSwitch)}: {bitRateSwitch},
235     {nameof(extendedDataLength)}: {extendedDataLength},
236     {nameof(extendedId)}: {extendedId},
237     {nameof(standardId)}: {standardId},
238     {nameof(localPriority)}: {localPriority},
239     {nameof(data)}: {DataString}
240 }}";
241 
242             public string DataString => data != null ? Misc.PrettyPrintCollectionHex(data) : "<data not fetched>";
243 
244             public RxCode? RxMessageCode
245             {
246                 get
247                 {
248                     if((messageBufferCode & 0b1) != 0)
249                     {
250                         return RxCode.Busy;
251                     }
252                     switch((RxMessageBufferCode)messageBufferCode)
253                     {
254                         case RxMessageBufferCode.Inactive:
255                             return RxCode.Inactive;
256                         case RxMessageBufferCode.Empty:
257                             return RxCode.Empty;
258                         case RxMessageBufferCode.Full:
259                             return RxCode.Full;
260                         case RxMessageBufferCode.Overrun:
261                             return RxCode.Overrun;
262                         case RxMessageBufferCode.RAnswer:
263                             return RxCode.RAnswer;
264                         default:
265                             return null;
266                     }
267                 }
268             }
269 
270             public TxCode? TxMessageCode
271             {
272                 get
273                 {
274                     switch((TxMessageBufferCode)messageBufferCode)
275                     {
276                         case TxMessageBufferCode.Inactive:
277                             return TxCode.Inactive;
278                         case TxMessageBufferCode.Abort:
279                             return TxCode.Abort;
280                         case TxMessageBufferCode.Data: // or TxMessageBufferCode.Remote
281                             return remoteTransmissionRequest ? TxCode.Remote : TxCode.Data;
282                         case TxMessageBufferCode.TAnswer:
283                             return TxCode.TAnswer;
284                         default:
285                             return null;
286                     }
287                 }
288             }
289 
290             // MB is ready for TX when code is set to Data or Remate (same code value)
291             public bool ReadyForTransmission => (TxMessageBufferCode)messageBufferCode == TxMessageBufferCode.Data;
292 
293             public bool ReadyForReception =>
294                 (RxMessageBufferCode)messageBufferCode == RxMessageBufferCode.Empty ||
295                 (RxMessageBufferCode)messageBufferCode == RxMessageBufferCode.Full ||
296                 (RxMessageBufferCode)messageBufferCode == RxMessageBufferCode.Overrun;
297 
298             public uint ExtendedId => standardId | extendedId << 11;
299             public uint StandardId => standardId;
300 
301             public uint Id => idExtendedBit ? ExtendedId : StandardId;
302 
303             public uint DataLength
304             {
305                 get => DataLengthCodeToPacketLength(dataLength);
306                 set => dataLength = (byte)PacketLengthToDataLengthCode(value);
307             }
308 
309             public uint Size => MetaSize + DataLength;
310 
311             public uint Priority => localPriority;
312 
313             public IEnumerable<byte> Data
314             {
315                 // NOTE: Data is send as big-endian double words, so we have to do conversion
316                 // before interpreting it as array of bytes
317                 get => data.Chunk(4).SelectMany(chunk => chunk.Reverse()).Take((int)DataLength);
318                 set
319                 {
320                     var length = value.Count();
321                     // NOTE: Data is stored in double words, therefore we have to make sure
322                     // we always use data length that is multiple of 4.
323                     var properLength = (length + 3) & ~3;
324                     data = Enumerable.Concat(value, Enumerable.Repeat((byte)0, properLength - length))
325                         .Chunk(4)
326                         .SelectMany(chunk => chunk.Reverse())
327                         .ToArray();
328                     DataLength = (uint)length;
329                 }
330             }
331 
332 #pragma warning disable 649
333             [PacketField, Offset(doubleWords: 0, bits:  0), Width(16)] // TIMESTAMP
334             public ushort timestamp; // Free-Running Counter Timestamp
335             [PacketField, Offset(doubleWords: 0, bits: 16), Width( 4)] // DLC
336             public byte dataLength; // Length of Data in Bytes
337             [PacketField, Offset(doubleWords: 0, bits: 20), Width( 1)] // RTR
338             public bool remoteTransmissionRequest;
339             [PacketField, Offset(doubleWords: 0, bits: 21), Width( 1)] // IDE
340             public bool idExtendedBit;
341             [PacketField, Offset(doubleWords: 0, bits: 22), Width( 1)] // SRR
342             public bool substituteRemoteRequest;
343             // bit 23 of 1st double word is reserved
344             [PacketField, Offset(doubleWords: 0, bits: 24), Width( 4)] // CODE
345             public byte messageBufferCode;
346             // bit 28 of 1st double word is reserved
347             [PacketField, Offset(doubleWords: 0, bits: 29), Width( 1)] // ESI
348             public bool errorStateIndicator;
349             [PacketField, Offset(doubleWords: 0, bits: 30), Width( 1)] // BRS
350             public bool bitRateSwitch;
351             [PacketField, Offset(doubleWords: 0, bits: 31), Width( 1)] // EDL
352             public bool extendedDataLength;
353             [PacketField, Offset(doubleWords: 1, bits:  0), Width(18)] // ID (extended)
354             public uint extendedId;
355             [PacketField, Offset(doubleWords: 1, bits: 18), Width(11)] // ID (standard/extended)
356             public uint standardId;
357             [PacketField, Offset(doubleWords: 1, bits: 29), Width( 3)] // PRIO
358             public byte localPriority;
359 #pragma warning restore 649
360             public byte[] data;
361 
362             public const uint MetaSize = 0x8;
363         }
364 
365         private enum RxMessageBufferCode : byte
366         {
367             Inactive = 0b0000,
368             Empty    = 0b0100,
369             Full     = 0b0010,
370             Overrun  = 0b0110,
371             RAnswer  = 0b1010,
372             Busy     = 0b0001, // 0bxxx1
373         }
374 
375         private enum TxMessageBufferCode : byte
376         {
377             Inactive = 0b1000,
378             Abort    = 0b1001,
379             Data     = 0b1100, // RTR = 0
380             Remote   = 0b1100, // RTR = 1
381             TAnswer  = 0b1110,
382         }
383 
384         [LeastSignificantByteFirst]
385         private struct LegacyRxFifoStructure
386         {
FromCANFrameAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoStructure387             public static LegacyRxFifoStructure FromCANFrame(CANMessageFrame frame, int filterIndex)
388             {
389                 var @this = new LegacyRxFifoStructure();
390 
391                 @this.DataLength = (uint)frame.Data.Length;
392                 @this.remoteFrame = frame.RemoteFrame;
393                 @this.extendedFrame = frame.ExtendedFormat;
394                 @this.identifierAcceptanceFilterHitIndicator = (ushort)filterIndex;
395                 if(frame.ExtendedFormat)
396                 {
397                     @this.extendedId = frame.Id;
398                 }
399                 else
400                 {
401                     @this.standardId = frame.Id;
402                 }
403                 @this.data = frame.Data.ToArray();
404                 return @this;
405             }
406 
CommitToMemoryAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoStructure407             public void CommitToMemory(IMultibyteWritePeripheral buffer, uint offset)
408             {
409                 var dataToBeWritten = Packet.Encode<LegacyRxFifoStructure>(this);
410                 buffer.WriteBytes((long)offset, dataToBeWritten, 0, (int)MetaSize);
411                 buffer.WriteBytes((long)offset + MetaSize, data, 0, (int)data.Length);
412             }
413 
ToStringAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoStructure414             public override string ToString()
415             {
416                 return PrettyString;
417             }
418 
419             public uint DataLength
420             {
421                 get => DataLengthCodeToPacketLength(dataLength);
422                 set => dataLength = (byte)PacketLengthToDataLengthCode(value);
423             }
424 
425             // NOTE: Data is send as big-endian double words, so we have to do conversion
426             // before interpreting it as array of bytes
427             public IEnumerable<byte> Data
428             {
429                 get => data.Chunk(4).SelectMany(chunk => chunk.Reverse()).Take((int)DataLength);
430                 set
431                 {
432                     var length = value.Count();
433                     // NOTE: Data is stored in double words, therefore we have to make sure
434                     // we always use data length that is multiple of 4.
435                     var properLength = (length + 3) & ~3;
436                     data = Enumerable.Concat(value, Enumerable.Repeat((byte)0, properLength - length))
437                         .Chunk(4)
438                         .SelectMany(chunk => chunk.Reverse())
439                         .ToArray();
440                     DataLength = (uint)length;
441                 }
442             }
443 
444             public string PrettyString => $@"{nameof(LegacyRxFifoStructure)} {{
445     {nameof(timestamp)}: 0x{timestamp:X},
446     {nameof(dataLength)}: {dataLength},
447     {nameof(remoteFrame)}: {remoteFrame},
448     {nameof(extendedFrame)}: {extendedFrame},
449     {nameof(substituteRemoteRequest)}: {substituteRemoteRequest},
450     {nameof(identifierAcceptanceFilterHitIndicator)}: {identifierAcceptanceFilterHitIndicator},
451     {nameof(extendedId)}: {extendedId},
452     {nameof(standardId)}: {standardId},
453     {nameof(data)}: {Misc.PrettyPrintCollectionHex(data)}
454 }}";
455 
456 #pragma warning disable 649
457             [PacketField, Offset(doubleWords: 0, bits:  0), Width(16)] // TIMESTAMP
458             public ushort timestamp; // Free-Running Counter Timestamp
459             [PacketField, Offset(doubleWords: 0, bits: 16), Width( 4)] // DLC
460             public byte dataLength; // Length of Data in Bytes
461             [PacketField, Offset(doubleWords: 0, bits: 20), Width( 1)] // RTR
462             public bool remoteFrame;
463             [PacketField, Offset(doubleWords: 0, bits: 21), Width( 1)] // IDE
464             public bool extendedFrame;
465             [PacketField, Offset(doubleWords: 0, bits: 22), Width( 1)] // SRR
466             public bool substituteRemoteRequest;
467             [PacketField, Offset(doubleWords: 0, bits: 23), Width( 9)] // IDHIT
468             public ushort identifierAcceptanceFilterHitIndicator;
469             [PacketField, Offset(doubleWords: 1, bits:  0), Width(18)] // ID (extended)
470             public uint extendedId;
471             [PacketField, Offset(doubleWords: 1, bits: 18), Width(11)] // ID (standard/extended)
472             public uint standardId;
473             // bits 29:31 of 2nd double word are reserved
474             [PacketField, Offset(doubleWords: 2), Width(8)] // Data bytes
475             public byte[] data;
476             // double words from 4th to 23th are reserved
477             // There is a table of ID filters with 128 double words elements starting at 24th
478 #pragma warning restore 649
479 
480             public const uint MetaSize = 0x8;
481         }
482 
483         [LeastSignificantByteFirst]
484         private struct LegacyRxFifoFilterAStructure : ILegacyRxFifoMatcher
485         {
FetchAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoFilterAStructure486             public static LegacyRxFifoFilterAStructure Fetch(IMultibyteWritePeripheral buffer, int offset)
487             {
488                 var data = buffer.ReadBytes((long)offset, 4);
489                 var structure = Packet.Decode<LegacyRxFifoFilterAStructure>(data);
490                 return structure;
491             }
492 
493             public bool IsMatching(CANMessageFrame frame) =>
494                 frame.ExtendedFormat == idExtendedBit &&
495                 frame.RemoteFrame == remoteTransmissionRequest &&
496                 (idExtendedBit ? rxFrameIdentifier == frame.Id : (rxFrameIdentifier >> 17) == frame.Id)
497             ;
498 
499 #pragma warning disable 649
500             [PacketField, Offset(bits:  1), Width(28)]
501             public uint rxFrameIdentifier;
502             [PacketField, Offset(bits: 30), Width( 1)]
503             public bool idExtendedBit;
504             [PacketField, Offset(bits: 31), Width( 1)]
505             public bool remoteTransmissionRequest;
506 #pragma warning restore 649
507         }
508 
509         [LeastSignificantByteFirst]
510         private struct LegacyRxFifoFilterBStructure : ILegacyRxFifoMatcher
511         {
FetchAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoFilterBStructure512             public static LegacyRxFifoFilterBStructure Fetch(IMultibyteWritePeripheral buffer, int offset)
513             {
514                 var data = buffer.ReadBytes((long)offset, 4);
515                 var structure = Packet.Decode<LegacyRxFifoFilterBStructure>(data);
516                 return structure;
517             }
518 
519             public bool IsMatching(CANMessageFrame frame) =>
520                 (frame.ExtendedFormat == idExtendedBit0 &&
521                  frame.RemoteFrame == remoteTransmissionRequest0 &&
522                  (idExtendedBit0 ? rxFrameIdentifier0 == frame.Id : (rxFrameIdentifier0 >> 3) == frame.Id)) ||
523                 (frame.ExtendedFormat == idExtendedBit1 &&
524                  frame.RemoteFrame == remoteTransmissionRequest1 &&
525                  (idExtendedBit1 ? rxFrameIdentifier1 == frame.Id : (rxFrameIdentifier1 >> 3) == frame.Id))
526             ;
527 
528 #pragma warning disable 649
529             [PacketField, Offset(bits:  0), Width(14)]
530             public uint rxFrameIdentifier1;
531             [PacketField, Offset(bits: 14), Width( 1)]
532             public bool idExtendedBit1;
533             [PacketField, Offset(bits: 15), Width( 1)]
534             public bool remoteTransmissionRequest1;
535             [PacketField, Offset(bits: 16), Width(14)]
536             public uint rxFrameIdentifier0;
537             [PacketField, Offset(bits: 30), Width( 1)]
538             public bool idExtendedBit0;
539             [PacketField, Offset(bits: 31), Width( 1)]
540             public bool remoteTransmissionRequest0;
541 #pragma warning restore 649
542         }
543 
544         [LeastSignificantByteFirst]
545         private struct LegacyRxFifoFilterCStructure : ILegacyRxFifoMatcher
546         {
FetchAntmicro.Renode.Peripherals.CAN.S32K3XX_FlexCAN.LegacyRxFifoFilterCStructure547             public static LegacyRxFifoFilterCStructure Fetch(IMultibyteWritePeripheral buffer, int offset)
548             {
549                 var data = buffer.ReadBytes((long)offset, 4);
550                 var structure = Packet.Decode<LegacyRxFifoFilterCStructure>(data);
551                 return structure;
552             }
553 
554             public bool IsMatching(CANMessageFrame frame) =>
555                 frame.Id == rxFrameIdentifier0 ||
556                 frame.Id == rxFrameIdentifier1 ||
557                 frame.Id == rxFrameIdentifier2 ||
558                 frame.Id == rxFrameIdentifier3
559             ;
560 
561 #pragma warning disable 649
562             [PacketField, Offset(bits:  0), Width(8)]
563             public uint rxFrameIdentifier3;
564             [PacketField, Offset(bits:  8), Width(8)]
565             public uint rxFrameIdentifier2;
566             [PacketField, Offset(bits: 16), Width(8)]
567             public uint rxFrameIdentifier1;
568             [PacketField, Offset(bits: 24), Width(8)]
569             public uint rxFrameIdentifier0;
570 #pragma warning restore 649
571         }
572     }
573 }
574