1 //
2 // Copyright (c) 2010-2023 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.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.CAN;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Utilities;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.Memory;
17 using Antmicro.Renode.Hooks;
18 using Antmicro.Renode.Utilities.Packets;
19 using Antmicro.Renode.Time;
20 
21 namespace Antmicro.Renode.Peripherals.CAN
22 {
23     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
24     public partial class MCAN : IDoubleWordPeripheral, IKnownSize, ICAN
25     {
MCAN(IMachine machine, IMultibyteWritePeripheral messageRAM)26         public MCAN(IMachine machine, IMultibyteWritePeripheral messageRAM)
27         {
28             this.machine = machine;
29             this.messageRAM = messageRAM;
30             Line0 = new GPIO();
31             Line1 = new GPIO();
32             Calibration = new GPIO();
33             BuildRegisterMapView();
34             registers = new DoubleWordRegisterCollection(this, BuildRegisterMap());
35             BuildStructuredViews();
36             UpdateInterrupts();
37         }
38 
OnFrameReceived(CANMessageFrame rxMessage)39         public void OnFrameReceived(CANMessageFrame rxMessage)
40         {
41             HandleRxInner(rxMessage);
42             UpdateInterrupts();
43         }
44 
Reset()45         public void Reset()
46         {
47             registers.Reset();
48         }
49 
ReadDoubleWord(long offset)50         public uint ReadDoubleWord(long offset)
51         {
52             return registers.Read(offset);
53         }
54 
WriteDoubleWord(long offset, uint value)55         public void WriteDoubleWord(long offset, uint value)
56         {
57             registers.Write(offset, value);
58         }
59 
BuildRegisterMap()60         private Dictionary<long, DoubleWordRegister> BuildRegisterMap()
61         {
62             var registerMap = new Dictionary<long, DoubleWordRegister>();
63 
64             registerMap[(long)Register.CoreReleaseRegister] = new DoubleWordRegister(this, resetValue: 0x33191121)
65                 .WithTag("DAY", 0, 8)
66                 .WithTag("MON", 8, 8)
67                 .WithTag("YEAR", 16, 4)
68                 .WithTag("SUBSTEP", 20, 4)
69                 .WithTag("STEP", 24, 4)
70                 .WithTag("REL", 28, 4);
71 
72             registerMap[(long)Register.EndianRegister] = new DoubleWordRegister(this, resetValue: 0x87654321)
73                 .WithTag("ETV", 0, 32);
74 
75             registerMap[(long)Register.CustomerRegister] = new DoubleWordRegister(this)
76                 .WithReservedBits(0, 32);
77 
78             registerMap[(long)Register.DataBitTimingAndPrescalerRegister] = new DoubleWordRegister(this, resetValue: 0x00000A33)
79                 .WithTag("DSJW", 0, 4)
80                 .WithTag("DTSEG", 4, 4)
81                 .WithTag("DTSEG1", 8, 5)
82                 .WithReservedBits(13, 3)
83                 .WithTag("DBRP", 16, 5)
84                 .WithReservedBits(21, 2)
85                 .WithTaggedFlag("TDC", 23)
86                 .WithReservedBits(24, 8);
87 
88             registerMap[(long)Register.TestRegister] = new DoubleWordRegister(this)
89                 .WithReservedBits(0, 4)
90                 .WithFlag(4, out rv.TestRegister.LoopBackMode, writeCallback: (oldVal, newVal) =>
91                 {
92                     if(!IsProtectedWrite && newVal != oldVal)
93                     {
94                         this.Log(LogLevel.Warning, "Trying to write to protected field. Ignoring.");
95                         rv.TestRegister.LoopBackMode.Value = oldVal;
96                         return;
97                     }
98                 }, name: "LBCK")
99                 .WithTag("TX", 5, 2)
100                 .WithTaggedFlag("RX", 7)
101                 .WithValueField(8, 5, out rv.TestRegister.TxBufferNumberPrepared, FieldMode.Read, name: "TXBNP")
102                 .WithFlag(13, out rv.TestRegister.PreparedValid, FieldMode.Read, name: "PVAL")
103                 .WithReservedBits(14, 2)
104                 .WithValueField(16, 5, out rv.TestRegister.TxBufferNumberStarted, FieldMode.Read, name: "TXBNS")
105                 .WithFlag(21, out rv.TestRegister.StartedValid, FieldMode.Read, name: "SVAL")
106                 .WithReservedBits(22, 10);
107 
108             registerMap[(long)Register.RAMWatchdog] = new DoubleWordRegister(this)
109                 .WithTag("WDC", 0, 8)
110                 .WithTag("WDV", 8, 8)
111                 .WithReservedBits(16, 16);
112 
113             registerMap[(long)Register.CCControlRegister] = new DoubleWordRegister(this, resetValue: 0x1)
114                 .WithFlags(0, 16, out rv.CCControlRegister.ControlFields, writeCallback: (idx, oldVal, newVal) =>
115                 {
116                     // Handle fields that have meaningful side effects from the point of emulation. Other fields are treated as flags.
117                     switch((Control)idx)
118                     {
119                         case Control.Initialization:
120                         {
121                             if(!newVal)
122                             {
123                                 rv.CCControlRegister.ControlFields[(int)Control.ConfigurationChangeEnable].Value = false;
124                                 this.Log(LogLevel.Debug, "Software initialization is finished");
125                             }
126                             break;
127                         }
128                         case Control.ConfigurationChangeEnable:
129                         {
130                             if(!rv.CCControlRegister.ControlFields[(int)Control.Initialization].Value && rv.CCControlRegister.ControlFields[(int)Control.ConfigurationChangeEnable].Value) // oldVal was reset through resetting INIT
131                             {
132                                 rv.CCControlRegister.ControlFields[idx].Value = oldVal;
133                                 return;
134                             }
135                             if(newVal)
136                             {
137                                 registerMap[(long)Register.HighPriorityMessageStatus].Reset();
138                                 registerMap[(long)Register.RxFIFO0Status].Reset();
139                                 registerMap[(long)Register.RxFIFO1Status].Reset();
140                                 registerMap[(long)Register.TxFIFOQueueStatus].Reset();
141                                 registerMap[(long)Register.TxBufferRequestPending].Reset();
142                                 registerMap[(long)Register.TxBufferTransmissionOccurred].Reset();
143                                 registerMap[(long)Register.TxBufferCancellationFinished].Reset();
144                                 registerMap[(long)Register.TxEventFIFOStatus].Reset();
145                             }
146                             break;
147                         }
148                         case Control.BusMonitoringMode:
149                         case Control.TestModeEnable:
150                         {
151                             if(newVal)
152                             {
153                                 if(!IsProtectedWrite && newVal != oldVal)
154                                 {
155                                     this.Log(LogLevel.Warning, "Trying to write to protected field. Ignoring.");
156                                     rv.CCControlRegister.ControlFields[idx].Value = oldVal;
157                                     return;
158                                 }
159                             }
160                             else
161                             {
162                                 if((Control)idx == Control.TestModeEnable)
163                                 {
164                                     registerMap[(long)Register.TestRegister].Reset();
165                                 }
166                             }
167                             break;
168                         }
169                         case Control.DisableAutomaticRetransmission:
170                         {
171                             if(!IsProtectedWrite && newVal != oldVal)
172                             {
173                                 this.Log(LogLevel.Warning, "Trying to write to protected field. Ignoring.");
174                                 rv.CCControlRegister.ControlFields[idx].Value = oldVal;
175                                 return;
176                             }
177                             break;
178                         }
179                     }
180                 })
181                 .WithReservedBits(16, 16);
182 
183             registerMap[(long)Register.NominalBitTimingAndPrescalerRegister] = new DoubleWordRegister(this, resetValue: 0x06000A03)
184                 .WithTag("NTSEG2", 0, 7)
185                 .WithReservedBits(7, 1)
186                 .WithTag("NTSEG1", 8, 8)
187                 .WithTag("NBRP", 16, 9)
188                 .WithTag("NSJW", 25, 7);
189 
190             registerMap[(long)Register.TimestampCounterConfiguration] = new DoubleWordRegister(this)
191                 .WithTag("TSS", 0, 2)
192                 .WithReservedBits(2, 14)
193                 .WithTag("TCP", 16, 4)
194                 .WithReservedBits(20, 12);
195 
196             registerMap[(long)Register.TimestampCounterValue] = new DoubleWordRegister(this)
197                 .WithTag("TSC", 0, 16)
198                 .WithReservedBits(16, 16);
199 
200             registerMap[(long)Register.TimeoutCounterConfiguration] = new DoubleWordRegister(this, resetValue: 0xFFFF0000)
201                 .WithTaggedFlag("ETOC", 0)
202                 .WithTag("TOS", 1, 2)
203                 .WithReservedBits(3, 13)
204                 .WithTag("TOP", 16, 16);
205 
206             registerMap[(long)Register.TimeoutCounterValue] = new DoubleWordRegister(this, resetValue: 0x0000FFFF)
207                 .WithTag("TOC", 0, 16)
208                 .WithReservedBits(16, 16);
209 
210             registerMap[(long)Register.ErrorCounterRegister] = new DoubleWordRegister(this)
211                 .WithTag("TEC", 0, 8)
212                 .WithTag("REC", 8, 7)
213                 .WithTaggedFlag("RP", 15)
214                 .WithTag("CEL", 16, 8)
215                 .WithReservedBits(24, 8);
216 
217             registerMap[(long)Register.ProtocolStatusRegister] = new DoubleWordRegister(this, resetValue: 0x00000707)
218                 .WithEnumField(0, 3, out rv.ProtocolStatusRegister.LastErrorCode, readCallback: (_, __) =>
219                 {
220                     rv.ProtocolStatusRegister.LastErrorCode.Value = LastErrorCode.NoChange; // Reset on read
221                 }, name: "LEC")
222                 .WithEnumField(3, 2, out rv.ProtocolStatusRegister.Activity, name: "ACT")
223                 .WithTaggedFlag("EP", 5)
224                 .WithTaggedFlag("EW", 6)
225                 .WithTaggedFlag("BO", 7)
226                 .WithTag("DLEC", 8, 3)
227                 .WithTaggedFlag("RESI", 11)
228                 .WithTaggedFlag("RBRS", 12)
229                 .WithFlag(13, out rv.ProtocolStatusRegister.ReceivedCANFDMessage, readCallback: (_, __) =>
230                 {
231                     rv.ProtocolStatusRegister.ReceivedCANFDMessage.Value = false; // Reset on read
232                 }, name: "RFDF")
233                 .WithTaggedFlag("PXE", 14)
234                 .WithReservedBits(15, 1)
235                 .WithTag("TDCV", 16, 7)
236                 .WithReservedBits(23, 9);
237 
238             registerMap[(long)Register.TransmitterDelayCompensationRegister] = new DoubleWordRegister(this)
239                 .WithTag("TDCF", 0, 7)
240                 .WithReservedBits(7, 1)
241                 .WithTag("TDCO", 8, 7)
242                 .WithReservedBits(15, 17);
243 
244             registerMap[(long)Register.InterruptRegister] = new DoubleWordRegister(this)
245                 .WithFlags(0, 30, out rv.InterruptRegister.InterruptFlags, FieldMode.Read | FieldMode.WriteOneToClear, writeCallback: (idx, oldVal, newVal) =>
246                 {
247                     if(!newVal)
248                     {
249                         return;
250                     }
251 
252                     switch((Interrupt)idx)
253                     {
254                         case Interrupt.RxFIFO0MessageLost:
255                         {
256                             rxFIFO0.MessageLost.Value = false;
257                             break;
258                         }
259                         case Interrupt.RxFIFO1MessageLost:
260                         {
261                             rxFIFO1.MessageLost.Value = false;
262                             break;
263                         }
264                         case Interrupt.TxEventFIFOElementLost:
265                         {
266                             txEventFIFO.ElementLost.Value = false;
267                             break;
268                         }
269                     }
270                 })
271                 .WithWriteCallback((_, __) => UpdateInterrupts());
272 
273             registerMap[(long)Register.InterruptEnable] = new DoubleWordRegister(this)
274                 .WithFlags(0, 30, out rv.InterruptEnable.InterruptEnableFlags)
275                 .WithWriteCallback((_, __) => UpdateInterrupts());
276 
277             registerMap[(long)Register.InterruptLineSelect] = new DoubleWordRegister(this)
278                 .WithFlags(0, 30, out rv.InterruptLineSelect.InterruptLineSelectFlags)
279                 .WithWriteCallback((_, __) => UpdateInterrupts());
280 
281             registerMap[(long)Register.InterruptLineEnable] = new DoubleWordRegister(this)
282                 .WithFlag(0, out rv.InterruptLineEnable.EnableInterruptLine0, name: "EINT0")
283                 .WithFlag(1, out rv.InterruptLineEnable.EnableInterruptLine1, name: "EINT1")
284                 .WithWriteCallback((_, __) => UpdateInterrupts());
285 
286             registerMap[(long)Register.GlobalFilterConfiguration] = new DoubleWordRegister(this)
287                 .WithFlag(0, out rv.GlobalFilterConfiguration.RejectRemoteFramesExtended, name: "RRFE")
288                 .WithFlag(1, out rv.GlobalFilterConfiguration.RejectRemoteFramesStandard, name: "RRFS")
289                 .WithEnumField(2, 2, out rv.GlobalFilterConfiguration.AcceptNonMatchingFramesExtended, name: "ANFE")
290                 .WithEnumField(4, 2, out rv.GlobalFilterConfiguration.AcceptNonMatchingFramesStandard, name: "ANFS");
291 
292             registerMap[(long)Register.StandardIDFilterConfiguration] = new DoubleWordRegister(this)
293                 .WithReservedBits(0, 2)
294                 .WithValueField(2, 14, out rv.StandardIDFilterConfiguration.FilterListStandardStartAddress, name: "FLSSA")
295                 .WithValueField(16, 8, out rv.StandardIDFilterConfiguration.ListSizeStandard, name: "LSS")
296                 .WithReservedBits(24, 8);
297 
298             registerMap[(long)Register.ExtendedIDFilterConfiguration] = new DoubleWordRegister(this)
299                 .WithReservedBits(0, 2)
300                 .WithValueField(2, 14, out rv.ExtendedIDFilterConfiguration.FilterListExtendedStartAddress, name: "FLESA")
301                 .WithValueField(16, 7, out rv.ExtendedIDFilterConfiguration.ListSizeExtended, name: "LSE")
302                 .WithReservedBits(23, 9);
303 
304             registerMap[(long)Register.ExtendedIdANDMask] = new DoubleWordRegister(this, resetValue: 0x1FFFFFFF)
305                 .WithValueField(0, 29, out rv.ExtendedIdANDMask.ExtendedIDANDMask, name: "EIDM")
306                 .WithReservedBits(29, 3);
307 
308             registerMap[(long)Register.HighPriorityMessageStatus] = new DoubleWordRegister(this)
309                 .WithValueField(0, 6, valueField: out rv.HighPriorityMessageStatus.BufferIndex, name: "BIDX")
310                 .WithEnumField(6, 2, out rv.HighPriorityMessageStatus.MessageStorageIndicator, name: "MSI")
311                 .WithValueField(8, 7, out rv.HighPriorityMessageStatus.FilterIndex, name: "FIDX")
312                 .WithFlag(15, out rv.HighPriorityMessageStatus.FilterList, name: "FLST")
313                 .WithReservedBits(16, 16);
314 
315             registerMap[(long)Register.NewData1] = new DoubleWordRegister(this)
316                 .WithFlags(0, 32, out rv.NewData1.NewData1Flags, FieldMode.Read | FieldMode.WriteOneToClear, name: "newData1x");
317 
318             registerMap[(long)Register.NewData2] = new DoubleWordRegister(this)
319                 .WithFlags(0, 32, out rv.NewData2.NewData2Flags, FieldMode.Read | FieldMode.WriteOneToClear, name: "newData2x");
320 
321             registerMap[(long)Register.RxFIFO0Configuration] = new DoubleWordRegister(this)
322                 .WithReservedBits(0, 2)
323                 .WithValueField(2, 14, out rv.RxFIFO0Configuration.RxFIFO0StartAddress, name: "F0SA")
324                 .WithValueField(16, 7, out rv.RxFIFO0Configuration.RxFIFO0Size, name: "F0S")
325                 .WithReservedBits(23, 1)
326                 .WithValueField(24, 7, out rv.RxFIFO0Configuration.RxFIFO0Watermark, name: "F0WM")
327                 .WithEnumField(31, 1, out rv.RxFIFO0Configuration.FIFO0OperationMode, name: "F0OM");
328 
329             registerMap[(long)Register.RxFIFO0Status] = new DoubleWordRegister(this)
330                 .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: _ => rxFIFO0.RxFIFOFillLevel, name: "F0FL")
331                 .WithReservedBits(7, 1)
332                 .WithValueField(8, 6, out rv.RxFIFO0Status.RxFIFO0GetIndex, FieldMode.Read, name: "F0GI")
333                 .WithReservedBits(14, 2)
334                 .WithValueField(16, 6, out rv.RxFIFO0Status.RxFIFO0PutIndex, FieldMode.Read, name: "F0PI")
335                 .WithReservedBits(22, 2)
336                 .WithFlag(24, out rv.RxFIFO0Status.RxFIFO0Full, FieldMode.Read, name: "F0F")
337                 .WithFlag(25, out rv.RxFIFO0Status.RxFIFO0MessageLost, FieldMode.Read, name: "RF0L")
338                 .WithReservedBits(26, 6);
339 
340             registerMap[(long)Register.RxFIFO0Acknowledge] = new DoubleWordRegister(this)
341                 .WithValueField(0, 6, out rv.RxFIFO0Acknowledge.RxFIFO0AcknowledgeIndex, writeCallback: (_, newVal) =>
342                 {
343                     rxFIFO0.RxFIFOGetIndex = newVal + 1;
344                     rxFIFO0.Full.Value = false;
345                 }, name: "F0AI")
346                 .WithReservedBits(6, 26);
347 
348             registerMap[(long)Register.RxBufferConfiguration] = new DoubleWordRegister(this)
349                 .WithReservedBits(0, 2)
350                 .WithValueField(2, 14, out rv.RxBufferConfiguration.RxBufferStartAddress, name: "RBSA")
351                 .WithReservedBits(16, 16);
352 
353             registerMap[(long)Register.RxFIFO1Configuration] = new DoubleWordRegister(this)
354                 .WithReservedBits(0, 2)
355                 .WithValueField(2, 14, out rv.RxFIFO1Configuration.RxFIFO1StartAddress, name: "F1SA")
356                 .WithValueField(16, 7, out rv.RxFIFO1Configuration.RxFIFO1Size, name: "F1S")
357                 .WithReservedBits(23, 1)
358                 .WithValueField(24, 7, out rv.RxFIFO1Configuration.RxFIFO1Watermark, name: "F1WM")
359                 .WithEnumField(31, 1, out rv.RxFIFO1Configuration.FIFO1OperationMode, name: "F1OM");
360 
361             registerMap[(long)Register.RxFIFO1Status] = new DoubleWordRegister(this)
362                 .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: _ => rxFIFO1.RxFIFOFillLevel, name: "F0FL")
363                 .WithReservedBits(7, 1)
364                 .WithValueField(8, 6, out rv.RxFIFO1Status.RxFIFO1GetIndex, FieldMode.Read, name: "F0GI")
365                 .WithReservedBits(14, 2)
366                 .WithValueField(16, 6, out rv.RxFIFO1Status.RxFIFO1PutIndex, FieldMode.Read, name: "F0PI")
367                 .WithReservedBits(22, 2)
368                 .WithFlag(24, out rv.RxFIFO1Status.RxFIFO1Full, FieldMode.Read, name: "F0F")
369                 .WithFlag(25, out rv.RxFIFO1Status.RxFIFO1MessageLost, FieldMode.Read, name: "RF0L")
370                 .WithReservedBits(26, 4)
371                 .WithEnumField(30, 2, out rv.RxFIFO1Status.DebugMessageStatus, FieldMode.Read, name: "DMS");
372 
373             registerMap[(long)Register.RxFIFO1Acknowledge] = new DoubleWordRegister(this)
374                 .WithValueField(0, 6, out rv.RxFIFO1Acknowledge.RxFIFO1AcknowledgeIndex, writeCallback: (_, newVal) =>
375                 {
376                     rxFIFO1.RxFIFOGetIndex = newVal + 1;
377                     rxFIFO1.Full.Value = false;
378                 }, name: "F1AI")
379                 .WithReservedBits(6, 26);
380 
381             registerMap[(long)Register.RxBufferFIFOElementSizeConfiguration] = new DoubleWordRegister(this)
382                 .WithValueField(0, 3, out rv.RxBufferFIFOElementSizeConfiguration.RxFIFO0DataFieldSize, name: "F0DS")
383                 .WithReservedBits(3, 1)
384                 .WithValueField(4, 3, out rv.RxBufferFIFOElementSizeConfiguration.RxFIFO1DataFieldSize, name: "F1DS")
385                 .WithReservedBits(7, 1)
386                 .WithValueField(8, 3, out rv.RxBufferFIFOElementSizeConfiguration.RxBufferDataFieldSize, name: "RBDS")
387                 .WithReservedBits(11, 21);
388 
389             registerMap[(long)Register.TxBufferConfiguration] = new DoubleWordRegister(this)
390                 .WithReservedBits(0, 2)
391                 .WithValueField(2, 14, out rv.TxBufferConfiguration.TxBuffersStartAddress, name: "TBSA") // start address is aligned to four bytes, hence the lowest two bits of register are reserved
392                 .WithValueField(16, 6, out rv.TxBufferConfiguration.NumberOfDedicatedTxBuffers, name: "NDTB")
393                 .WithReservedBits(22, 2)
394                 .WithValueField(24, 6, out rv.TxBufferConfiguration.TxFIFOQueueSize, name: "TFQS")
395                 .WithFlag(30, out rv.TxBufferConfiguration.TxFIFOQueueMode, name: "TFQM")
396                 .WithReservedBits(31, 1);
397 
398             registerMap[(long)Register.TxFIFOQueueStatus] = new DoubleWordRegister(this)
399                 .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => txFIFOQueue.FreeLevel, name: "TFFL")
400                 .WithReservedBits(6, 2)
401                 .WithValueField(8, 5, out rv.TxFIFOQueueStatus.TxFIFOGetIndex, FieldMode.Read, valueProviderCallback: _ => txFIFOQueue.GetIndex, name: "TFGI")
402                 .WithReservedBits(13, 3)
403                 .WithValueField(16, 5, out rv.TxFIFOQueueStatus.TxFIFOQueuePutIndex, FieldMode.Read, valueProviderCallback: _ => txFIFOQueue.PutIndex, name: "TFQPI")
404                 .WithFlag(21, out rv.TxFIFOQueueStatus.TxFIFOQueueFull, FieldMode.Read, valueProviderCallback: _ => txFIFOQueue.Full, name: "TFQF")
405                 .WithReservedBits(22, 10);
406 
407             registerMap[(long)Register.TxBufferElementSizeConfiguration] = new DoubleWordRegister(this)
408                 .WithValueField(0, 3, out rv.TxBufferElementSizeConfiguration.TxBufferDataFieldSize, name: "TBDS")
409                 .WithReservedBits(3, 29);
410 
411             registerMap[(long)Register.TxBufferRequestPending] = new DoubleWordRegister(this)
412                 .WithFlags(0, 32, out rv.TxBufferRequestPending.TransmissionRequestPendingFlags, FieldMode.Read, name: "TRPx");
413 
414             registerMap[(long)Register.TxBufferAddRequest] = new DoubleWordRegister(this)
415                 .WithFlags(0, 32, out rv.TxBufferAddRequest.AddRequestFlags, writeCallback: (idx, oldVal, newVal) =>
416                 {
417                     if(!newVal || rv.CCControlRegister.ControlFields[(int)Control.ConfigurationChangeEnable].Value || idx >= (int)(rv.TxBufferConfiguration.NumberOfDedicatedTxBuffers.Value + rv.TxBufferConfiguration.TxFIFOQueueSize.Value))
418                     {
419                         rv.TxBufferAddRequest.AddRequestFlags[idx].Value = oldVal;
420                         return;
421                     }
422                     rv.TxBufferRequestPending.TransmissionRequestPendingFlags[idx].Value = true;
423                     rv.TxBufferCancellationFinished.CancellationFinishedFlags[idx].Value = false;
424                     rv.TxBufferTransmissionOccurred.TransmissionOccurredFlags[idx].Value = false;
425 
426                     if(!txFIFOQueue.QueueMode.Value && idx >= (int)txFIFOQueue.Offset.Value)
427                     {
428                         // Message added Tx FIFO
429                         txFIFOQueue.PutIndex++;
430                         if(txFIFOQueue.PutIndex == txFIFOQueue.GetIndex)
431                         {
432                             txFIFOQueue.FullRaw.Value = true;
433                             this.Log(LogLevel.Warning, "Tx FIFO is full");
434                         }
435                     }
436                 }, name: "ARx")
437                 .WithWriteCallback((oldVal, newVal) =>
438                 {
439                     TxScan();
440                 });
441 
442             registerMap[(long)Register.TxBufferCancellationRequest] = new DoubleWordRegister(this)
443                 .WithFlags(0, 32, out rv.TxBufferCancellationRequest.CancellationRequestFlags, writeCallback: (idx, oldVal, newVal) =>
444                 {
445                     if(!newVal || rv.CCControlRegister.ControlFields[(int)Control.ConfigurationChangeEnable].Value || idx >= (int)(rv.TxBufferConfiguration.NumberOfDedicatedTxBuffers.Value + rv.TxBufferConfiguration.TxFIFOQueueSize.Value))
446                     {
447                         rv.TxBufferCancellationRequest.CancellationRequestFlags[idx].Value = oldVal;
448                         return;
449                     }
450                     rv.TxBufferRequestPending.TransmissionRequestPendingFlags[idx].Value = false;
451                     rv.TxBufferCancellationRequest.CancellationRequestFlags[idx].Value = false;
452 
453                     if(!txFIFOQueue.QueueMode.Value && idx == (int)txFIFOQueue.GetIndex)
454                     {
455                         txFIFOQueue.GetIndex++;
456                         txFIFOQueue.FullRaw.Value = false;
457                     }
458 
459                     rv.TxBufferCancellationFinished.CancellationFinishedFlags[idx].Value = true;
460                 }, name: "CRx")
461                 .WithWriteCallback((oldVal, newVal) =>
462                 {
463                     UpdateInterrupts();
464                     TxScan();
465                 });
466 
467             registerMap[(long)Register.TxBufferTransmissionOccurred] = new DoubleWordRegister(this)
468                 .WithFlags(0, 32, out rv.TxBufferTransmissionOccurred.TransmissionOccurredFlags, name: "TOx");
469 
470             registerMap[(long)Register.TxBufferCancellationFinished] = new DoubleWordRegister(this)
471                 .WithFlags(0, 32, out rv.TxBufferCancellationFinished.CancellationFinishedFlags, name: "CFx");
472 
473             registerMap[(long)Register.TxBufferTransmissionInterruptEnable] = new DoubleWordRegister(this)
474                 .WithFlags(0, 32, out rv.TxBufferTransmissionInterruptEnable.TransmissionInterruptEnableFlags, name: "TIEx");
475 
476             registerMap[(long)Register.TxBufferCancellationFinishedInterruptEnable] = new DoubleWordRegister(this)
477                 .WithFlags(0, 32, out rv.TxBufferCancellationFinishedInterruptEnable.CancellationFinishedInterruptEnableFlags, name: "CFIEx");
478 
479             registerMap[(long)Register.TxEventFIFOConfiguration] = new DoubleWordRegister(this)
480                 .WithReservedBits(0, 2)
481                 .WithValueField(2, 14, out rv.TxEventFIFOConfiguration.EventFIFOStartAddress, name: "EFSA")
482                 .WithValueField(16, 6, out rv.TxEventFIFOConfiguration.EventFIFOSize, name: "EFS")
483                 .WithReservedBits(22, 2)
484                 .WithValueField(24, 6, out rv.TxEventFIFOConfiguration.EventFIFOWatermark, name: "EFWM")
485                 .WithReservedBits(30, 2);
486 
487             registerMap[(long)Register.TxEventFIFOStatus] = new DoubleWordRegister(this)
488                 .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => txEventFIFO.FillLevel, name: "EFFL")
489                 .WithReservedBits(6, 2)
490                 .WithValueField(8, 5, out rv.TxEventFIFOStatus.EventFIFOGetIndex, FieldMode.Read, name: "EFGI")
491                 .WithReservedBits(13, 3)
492                 .WithValueField(16, 5, out rv.TxEventFIFOStatus.EventFIFOPutIndex, FieldMode.Read, name: "EFPI")
493                 .WithReservedBits(21, 3)
494                 .WithFlag(24, out rv.TxEventFIFOStatus.EventFIFOFull, FieldMode.Read, name: "EFF")
495                 .WithFlag(25, out rv.TxEventFIFOStatus.TxEventFIFOElementLost, FieldMode.Read, name: "TEFL")
496                 .WithReservedBits(26, 6);
497 
498             registerMap[(long)Register.TxEventFIFOAcknowledge] = new DoubleWordRegister(this)
499                 .WithValueField(0, 5, out rv.TxEventFIFOAcknowledge.EventFIFOAcknowledgeIndex, writeCallback: (_, newVal) =>
500                 {
501                     txEventFIFO.GetIndex = newVal + 1;
502                     txEventFIFO.Full.Value = false;
503                     if(txEventFIFO.FillLevel == 0)
504                     {
505                         rv.InterruptRegister.InterruptFlags[(int)Interrupt.TxFIFOEmpty].Value = true;
506                         UpdateInterrupts();
507                     }
508                 }, name: "EFAI")
509                 .WithReservedBits(5, 27);
510 
511             return registerMap;
512         }
513 
TxScan()514         private void TxScan()
515         {
516             var bufferIdx = FindPrioritizedBuffer(out var messageID);
517             if(bufferIdx == -1)
518             {
519                 return;
520             }
521             this.Log(LogLevel.Debug, "Buffer {0} with Message ID {1} will be transmitted", bufferIdx, messageID);
522             TransmitBuffer(bufferIdx);
523         }
524 
525         // It scans Tx Buffers section in the Message RAM and returns index of the buffer to be transmitted next according to Tx prioritization rules.
FindPrioritizedBuffer(out uint messageID)526         private int FindPrioritizedBuffer(out uint messageID)
527         {
528             var numberOfDedicatedTxBuffers = txBuffers.NumberOfDedicatedTxBuffers.Value;
529             var txFIFOQueueSize = txBuffers.TxFIFOQueueSize.Value;
530             var txFIFOQueueMode = txBuffers.TxFIFOQueueMode.Value;
531 
532             var txScanMode = TxScanModeInternal.Dedicated;
533 
534             if(txFIFOQueueSize == 0)
535             {
536                 txScanMode = TxScanModeInternal.Dedicated;
537             }
538             else if(numberOfDedicatedTxBuffers == 0)
539             {
540                 if(txFIFOQueueMode)
541                 {
542                     txScanMode = TxScanModeInternal.Queue;
543                 }
544                 else
545                 {
546                     txScanMode = TxScanModeInternal.FIFO;
547                 }
548             }
549             else
550             {
551                 if(txFIFOQueueMode)
552                 {
553                     txScanMode = TxScanModeInternal.MixedDedicatedQueue;
554                 }
555                 else
556                 {
557                     txScanMode = TxScanModeInternal.MixedDedicatedFIFO;
558                 }
559             }
560 
561             messageID = uint.MaxValue; // Message ID of selected buffer
562             var bufferNumber = -1; // Index of selected buffer
563 
564             switch(txScanMode)
565             {
566                 case TxScanModeInternal.Dedicated:
567                 {
568                     bufferNumber = ScanDedicatedTxBuffers(out messageID);
569                     break;
570                 }
571                 case TxScanModeInternal.FIFO:
572                 {
573                     bufferNumber = ScanTxFIFO(out messageID);
574                     break;
575                 }
576                 case TxScanModeInternal.Queue:
577                 {
578                     bufferNumber = ScanTxQueue(out messageID);
579                     break;
580                 }
581                 case TxScanModeInternal.MixedDedicatedFIFO:
582                 {
583                     var bufferNumber0 = ScanDedicatedTxBuffers(out var messageID0);
584                     var bufferNumber1 = ScanTxFIFO(out var messageID1);
585                     messageID = messageID0 <= messageID1 ? messageID0 : messageID1;
586                     bufferNumber = messageID0 <= messageID1 ? bufferNumber0 : bufferNumber1;
587                     break;
588                 }
589                 case TxScanModeInternal.MixedDedicatedQueue:
590                 {
591                     var bufferNumber0 = ScanDedicatedTxBuffers(out var messageID0);
592                     var bufferNumber1 = ScanTxQueue(out var messageID1);
593                     messageID = messageID0 <= messageID1 ? messageID0 : messageID1;
594                     bufferNumber = messageID0 <= messageID1 ? bufferNumber0 : bufferNumber1;
595                     break;
596                 }
597             }
598 
599             return bufferNumber;
600         }
601 
ScanDedicatedTxBuffers(out uint messageID)602         private int ScanDedicatedTxBuffers(out uint messageID)
603         {
604             var startAddress = (int)(txBuffers.StartAddress.Value << 2);
605             var dataSizeInBytes = MapDataFieldSizeToDataBytes(txBuffers.DataFieldSize.Value);
606             var bufferSizeInBytes = BufferElementHeaderSizeInBytes + dataSizeInBytes;
607 
608             messageID = uint.MaxValue; // Message ID of selected buffer
609             var bufferNumber = -1; // Index of selected buffer
610 
611             for(var i = 0; i < (int)txBuffers.NumberOfDedicatedTxBuffers.Value; i++)
612             {
613                 if(!rv.TxBufferRequestPending.TransmissionRequestPendingFlags[i].Value)
614                 {
615                     continue;
616                 }
617 
618                 var offset = startAddress + i * bufferSizeInBytes;
619                 byte[] scanBytes = messageRAM.ReadBytes((long)offset, 4);
620                 var scanRecord = Packet.Decode<TxScanBufferAndEventFIFOCommonHeader>(scanBytes);
621 
622                 var id = scanRecord.Identifier;
623                 id = scanRecord.ExtendedIdentifier ? id : (id >> 18);
624 
625                 if(id < messageID || (i == 0 && id == uint.MaxValue))
626                 {
627                     // Found a message with higher priority
628                     messageID = id;
629                     bufferNumber = i;
630                 }
631             }
632 
633             return bufferNumber;
634         }
635 
ScanTxFIFO(out uint messageID)636         private int ScanTxFIFO(out uint messageID)
637         {
638             var startAddress = (int)(txBuffers.StartAddress.Value << 2);
639             var dataSizeInBytes = MapDataFieldSizeToDataBytes(txBuffers.DataFieldSize.Value);
640             var bufferSizeInBytes = BufferElementHeaderSizeInBytes + dataSizeInBytes;
641 
642             messageID = uint.MaxValue; // Message ID of selected buffer
643             var bufferNumber = -1; // Index of selected buffer
644 
645             var getIndex = (int)txFIFOQueue.GetIndex;
646 
647             if(!rv.TxBufferRequestPending.TransmissionRequestPendingFlags[getIndex].Value)
648             {
649                 return bufferNumber;
650             }
651 
652             var offset = startAddress + getIndex * bufferSizeInBytes;
653             byte[] scanBytes = messageRAM.ReadBytes((long)offset, 4);
654             var scanRecord = Packet.Decode<TxScanBufferAndEventFIFOCommonHeader>(scanBytes);
655 
656             var id = scanRecord.Identifier;
657             id = scanRecord.ExtendedIdentifier ? id : (id >> 18);
658 
659             messageID = id;
660             bufferNumber = getIndex;
661 
662             return bufferNumber;
663         }
664 
ScanTxQueue(out uint messageID)665         private int ScanTxQueue(out uint messageID)
666         {
667             var startAddress = (int)(txBuffers.StartAddress.Value << 2);
668             var dataSizeInBytes = MapDataFieldSizeToDataBytes(txBuffers.DataFieldSize.Value);
669             var bufferSizeInBytes = BufferElementHeaderSizeInBytes + dataSizeInBytes;
670 
671             messageID = uint.MaxValue; // Message ID of selected buffer
672             var bufferNumber = -1; // Index of selected buffer
673 
674             for(var i = (int)txFIFOQueue.Offset.Value; i < (int)(txFIFOQueue.Offset.Value + txFIFOQueue.Size.Value); i++)
675             {
676                 if(!rv.TxBufferRequestPending.TransmissionRequestPendingFlags[i].Value)
677                 {
678                     continue;
679                 }
680 
681                 var offset = startAddress + i * bufferSizeInBytes;
682                 byte[] scanBytes = messageRAM.ReadBytes((long)offset, 4);
683                 var scanRecord = Packet.Decode<TxScanBufferAndEventFIFOCommonHeader>(scanBytes);
684 
685                 var id = scanRecord.Identifier;
686                 id = scanRecord.ExtendedIdentifier ? id : (id >> 18);
687 
688                 if(id < messageID || (i == 0 && id == uint.MaxValue))
689                 {
690                     // Found a message with higher priority
691                     messageID = id;
692                     bufferNumber = i;
693                 }
694             }
695 
696             return bufferNumber;
697         }
698 
TransmitBuffer(int i)699         private void TransmitBuffer(int i)
700         {
701             var txBufferDataSize = MapDataFieldSizeToDataBytes(rv.TxBufferElementSizeConfiguration.TxBufferDataFieldSize.Value);
702             var bufferSizeInBytes = BufferElementHeaderSizeInBytes + txBufferDataSize;
703 
704             if(!rv.TxBufferRequestPending.TransmissionRequestPendingFlags[i].Value)
705             {
706                 return; // it was cancelled
707             }
708 
709             var addr = (rv.TxBufferConfiguration.TxBuffersStartAddress.Value << 2) + (ulong)(i * bufferSizeInBytes);
710             var frameBytes = messageRAM.ReadBytes((long)addr, (int)bufferSizeInBytes);
711             var frame = Packet.Decode<TxBufferElementHeader>(frameBytes);
712             var data = frameBytes.Skip(BufferElementHeaderSizeInBytes).Take((int)txBufferDataSize).ToArray();
713 
714             var dlcBufferSizeInBytes = MapDataLengthCodeToDataBytesCount(frame.DataLengthCode);
715             Array.Resize(ref data, dlcBufferSizeInBytes);
716 
717             if(txBufferDataSize < dlcBufferSizeInBytes)
718             {
719                 // The bytes not defined by the Tx Buffer are transmitted as “0xCC” (padding bytes).
720                 for(var j = (int)txBufferDataSize; j < dlcBufferSizeInBytes; j++)
721                 {
722                     data[j] = PaddingByte;
723                 }
724             }
725 
726             var id = frame.Identifier;
727             id = frame.ExtendedIdentifier ? id : (id >> 18); // 11 or 29 bit identifier, a standard identifier is stored in ID[28:18]
728             var canMessage = new CANMessageFrame(id, data, frame.ExtendedIdentifier, frame.RemoteTransmissionRequest, frame.FDFormat, frame.BitRateSwitch);
729 
730             var wasTransmitted = TransmitMessage(canMessage);
731             if(wasTransmitted)
732             {
733                 HandleTransmitSuccess(i, frame);
734             }
735 
736             machine.LocalTimeSource.ExecuteInNearestSyncedState(__ =>
737             {
738                 if(wasTransmitted)
739                 {
740                     UpdateInterrupts();
741                     TxScan();
742                 }
743             }, true);
744         }
745 
HandleTransmitSuccess(int i, TxBufferElementHeader frame)746         private void HandleTransmitSuccess(int i, TxBufferElementHeader frame)
747         {
748             rv.TxBufferRequestPending.TransmissionRequestPendingFlags[i].Value = false;
749             rv.ProtocolStatusRegister.LastErrorCode.Value = LastErrorCode.NoError;
750             HandleTxEvent(frame);
751 
752             if(!txFIFOQueue.QueueMode.Value && i >= (int)txFIFOQueue.Offset.Value)
753             {
754                 // Transmitted message belonged to Tx FIFO
755                 txFIFOQueue.GetIndex++;
756                 txFIFOQueue.FullRaw.Value = false;
757             }
758 
759             rv.TxBufferTransmissionOccurred.TransmissionOccurredFlags[i].Value = true;
760         }
761 
HandleTxEvent(TxBufferElementHeader txHeader)762         private void HandleTxEvent(TxBufferElementHeader txHeader)
763         {
764             if(rv.CCControlRegister.ControlFields[(int)Control.WideMessageMarker].Value)
765             {
766                 this.Log(LogLevel.Warning, "Wide Message Marker requires an external Time Stamping Unit (TSU) that is not available");
767                 return;
768             }
769 
770             var txFIFOElement = new TxEventFIFOElement
771             {
772                 Identifier = txHeader.Identifier,
773                 RemoteTransmissionRequest = txHeader.RemoteTransmissionRequest,
774                 ExtendedIdentifier = txHeader.ExtendedIdentifier,
775                 ErrorStateIndicator = txHeader.ErrorStateIndicator,
776                 TxTimestamp = 0,
777                 DataLengthCode = txHeader.DataLengthCode,
778                 BitRateSwitch = txHeader.BitRateSwitch,
779                 FDFormat = txHeader.FDFormat,
780                 EventType = 0b10, // Tx event
781                 MessageMarker = txHeader.MessageMarkerLow
782             };
783 
784             StoreInTxEventFIFO(txFIFOElement);
785         }
786 
StoreInTxEventFIFO(TxEventFIFOElement txFIFOElement)787         private void StoreInTxEventFIFO(TxEventFIFOElement txFIFOElement)
788         {
789             if(txEventFIFO.Full.Value || txEventFIFO.Size.Value == 0)
790             {
791                 txEventFIFO.InterruptElementLost.Value = true;
792                 txEventFIFO.ElementLost.Value = true;
793                 return;
794             }
795 
796             var addr = (txEventFIFO.StartAddress.Value << 2) + txEventFIFO.PutIndex * (ulong)TxEventFIFOElementSizeInBytes;
797             var txFIFOElementBytes = Packet.Encode(txFIFOElement);
798 
799             messageRAM.WriteBytes((long)addr, txFIFOElementBytes, 0, txFIFOElementBytes.Length);
800 
801             txEventFIFO.PutIndex += 1;
802             txEventFIFO.Full.Value = txEventFIFO.PutIndexRaw == txEventFIFO.GetIndexRaw;
803 
804             var watermarkReached = (txEventFIFO.Watermark.Value > 0) && (txEventFIFO.FillLevel >= txEventFIFO.Watermark.Value);
805             if(watermarkReached)
806             {
807                 txEventFIFO.InterruptWatermarkReached.Value = true;
808             }
809 
810             if(txEventFIFO.Full.Value)
811             {
812                 txEventFIFO.InterruptFull.Value = true;
813             }
814 
815             txEventFIFO.InterruptNewEntry.Value = true;
816         }
817 
TransmitMessage(CANMessageFrame canMessage)818         private bool TransmitMessage(CANMessageFrame canMessage)
819         {
820             var transmitted = true;
821             var fs = FrameSent;
822             if(fs != null)
823             {
824                 fs.Invoke(canMessage);
825             }
826             else
827             {
828                 transmitted = false;
829                 this.Log(LogLevel.Warning, "FrameSent is not initialized. Is the controller connected to medium?");
830             }
831 
832             return transmitted;
833         }
834 
HandleRxInner(CANMessageFrame rxMessage)835         private void HandleRxInner(CANMessageFrame rxMessage)
836         {
837             var match = FilterMessage(rxMessage);
838             if(!match)
839             {
840                 this.Log(LogLevel.Debug, "Received CAN message discarded");
841             }
842         }
843 
FilterMessage(CANMessageFrame rxMessage)844         private bool FilterMessage(CANMessageFrame rxMessage)
845         {
846             var isExtended = rxMessage.ExtendedFormat;
847             var isRemote = rxMessage.RemoteFrame;
848             var id = rxMessage.Id;
849 
850             rv.ProtocolStatusRegister.ReceivedCANFDMessage.Value = rxMessage.FDFormat;
851 
852             var filterConfig = isExtended ? filterConfigurationExtended : filterConfigurationStandard;
853 
854             var rejectRemoteFrames = filterConfig.RejectRemoteFrames.Value;
855             if(isRemote && rejectRemoteFrames)
856             {
857                 return false; // discard remote frame
858             }
859 
860             var listSize = filterConfig.ListSize.Value;
861             var receiveFilterListEnabled = listSize > 0;
862 
863             var acceptNonMatchingFrames = filterConfig.AcceptNonMatchingFrames.Value;
864             var rejectNonMatchingFrames = acceptNonMatchingFrames != NonMatchingFrameTarget.AcceptInRxFIFO0 && acceptNonMatchingFrames != NonMatchingFrameTarget.AcceptInRxFIFO1;
865             if(!receiveFilterListEnabled && rejectNonMatchingFrames)
866             {
867                 return false; // discard non-matching frame
868             }
869 
870             if(receiveFilterListEnabled)
871             {
872                 var startAddress = filterConfig.FilterListStartAddress.Value;
873                 var filterSizeInBytes = isExtended ? ExtendedFilterSizeInBytes : StandardFilterSizeInBytes;
874 
875                 var match = false;
876                 for(var i = 0; i < (int)listSize; i++)
877                 {
878                     var addr = (long)(startAddress << 2) + i * filterSizeInBytes;
879                     var filterBytes = messageRAM.ReadBytes(addr, filterSizeInBytes);
880                     var filter = DecodeFilterElement(isExtended, filterBytes);
881 
882                     if(filter.FilterElementConfiguration == FilterElementConfiguration.DisableFilter)
883                     {
884                         continue; // filter element disabled
885                     }
886                     else if(filter.FilterElementConfiguration == FilterElementConfiguration.RxBufferOrDebugMessageOnMatch)
887                     {
888                         var rxBufferIdx = BitHelper.GetValue(filter.ID2, 0, 6);
889                         var newDataFlags = rxBufferIdx < 32 ? rv.NewData1.NewData1Flags : rv.NewData2.NewData2Flags;
890                         if(newDataFlags[rxBufferIdx % 32].Value)
891                         {
892                             // While an Rx Buffer’s New Data flag is set, a Message ID Filter Element
893                             // referencing this specific RxBuffer will not match.
894                             continue;
895                         }
896                     }
897 
898                     match = MatchFilterElement(isExtended, id, filter);
899 
900                     if(!match)
901                     {
902                         continue;
903                     }
904 
905                     HandleMatchedFilter(filter, i, rxMessage);
906 
907                     return true;
908                 }
909 
910                 if(!match && rejectNonMatchingFrames)
911                 {
912                     return false; // discard non-matching frame
913                 }
914             }
915 
916             AcceptNonMatchingFrame(acceptNonMatchingFrames, rxMessage);
917 
918             return true;
919         }
920 
DecodeFilterElement(bool extended, byte[] filterBytes)921         private MessageIDFilterElement DecodeFilterElement(bool extended, byte[] filterBytes)
922         {
923             if(extended)
924             {
925                 var filter = Packet.Decode<ExtendedMessageIDFilterElement>(filterBytes);
926                 return new MessageIDFilterElement
927                 {
928                     ID1 = filter.ExtendedFilterID1,
929                     ID2 = filter.ExtendedFilterID2,
930                     SyncMessage = filter.ExtendedSyncMessage,
931                     FilterElementConfiguration = filter.ExtendedFilterElementConfiguration,
932                     FilterType = filter.ExtendedFilterType,
933                     IsExtended = true
934                 };
935             }
936             else
937             {
938                 var filter = Packet.Decode<StandardMessageIDFilterElement>(filterBytes);
939                 return new MessageIDFilterElement
940                 {
941                     ID1 = filter.StandardFilterID1,
942                     ID2 = filter.StandardFilterID2,
943                     SyncMessage = filter.StandardSyncMessage,
944                     FilterElementConfiguration = filter.StandardFilterElementConfiguration,
945                     FilterType = filter.StandardFilterType,
946                     IsExtended = false
947                 };
948             }
949         }
950 
MatchFilterElement(bool isExtended, uint id, MessageIDFilterElement filter)951         private bool MatchFilterElement(bool isExtended, uint id, MessageIDFilterElement filter)
952         {
953             switch(filter.FilterType)
954             {
955                 case FilterType.Range:
956                 {
957                     if(!isExtended)
958                     {
959                         if(id >= filter.ID1 && id <= filter.ID2)
960                         {
961                             return true;
962                         }
963                     }
964                     else
965                     {
966                         var idMasked = id & (uint)rv.ExtendedIdANDMask.ExtendedIDANDMask.Value;
967                         if(idMasked >= filter.ID1 && idMasked <= filter.ID2)
968                         {
969                             return true;
970                         }
971                     }
972                     break;
973                 }
974                 case FilterType.DualID:
975                 {
976                     if((id == filter.ID1) || (id == filter.ID2))
977                     {
978                         return true;
979                     }
980                     break;
981                 }
982                 case FilterType.Classic:
983                 {
984                     if((id & filter.ID2) == (filter.ID1 & filter.ID2))
985                     {
986                         return true;
987                     }
988                     break;
989                 }
990                 case FilterType.RangeWithoutMask:
991                 {
992                     if(!isExtended)
993                     {
994                         break;
995                     }
996                     if(id >= filter.ID1 && id <= filter.ID2)
997                     {
998                         return true;
999                     }
1000                     break;
1001                 }
1002                 default:
1003                 {
1004                     this.Log(LogLevel.Warning, "Invalid filter type.");
1005                     break;
1006                 }
1007             }
1008             return false;
1009         }
1010 
HandleMatchedFilter(MessageIDFilterElement filter, int idx, CANMessageFrame rxMessage)1011         private void HandleMatchedFilter(MessageIDFilterElement filter, int idx, CANMessageFrame rxMessage)
1012         {
1013             var rxBufferElementHeader = new RxBufferElementHeader
1014             {
1015                 Identifier = rxMessage.ExtendedFormat ? rxMessage.Id : rxMessage.Id << 18,
1016                 RemoteTransmissionRequest = rxMessage.RemoteFrame,
1017                 ExtendedIdentifier = rxMessage.ExtendedFormat,
1018                 ErrorStateIndicator = false,
1019                 RxTimestamp = 0,
1020                 DataLengthCode = MapDataBytesCountToDataLengthCode(k: rxMessage.Data.Length),
1021                 BitRateSwitch = rxMessage.BitRateSwitch,
1022                 FDFormat = rxMessage.FDFormat,
1023                 FilterIndex = (byte)idx,
1024                 AcceptedNonMatchingFrame = false
1025             };
1026 
1027             switch(filter.FilterElementConfiguration)
1028             {
1029                 case FilterElementConfiguration.RxFIFO0OnMatch:
1030                 {
1031                     var wasStored = StoreInRxFIFO(0, rxBufferElementHeader, rxMessage.Data);
1032                     break;
1033                 }
1034                 case FilterElementConfiguration.RxFIFO1OnMatch:
1035                 {
1036                     var wasStored = StoreInRxFIFO(1, rxBufferElementHeader, rxMessage.Data);
1037                     break;
1038                 }
1039                 case FilterElementConfiguration.RejectIDOnMatch:
1040                 {
1041                     if(filter.SyncMessage)
1042                     {
1043                         this.Log(LogLevel.Warning, "Reject ID if filter matches is not intended to be used with Sync messages");
1044                     }
1045                     break;
1046                 }
1047                 case FilterElementConfiguration.SetPriorityOnMatch:
1048                 {
1049                     if(filter.SyncMessage)
1050                     {
1051                         this.Log(LogLevel.Warning, "Setting priority on filter match is not intended to be used with Sync messages");
1052                         return;
1053                     }
1054 
1055                     rv.HighPriorityMessageStatus.MessageStorageIndicator.Value = MessageStorageIndicator.NoFIFOselected;
1056                     rv.HighPriorityMessageStatus.FilterIndex.Value = (ulong)idx;
1057                     rv.HighPriorityMessageStatus.FilterList.Value = filter.IsExtended;
1058 
1059                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.HighPriorityMessage].Value = true;
1060                     break;
1061                 }
1062                 case FilterElementConfiguration.SetPriorityAndRxFIFO0OnMatch:
1063                 {
1064                     var wasStored = StoreInRxFIFO(0, rxBufferElementHeader, rxMessage.Data);
1065 
1066                     if(wasStored)
1067                     {
1068                         rv.HighPriorityMessageStatus.BufferIndex.Value = rv.RxFIFO0Status.RxFIFO0PutIndex.Value - 1; // Put Index was already incremented for new message so subtract one
1069                         rv.HighPriorityMessageStatus.MessageStorageIndicator.Value = MessageStorageIndicator.MessageInFIFO0;
1070                     }
1071                     else
1072                     {
1073                         rv.HighPriorityMessageStatus.MessageStorageIndicator.Value = MessageStorageIndicator.FIFOMessageLost;
1074                     }
1075                     rv.HighPriorityMessageStatus.FilterIndex.Value = (ulong)idx;
1076                     rv.HighPriorityMessageStatus.FilterList.Value = filter.IsExtended;
1077 
1078                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.HighPriorityMessage].Value = true;
1079                     break;
1080                 }
1081                 case FilterElementConfiguration.SetPriorityAndRxFIFO1OnMatch:
1082                 {
1083                     var wasStored = StoreInRxFIFO(1, rxBufferElementHeader, rxMessage.Data);
1084 
1085                     if(wasStored)
1086                     {
1087                         rv.HighPriorityMessageStatus.BufferIndex.Value = rv.RxFIFO1Status.RxFIFO1PutIndex.Value - 1; // Put Index was already incremented for new message so subtract one
1088                         rv.HighPriorityMessageStatus.MessageStorageIndicator.Value = MessageStorageIndicator.MessageInFIFO1;
1089                     }
1090                     else
1091                     {
1092                         rv.HighPriorityMessageStatus.MessageStorageIndicator.Value = MessageStorageIndicator.FIFOMessageLost;
1093                     }
1094                     rv.HighPriorityMessageStatus.FilterIndex.Value = (ulong)idx;
1095                     rv.HighPriorityMessageStatus.FilterList.Value = filter.IsExtended;
1096 
1097                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.HighPriorityMessage].Value = true;
1098                     break;
1099                 }
1100                 case FilterElementConfiguration.RxBufferOrDebugMessageOnMatch:
1101                 {
1102                     StoreInRxBuffer(rxBufferElementHeader, rxMessage.Data, filter);
1103                     break;
1104                 }
1105                 default:
1106                 {
1107                     this.Log(LogLevel.Warning, "Invalid Filter Element Configuration");
1108                     break;
1109                 }
1110             }
1111         }
1112 
AcceptNonMatchingFrame(NonMatchingFrameTarget frameTarget, CANMessageFrame rxMessage)1113         private void AcceptNonMatchingFrame(NonMatchingFrameTarget frameTarget, CANMessageFrame rxMessage)
1114         {
1115             var rxBufferElementHeader = new RxBufferElementHeader
1116             {
1117                 Identifier = rxMessage.ExtendedFormat ? rxMessage.Id : rxMessage.Id << 18,
1118                 RemoteTransmissionRequest = rxMessage.RemoteFrame,
1119                 ExtendedIdentifier = rxMessage.ExtendedFormat,
1120                 ErrorStateIndicator = false,
1121                 RxTimestamp = 0,
1122                 DataLengthCode = MapDataBytesCountToDataLengthCode(k: rxMessage.Data.Length),
1123                 BitRateSwitch = rxMessage.BitRateSwitch,
1124                 FDFormat = rxMessage.FDFormat,
1125                 FilterIndex = 0,
1126                 AcceptedNonMatchingFrame = true
1127             };
1128 
1129             switch(frameTarget)
1130             {
1131                 case NonMatchingFrameTarget.AcceptInRxFIFO0:
1132                 {
1133                     StoreInRxFIFO(0, rxBufferElementHeader, rxMessage.Data);
1134                     break;
1135                 }
1136                 case NonMatchingFrameTarget.AcceptInRxFIFO1:
1137                 {
1138                     StoreInRxFIFO(1, rxBufferElementHeader, rxMessage.Data);
1139                     break;
1140                 }
1141                 default:
1142                 {
1143                     this.Log(LogLevel.Warning, "Non-matching frame was rejected");
1144                     break;
1145                 }
1146             }
1147         }
1148 
StoreInRxFIFO(uint idx, RxBufferElementHeader rxHeader, byte[] rxData)1149         private bool StoreInRxFIFO(uint idx, RxBufferElementHeader rxHeader, byte[] rxData)
1150         {
1151             if(idx >= NumberOfRxFIFOs)
1152             {
1153                 this.Log(LogLevel.Warning, "Only FIFO0 or FIFO1 are available");
1154             }
1155 
1156             var rxFIFO = idx == 0 ? rxFIFO0 : rxFIFO1;
1157 
1158             if(rxFIFO.Size.Value == 0)
1159             {
1160                 rxFIFO.InterruptMessageLost.Value = true;
1161                 rxFIFO.MessageLost.Value = true;
1162                 return false; // Message is discarded
1163             }
1164 
1165             var dataFieldInBytes = MapDataFieldSizeToDataBytes(rxFIFO.DataFieldSize.Value);
1166             var fifoElementSizeInBytes = BufferElementHeaderSizeInBytes + dataFieldInBytes;
1167 
1168             var addr = (rxFIFO.StartAddress.Value << 2) + rxFIFO.RxFIFOPutIndex * (ulong)fifoElementSizeInBytes;
1169             var rxHeaderBytes = Packet.Encode(rxHeader);
1170 
1171             switch(rxFIFO.OperationMode.Value)
1172             {
1173                 case FIFOOperationMode.Overwrite:
1174                 {
1175                     if(rxFIFO.Full.Value)
1176                     {
1177                         rxFIFO.RxFIFOGetIndex += 1;
1178                     }
1179                     break;
1180                 }
1181                 case FIFOOperationMode.Blocking:
1182                 default:
1183                 {
1184                     if(rxFIFO.Full.Value)
1185                     {
1186                         rxFIFO.InterruptMessageLost.Value = true;
1187                         rxFIFO.MessageLost.Value = true;
1188                         return false; // Message is discarded
1189                     }
1190                     break;
1191                 }
1192             }
1193 
1194             messageRAM.WriteBytes((long)addr, rxHeaderBytes, 0, rxHeaderBytes.Length);
1195             messageRAM.WriteBytes((long)addr + rxHeaderBytes.Length, rxData, 0, rxData.Length);
1196 
1197             rxFIFO.RxFIFOPutIndex += 1;
1198             rxFIFO.Full.Value = rxFIFO.RxFIFOPutIndex == rxFIFO.RxFIFOGetIndex;
1199 
1200             var watermarkReached = (rxFIFO.Watermark.Value > 0) && (rxFIFO.RxFIFOFillLevel >= rxFIFO.Watermark.Value);
1201             if(watermarkReached)
1202             {
1203                 rxFIFO.InterruptWatermarkReached.Value = true;
1204             }
1205 
1206             if(rxFIFO.Full.Value)
1207             {
1208                 rxFIFO.InterruptFull.Value = true;
1209             }
1210 
1211             rxFIFO.InterruptNewMessage.Value = true;
1212 
1213             return true;
1214         }
1215 
StoreInRxBuffer(RxBufferElementHeader rxHeader, byte[] rxData, MessageIDFilterElement filter)1216         private void StoreInRxBuffer(RxBufferElementHeader rxHeader, byte[] rxData, MessageIDFilterElement filter)
1217         {
1218             var id2 = filter.ID2;
1219 
1220             var rxBufferIdx = BitHelper.GetValue(id2, 0, 6);
1221             var filterEventPins = BitHelper.GetValue(id2, 6, 3);
1222             var target = (RxBufferOrDebugDestination)BitHelper.GetValue(id2, 9, 2);
1223 
1224             var startAddress = rxBuffer.StartAddress.Value << 2;
1225             var dataFieldSize = rxBuffer.DataFieldSize.Value;
1226 
1227             var dataFieldInBytes = MapDataFieldSizeToDataBytes(dataFieldSize);
1228             var bufferElementSizeInBytes = BufferElementHeaderSizeInBytes + dataFieldInBytes;
1229 
1230             var addr = startAddress + rxBufferIdx * (ulong)bufferElementSizeInBytes;
1231             var rxHeaderBytes = Packet.Encode(rxHeader);
1232 
1233             messageRAM.WriteBytes((long)addr, rxHeaderBytes, 0, rxHeaderBytes.Length);
1234             messageRAM.WriteBytes((long)addr + rxHeaderBytes.Length, rxData, 0, rxData.Length);
1235 
1236             switch(target)
1237             {
1238                 case RxBufferOrDebugDestination.StoreInRxBuffer:
1239                 {
1240                     var newDataFlags = rxBufferIdx < 32 ? rv.NewData1.NewData1Flags : rv.NewData2.NewData2Flags;
1241                     newDataFlags[rxBufferIdx % 32].Value = true;
1242 
1243                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.MessageStoredToDedicatedRxBuffer].Value = true;
1244                     break;
1245                 }
1246                 case RxBufferOrDebugDestination.DebugMessageA:
1247                 case RxBufferOrDebugDestination.DebugMessageB:
1248                 case RxBufferOrDebugDestination.DebugMessageC:
1249                 default:
1250                 {
1251                     this.Log(LogLevel.Warning, "DMU add-on is required to activate DMA request output after debug message is stored");
1252                     break;
1253                 }
1254             }
1255         }
1256 
MapDataFieldSizeToDataBytes(ulong k)1257         private int MapDataFieldSizeToDataBytes(ulong k)
1258         {
1259             if(k >= 8)
1260             {
1261                 this.Log(LogLevel.Warning, "Invalid Data Field Size");
1262                 return 0;
1263             }
1264 
1265             DataFieldSizeToBytesCountMap.TryGetValue(k, out var fieldSize);
1266             return fieldSize;
1267         }
1268 
MapDataBytesCountToDataLengthCode(int k)1269         private byte MapDataBytesCountToDataLengthCode(int k)
1270         {
1271             if(k <= 8)
1272             {
1273                 return (byte)k;
1274             }
1275 
1276             if(k > 64)
1277             {
1278                 this.Log(LogLevel.Warning, "Received frame has more than 64 bytes");
1279                 return 0;
1280             }
1281             var success = FDBytesCountToDataLengthCodeMap.TryGetValue(k, out var datalengthCode);
1282 
1283             if(!success)
1284             {
1285                 this.Log(LogLevel.Warning, "Invalid length of received frame");
1286                 return 0;
1287             }
1288 
1289             return datalengthCode;
1290         }
1291 
MapDataLengthCodeToDataBytesCount(int k)1292         private byte MapDataLengthCodeToDataBytesCount(int k)
1293         {
1294             if(k <= 8)
1295             {
1296                 return (byte)k;
1297             }
1298 
1299             if(k > 15)
1300             {
1301                 this.Log(LogLevel.Warning, "Frame specfied an invalid Data Length Code");
1302                 return 0;
1303             }
1304 
1305             DataLengthCodeToFDBytesCountMap.TryGetValue(k, out var fdBytesCount);
1306             return fdBytesCount;
1307         }
1308 
UpdateInterrupts()1309         private void UpdateInterrupts()
1310         {
1311             var flag0 = false;
1312             var flag1 = false;
1313 
1314             for(int i = 0; i < rv.TxBufferTransmissionInterruptEnable.TransmissionInterruptEnableFlags.Length; i++)
1315             {
1316                 if(rv.TxBufferTransmissionInterruptEnable.TransmissionInterruptEnableFlags[i].Value && rv.TxBufferTransmissionOccurred.TransmissionOccurredFlags[i].Value)
1317                 {
1318                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.TransmissionCompleted].Value = true;
1319                 }
1320             }
1321 
1322             for(int i = 0; i < rv.TxBufferCancellationFinishedInterruptEnable.CancellationFinishedInterruptEnableFlags.Length; i++)
1323             {
1324                 if(rv.TxBufferCancellationFinishedInterruptEnable.CancellationFinishedInterruptEnableFlags[i].Value && rv.TxBufferCancellationFinished.CancellationFinishedFlags[i].Value)
1325                 {
1326                     rv.InterruptRegister.InterruptFlags[(int)Interrupt.TransmissionCancellationFinished].Value = true;
1327                 }
1328             }
1329 
1330             for(int i = 0; i < rv.InterruptRegister.InterruptFlags.Length; i++)
1331             {
1332                 if(rv.InterruptEnable.InterruptEnableFlags[i].Value && rv.InterruptRegister.InterruptFlags[i].Value)
1333                 {
1334                     flag0 |= rv.InterruptLineEnable.EnableInterruptLine0.Value && !rv.InterruptLineSelect.InterruptLineSelectFlags[i].Value;
1335                     flag1 |= rv.InterruptLineEnable.EnableInterruptLine1.Value && rv.InterruptLineSelect.InterruptLineSelectFlags[i].Value;
1336                 }
1337             }
1338 
1339             Line0.Set(flag0);
1340             Line1.Set(flag1);
1341         }
1342     }
1343 }
1344