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