1 //
2 // Copyright (c) 2010-2021 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Core;
12 using System.Collections.Generic;
13 using System.Collections.ObjectModel;
14 using Antmicro.Renode.Core.CAN;
15 using Antmicro.Renode.Exceptions;
16 using System.Linq;
17 
18 namespace Antmicro.Renode.Peripherals.CAN
19 {
20     public class STMCAN : IDoubleWordPeripheral, ICAN, INumberedGPIOOutput
21     {
STMCAN(STMCAN master = null)22         public STMCAN(STMCAN master = null)
23         {
24             // Register master CAN
25             this.master = master;
26 
27             for(int i = 0; i < NumberOfRxFifos; i++)
28             {
29                 RxFifo[i] = new Queue<CANMessage>();
30                 if(!IsSlave)
31                 {
32                     FifoFiltersPrioritized[i] = new List<FilterBank>();
33                 }
34             }
35 
36             var innerConnections = new Dictionary<int, IGPIO>();
37             for(int i = 0; i < NumberOfInterruptLines; i++)
38             {
39                 innerConnections[i] = new GPIO();
40             }
41             Connections = new ReadOnlyDictionary<int, IGPIO>(innerConnections);
42 
43             registers = new DeviceRegisters();
44 
45             // Fixup receive fifo regs
46             registers.CAN_RFR[RxFifo0].SetRxFifo(RxFifo[RxFifo0]);
47             registers.CAN_RFR[RxFifo0].UpdateInterruptLine =
48                 new UpdateInterruptLine(UpdateFifo0InterruptLine);
49 
50             registers.CAN_RFR[RxFifo1].SetRxFifo(RxFifo[RxFifo1]);
51             registers.CAN_RFR[RxFifo1].UpdateInterruptLine =
52                 new UpdateInterruptLine(UpdateFifo1InterruptLine);
53 
54             if(!IsSlave)
55             {
56                 FilterBanks = new FilterBank[NumberOfFilterBanks];
57                 for(int i = 0; i < NumberOfFilterBanks; i++)
58                 {
59                     FilterBanks[i] = new FilterBank();
60                 }
61             }
62             else
63             {
64                 if(master.FilterBanks == null)
65                 {
66                     throw new ConstructionException("You need to construct the master first.");
67                 }
68                 if(master.IsSlave)
69                 {
70                     throw new ConstructionException("The master of this peripheral cannot be a slave to another master.");
71                 }
72                 FilterBanks = master.FilterBanks;
73                 FifoFiltersPrioritized = master.FifoFiltersPrioritized;
74                 registers.CAN_FMR = master.registers.CAN_FMR;
75                 registers.CAN_FM1R = master.registers.CAN_FM1R;
76                 registers.CAN_FS1R = master.registers.CAN_FS1R;
77                 registers.CAN_FFA1R = master.registers.CAN_FFA1R;
78                 registers.CAN_FA1R = master.registers.CAN_FA1R;
79             }
80 
81             Reset();
82         }
83 
84         public event Action<int, byte[]> FrameReceived;
85 
OnFrameReceived(CANMessageFrame message)86         public void OnFrameReceived(CANMessageFrame message)
87         {
88             if(registers.CAN_MCR.SleepRequest == true)
89             {
90                 // Wake up if autowake up is on
91                 if(registers.CAN_MCR.AutoWakeUpMode == true)
92                 {
93                     registers.CAN_MCR.SleepRequest = false;
94                     registers.CAN_MSR.SleepAck = false;
95                 }
96                 // Signal wake up interrupt
97                 registers.CAN_MSR.WakeupInterrupt = true;
98                 UpdateSCEInterruptLine();
99             }
100             else if(registers.CAN_BTR.LoopbackMode == false)
101             {
102                 CANMessage RxMsg = new CANMessage(message);
103                 for(int fifo = 0; fifo < NumberOfRxFifos; fifo++)
104                 {
105                     if(FilterCANMessage(fifo, RxMsg) == true)
106                     {
107                         this.Log(LogLevel.Debug, "Message received RIR={0:X}", message.Id);
108                         ReceiveCANMessage(RxMsg);
109                     }
110                     else
111                     {
112                        this.Log(LogLevel.Debug, "Message dropped by filter RIR={0:X}", message.Id);
113                     }
114                 }
115             }
116             FrameReceived?.Invoke((int)message.Id, message.Data);
117         }
118 
WriteDoubleWord(long address, uint value)119         public void WriteDoubleWord(long address, uint value)  // cpu do per
120         {
121             if(IsSlave && AddressIsWithinFilterRegistersArea(address))
122             {
123                 this.Log(LogLevel.Warning, "Trying to access slave's filter registers, but the slave has to be configured via master's filters. This change has no effect.");
124                 return;
125             }
126 
127             // Filter bank registers
128             if((registerOffset)address >= registerOffset.CAN_F0R1 &&
129                 (registerOffset)address <= registerOffset.CAN_F27R2)
130             {
131                 int bankIdx = AddressToFilterBankIdx(address);
132 
133                 // The filter bank registers can only be written if
134                 // CAN_FMR.FINIT is true or the FA1R has FACtx cleared
135                 // (the filter is disabled)
136                 if(registers.CAN_FMR.FilterInitMode == true ||
137                     registers.CAN_FA1R.FilterActive(bankIdx) == false)
138                 {
139                     int regIdx = AddressToRegIdx(address);
140                     //registers.CAN_FiRx[RegIdx] = value;
141                     FilterBanks[bankIdx].FR[regIdx] = value;
142                 }
143                 return;
144             }
145 
146             switch((registerOffset)address)
147             {
148                 case registerOffset.CAN_MSR:
149                     registers.CAN_MSR.SetValue(value);
150                     UpdateSCEInterruptLine();
151                     return;
152                 case registerOffset.CAN_MCR:
153                     registers.CAN_MCR.SetValue(value);
154 
155                     if(registers.CAN_MCR.InitRequest == true &&
156                        registers.CAN_MCR.SleepRequest == false)
157                     {
158                         // Enter initialisation mode
159                         registers.CAN_MSR.InitAck = true;
160                         registers.CAN_MSR.SleepAck = false;
161                     }
162                     else if(registers.CAN_MCR.SleepRequest == true &&
163                             registers.CAN_MCR.InitRequest == false)
164                     {
165                         // Enter sleep mode
166                         registers.CAN_MSR.SleepAck = true;
167                         registers.CAN_MSR.SleepAckInterrupt = true;
168                         registers.CAN_MSR.InitAck = false;
169                         UpdateSCEInterruptLine();
170                     }
171                     else
172                     {
173                         // Enter normal mode
174                         registers.CAN_MSR.SleepAck = false;
175                         registers.CAN_MSR.InitAck = false;
176                     }
177 
178                     if(registers.CAN_MCR.Reset == true)
179                     {
180                         registers.Reset();
181                     }
182 
183                     return;
184 
185                 case registerOffset.CAN_TSR:
186                     registers.CAN_TSR.SetValue(value);
187                     UpdateTransmitInterruptLine();
188                     return;
189 
190                 case registerOffset.CAN_RF0R:
191                     registers.CAN_RFR[RxFifo0].SetValue(value);
192                     return;
193 
194                 case registerOffset.CAN_RF1R:
195                     registers.CAN_RFR[RxFifo1].SetValue(value);
196                     return;
197 
198                 case registerOffset.CAN_IER:
199                     registers.CAN_IER.SetValue(value);
200                     UpdateTransmitInterruptLine();
201                     registers.CAN_RFR[RxFifo0].UpdateInterruptLine();
202                     registers.CAN_RFR[RxFifo1].UpdateInterruptLine();
203                     UpdateSCEInterruptLine();
204                     return;
205 
206                 case registerOffset.CAN_ESR:
207                     registers.CAN_ESR.SetValue(value);
208                     UpdateSCEInterruptLine();
209                     return;
210 
211                 case registerOffset.CAN_BTR:
212                     if(registers.CAN_MSR.InitAck == true)
213                     {
214                         registers.CAN_BTR.SetValue(value);
215                     }
216                     return;
217 
218                 // Filter registers
219                 case registerOffset.CAN_FMR:
220                     registers.CAN_FMR.SetValue(value);
221                     UpdateFilterCANAssignment();
222                     return;
223                 case registerOffset.CAN_FM1R:
224                     if(registers.CAN_FMR.FilterInitMode == true)
225                     {
226                         registers.CAN_FM1R.SetValue(value);
227                         for(int i = 0; i < NumberOfFilterBanks; i++)
228                         {
229                             FilterBanks[i].Mode =
230                                 registers.CAN_FM1R.FilterMode(i);
231                         }
232                     }
233                     return;
234                 case registerOffset.CAN_FS1R:
235                     if(registers.CAN_FMR.FilterInitMode == true)
236                     {
237                         registers.CAN_FS1R.SetValue(value);
238                         for(int i = 0; i < NumberOfFilterBanks; i++)
239                         {
240                             FilterBanks[i].Scale =
241                                 registers.CAN_FS1R.FilterScale(i);
242                         }
243                     }
244                     return;
245                 case registerOffset.CAN_FFA1R:
246                     if(registers.CAN_FMR.FilterInitMode == true)
247                     {
248                         registers.CAN_FFA1R.SetValue(value);
249                         for(int i = 0; i < NumberOfFilterBanks; i++)
250                         {
251                             FilterBanks[i].FifoAssignment =
252                                 registers.CAN_FFA1R.FifoAssignment(i);
253                         }
254                     }
255                     return;
256                 case registerOffset.CAN_FA1R:
257                     registers.CAN_FA1R.SetValue(value);
258                     for(int i = 0; i < NumberOfFilterBanks; i++)
259                     {
260                         FilterBanks[i].Active =
261                             registers.CAN_FA1R.FilterActive(i);
262                     }
263                     for(uint fifo = 0; fifo < NumberOfRxFifos; fifo++)
264                     {
265                         PrioritizeFiFoFilters(fifo);
266                     }
267                     return;
268 
269                 // TX mailbox 0
270                 case registerOffset.CAN_TI0R:
271                     registers.CAN_TI0R.SetValue(value);
272                     if(registers.CAN_TI0R.TransmitMailboxRequest(value) == true)
273                     {
274                         // Transmit data
275                         // registers.CAN_TDT0R = timestamp_me; FIXME
276                         CANMessage TxMsg = new CANMessage(registers.CAN_TI0R.GetValue(),
277                                                               registers.CAN_TDT0R,
278                                                               registers.CAN_TDL0R,
279                                                               registers.CAN_TDH0R);
280                         TransmitData(TxMsg);
281 
282                         // Transmition done
283                         registers.CAN_TSR.TxMailbox0Done();
284                         UpdateTransmitInterruptLine();
285                     }
286                     return;
287                 case registerOffset.CAN_TDT0R:
288                     registers.CAN_TDT0R = value;
289                     return;
290                 case registerOffset.CAN_TDL0R:
291                     registers.CAN_TDL0R = value;
292                     return;
293                 case registerOffset.CAN_TDH0R:
294                     registers.CAN_TDH0R = value;
295                     return;
296 
297                 // TX mailbox 1
298                 case registerOffset.CAN_TI1R:
299                     registers.CAN_TI1R.SetValue(value);
300                     if(registers.CAN_TI1R.TransmitMailboxRequest(value) == true)
301                     {
302                         // Transmit data
303                         // registers.CAN_TDT1R = timestamp_me; FIXME
304                         CANMessage TxMsg = new CANMessage(registers.CAN_TI1R.GetValue(),
305                                                               registers.CAN_TDT1R,
306                                                               registers.CAN_TDL1R,
307                                                               registers.CAN_TDH1R);
308                         TransmitData(TxMsg);
309 
310                         // Transmition done
311                         registers.CAN_TSR.TxMailbox1Done();
312                         UpdateTransmitInterruptLine();
313                     }
314                     return;
315                 case registerOffset.CAN_TDT1R:
316                     registers.CAN_TDT1R = value;
317                     return;
318                 case registerOffset.CAN_TDL1R:
319                     registers.CAN_TDL1R = value;
320                     return;
321                 case registerOffset.CAN_TDH1R:
322                     registers.CAN_TDH1R = value;
323                     return;
324 
325                 // TX mailbox 2
326                 case registerOffset.CAN_TI2R:
327                     registers.CAN_TI2R.SetValue(value);
328                     if(registers.CAN_TI2R.TransmitMailboxRequest(value) == true)
329                     {
330                         // Transmit data
331                         // registers.CAN_TDT2R = timestamp_me; FIXME
332                         CANMessage TxMsg = new CANMessage(registers.CAN_TI2R.GetValue(),
333                                                               registers.CAN_TDT2R,
334                                                               registers.CAN_TDL2R,
335                                                               registers.CAN_TDH2R);
336                         TransmitData(TxMsg);
337 
338                         // Transmition done
339                         registers.CAN_TSR.TxMailbox2Done();
340                         UpdateTransmitInterruptLine();
341                     }
342                     return;
343                 case registerOffset.CAN_TDT2R:
344                     registers.CAN_TDT2R = value;
345                     return;
346                 case registerOffset.CAN_TDL2R:
347                     registers.CAN_TDL2R = value;
348                     return;
349                 case registerOffset.CAN_TDH2R:
350                     registers.CAN_TDH2R = value;
351                     return;
352                 default:
353                     this.LogUnhandledWrite(address, value);
354                     return;
355             }
356         }
357 
TransmitData(CANMessage msg)358         public void TransmitData(CANMessage msg)
359         {
360             if(registers.CAN_BTR.SilentMode == false)
361             {
362                 if(FrameSent != null)
363                 {
364                     // Message frame created with receive identifier register
365                     // value because filtering can be implemented on bits other
366                     // than just standard/extended identifier value, e.g. IDE
367                     // or RTR bit.
368                     FrameSent(new CANMessageFrame(msg.CAN_RIR, msg.Data));
369                 }
370                 else
371                 {
372                     registers.CAN_ESR.SetLECBitDominantError();
373                     UpdateSCEInterruptLine();
374                 }
375             }
376             if(registers.CAN_BTR.LoopbackMode == true)
377             {
378                 for(int fifo = 0; fifo < NumberOfRxFifos; fifo++)
379                 {
380                     if(FilterCANMessage(fifo, msg) == true)
381                     {
382                         ReceiveCANMessage(msg);
383                     }
384                 }
385             }
386         }
387 
PrioritizeFiFoFilters(uint Fifo)388         public void PrioritizeFiFoFilters(uint Fifo)
389         {
390             uint FirstFilterNumber = 0;
391 
392             FifoFiltersPrioritized[Fifo].Clear();
393 
394             // Enumarate Fifo filters and add to priolist
395             for(int i = 0; i < NumberOfFilterBanks; i++)
396             {
397                 if(FilterBanks[i].FifoAssignment == Fifo)
398                 {
399                     FilterBanks[i].FirstFilterNumber = FirstFilterNumber;
400                     FirstFilterNumber += FilterBanks[i].NumberOfFiltersInBank();
401                     FifoFiltersPrioritized[Fifo].Add(FilterBanks[i]);
402                 }
403             }
404 
405             UpdateFilterCANAssignment();
406             FifoFiltersPrioritized[Fifo].Sort();
407         }
408 
UpdateFilterCANAssignment()409         public void UpdateFilterCANAssignment()
410         {
411             for(var i = 0; i < NumberOfFilterBanks; i++)
412             {
413                 FilterBanks[i].BelongsToMaster = i < registers.CAN_FMR.CAN2StartBank;
414             }
415         }
416 
FilterCANMessage(int RxFifo, CANMessage msg)417         public bool FilterCANMessage(int RxFifo, CANMessage msg)
418         {
419             foreach(FilterBank filterBank in FifoFiltersPrioritized[RxFifo].Where(m => m.BelongsToMaster == !IsSlave))
420             {
421                 if(filterBank.Active == true &&
422                         filterBank.MatchMessage(msg) == true)
423                 {
424                     return true;
425                 }
426             }
427             return false;
428         }
429 
ReceiveCANMessage(CANMessage msg)430         public void ReceiveCANMessage(CANMessage msg)
431         {
432             if(msg.RxFifo < NumberOfRxFifos)
433             {
434                 bool LockedMode = registers.CAN_MCR.RxFifoLockedMode;
435                 registers.CAN_RFR[msg.RxFifo].ReceiveMessage(msg, LockedMode);
436 
437                 if(registers.CAN_RFR[msg.RxFifo].UpdateInterruptLine != null)
438                 {
439                     registers.CAN_RFR[msg.RxFifo].UpdateInterruptLine();
440                 }
441             }
442         }
443 
UpdateTransmitInterruptLine()444         public void UpdateTransmitInterruptLine()
445         {
446             // Transmit interrupt
447             if(EnableTransmitInterrupt() == true)
448             {
449                 Connections[CAN_Tx].Set();
450             }
451             else
452             {
453                 Connections[CAN_Tx].Unset();
454             }
455         }
456 
UpdateInterruptLine()457         public delegate void UpdateInterruptLine();
458 
UpdateFifo0InterruptLine()459         public void UpdateFifo0InterruptLine()
460         {
461             // Fifo0 interrupt
462             if(EnableFifo0Interrupt() == true)
463             {
464                 Connections[CAN_Rx0].Set();
465             }
466             else
467             {
468                 Connections[CAN_Rx0].Unset();
469             }
470         }
471 
UpdateFifo1InterruptLine()472         public void UpdateFifo1InterruptLine()
473         {
474             // Fifo1 interrupt
475             if(EnableFifo1Interrupt() == true)
476             {
477                 Connections[CAN_Rx1].Set();
478             }
479             else
480             {
481                 Connections[CAN_Rx1].Unset();
482             }
483         }
484 
UpdateSCEInterruptLine()485         public void UpdateSCEInterruptLine()
486         {
487             // Error and status change interrupt
488             if(EnableSCEInterrupt() == true)
489             {
490                 Connections[CAN_SCE].Set();
491             }
492             else
493             {
494                 Connections[CAN_SCE].Unset();
495             }
496         }
497 
EnableTransmitInterrupt()498         public bool EnableTransmitInterrupt()
499         {
500             if(registers.CAN_IER.TMEInterruptEnabled == true &&
501                 registers.CAN_TSR.MailboxRequestCompleted() == true)
502             {
503                 return true;
504             }
505             return false;
506         }
507 
EnableFifo0Interrupt()508         public bool EnableFifo0Interrupt()
509         {
510             // Check pending message
511             if(registers.CAN_IER.FMP0InterruptEnabled == true &&
512                 registers.CAN_RFR[RxFifo0].HasMessagesPending() == true)
513             {
514                 return true;
515             }
516             // Check Fifo0 full
517             if(registers.CAN_IER.FF0InterruptEnabled == true &&
518                 registers.CAN_RFR[RxFifo0].FifoFull == true)
519             {
520                 return true;
521             }
522             // Check Fifo0 overrun
523             if(registers.CAN_IER.FOV0InterruptEnabled == true &&
524                 registers.CAN_RFR[RxFifo0].FifoOverrun == true)
525             {
526                 return true;
527             }
528             return false;
529         }
530 
EnableFifo1Interrupt()531         public bool EnableFifo1Interrupt()
532         {
533             // Check pending message
534             if(registers.CAN_IER.FMP1InterruptEnabled == true &&
535                 registers.CAN_RFR[RxFifo1].HasMessagesPending() == true)
536             {
537                 return true;
538             }
539             // Check Fifo1 full
540             if(registers.CAN_IER.FF1InterruptEnabled == true &&
541                 registers.CAN_RFR[RxFifo1].FifoFull == true)
542             {
543                 return true;
544             }
545             // Check Fifo1 overrun
546             if(registers.CAN_IER.FOV1InterruptEnabled == true &&
547                 registers.CAN_RFR[RxFifo1].FifoOverrun == true)
548             {
549                 return true;
550             }
551             return false;
552         }
553 
EnableSCEInterrupt()554         public bool EnableSCEInterrupt()
555         {
556             // An error condition is pending
557             if(registers.CAN_IER.ERRInterruptEnabled == true &&
558                 registers.CAN_MSR.ErrorInterrupt == true)
559             {
560                 return true;
561             }
562             // Error warning interrupt
563             if(registers.CAN_IER.EWGInterruptEnabled == true &&
564                 registers.CAN_ESR.ErrorWarningFlag == true)
565             {
566                 return true;
567             }
568             // Error passive interrupt
569             if(registers.CAN_IER.EPVInterruptEnabled == true &&
570                 registers.CAN_ESR.ErrorPassiveFlag == true)
571             {
572                 return true;
573             }
574             // Error passive interrupt
575             if(registers.CAN_IER.BOFInterruptEnabled == true &&
576                 registers.CAN_ESR.BusOffFlag == true)
577             {
578                 return true;
579             }
580             // LEC Error pending
581             if(registers.CAN_IER.LECInterruptEnabled == true &&
582                 registers.CAN_ESR.LECErrorPending() == true)
583             {
584                 return true;
585             }
586             //  Sleep interrupt
587             if(registers.CAN_IER.SLKInterruptEnabled == true &&
588                 registers.CAN_MSR.SleepAckInterrupt == true)
589             {
590                 return true;
591             }
592             //  Wakup interrupt
593             if(registers.CAN_IER.WKUInterruptEnabled == true &&
594                 registers.CAN_MSR.WakeupInterrupt == true)
595             {
596                 return true;
597             }
598             return false;
599         }
600 
AddressToFilterBankIdx(long address)601         public int AddressToFilterBankIdx(long address)
602         {
603             // Filter bank has a size of 2 * uint
604             return (int)(address - (long)registerOffset.CAN_F0R1) / (2 * sizeof(uint));
605         }
606 
AddressToRegIdx(long address)607         public int AddressToRegIdx(long address)
608         {
609             return (int)((address - (long)registerOffset.CAN_F0R1) / sizeof(uint)) % 2;
610         }
611 
ReadDoubleWord(long offset)612         public uint ReadDoubleWord(long offset)
613         {
614             uint Retval = 0;
615 
616             if(IsSlave && AddressIsWithinFilterRegistersArea(offset))
617             {
618                 this.Log(LogLevel.Warning, "Trying to read slave's filter registers, but the slave uses master's filter registers - reading from master instead.");
619             }
620 
621             // Filter bank registers
622             if((registerOffset)offset >= registerOffset.CAN_F0R1 && (registerOffset)offset <= registerOffset.CAN_F27R2)
623             {
624                 int bankIdx = AddressToFilterBankIdx(offset);
625                 int regIdx = AddressToRegIdx(offset);
626                 //Retval = registers.CAN_FiRx[RegIdx];
627                 Retval = FilterBanks[bankIdx].FR[regIdx];
628             }
629             else
630             {
631                 switch((registerOffset)offset)
632                 {
633                     case registerOffset.CAN_MCR:
634                         Retval = registers.CAN_MCR.GetValue();
635                         break;
636                     case registerOffset.CAN_MSR:
637                         Retval = registers.CAN_MSR.GetValue();
638                         break;
639                     case registerOffset.CAN_TSR:
640                         Retval = registers.CAN_TSR.GetValue();
641                         break;
642                     case registerOffset.CAN_RF0R:
643                         Retval = registers.CAN_RFR[RxFifo0].GetValue();
644                         break;
645                     case registerOffset.CAN_RF1R:
646                         Retval = registers.CAN_RFR[RxFifo1].GetValue();
647                         break;
648                     case registerOffset.CAN_IER:
649                         Retval = registers.CAN_IER.GetValue();
650                         break;
651                     case registerOffset.CAN_ESR:
652                         Retval = registers.CAN_ESR.GetValue();
653                         break;
654                     case registerOffset.CAN_BTR:
655                         if(registers.CAN_MSR.InitAck == true)
656                         {
657                             Retval = registers.CAN_BTR.GetValue();
658                         }
659                         break;
660 
661                     // Filter registers
662                     case registerOffset.CAN_FMR:
663                         Retval = registers.CAN_FMR.GetValue();
664                         break;
665                     case registerOffset.CAN_FM1R:
666                         Retval = registers.CAN_FM1R.GetValue();
667                         break;
668                     case registerOffset.CAN_FS1R:
669                         Retval = registers.CAN_FS1R.GetValue();
670                         break;
671                     case registerOffset.CAN_FFA1R:
672                         Retval = registers.CAN_FFA1R.GetValue();
673                         break;
674                     case registerOffset.CAN_FA1R:
675                         Retval = registers.CAN_FA1R.GetValue();
676                         break;
677 
678                     // TX mailboxes 0
679                     case registerOffset.CAN_TI0R:
680                         Retval = registers.CAN_TI0R.GetValue();
681                         break;
682                     case registerOffset.CAN_TDT0R:
683                         Retval = registers.CAN_TDT0R;
684                         break;
685                     case registerOffset.CAN_TDL0R:
686                         Retval = registers.CAN_TDL0R;
687                         break;
688                     case registerOffset.CAN_TDH0R:
689                         Retval = registers.CAN_TDH0R;
690                         break;
691 
692                     // TX mailboxes 1
693                     case registerOffset.CAN_TI1R:
694                         Retval = registers.CAN_TI1R.GetValue();
695                         break;
696                     case registerOffset.CAN_TDT1R:
697                         Retval = registers.CAN_TDT1R;
698                         break;
699                     case registerOffset.CAN_TDL1R:
700                         Retval = registers.CAN_TDL1R;
701                         break;
702                     case registerOffset.CAN_TDH1R:
703                         Retval = registers.CAN_TDH1R;
704                         break;
705 
706                     // TX mailboxes 2
707                     case registerOffset.CAN_TI2R:
708                         Retval = registers.CAN_TI2R.GetValue();
709                         break;
710                     case registerOffset.CAN_TDT2R:
711                         Retval = registers.CAN_TDT2R;
712                         break;
713                     case registerOffset.CAN_TDL2R:
714                         Retval = registers.CAN_TDL2R;
715                         break;
716                     case registerOffset.CAN_TDH2R:
717                         Retval = registers.CAN_TDH2R;
718                         break;
719 
720                     // RX mailbox 0
721                     case registerOffset.CAN_RI0R:
722                         if(registers.CAN_RFR[RxFifo0].HasMessagesPending() == true)
723                         {
724                             Retval = RxFifo[RxFifo0].Peek().CAN_RIR;
725                         }
726                         break;
727                     case registerOffset.CAN_RDT0R:
728                         if(registers.CAN_RFR[RxFifo0].HasMessagesPending() == true)
729                         {
730                             Retval = RxFifo[RxFifo0].Peek().CAN_RDTR;
731                         }
732                         break;
733                     case registerOffset.CAN_RL0R:
734                         if(registers.CAN_RFR[RxFifo0].HasMessagesPending() == true)
735                         {
736                             Retval = RxFifo[RxFifo0].Peek().CAN_RLR;
737                         }
738                         break;
739                     case registerOffset.CAN_RH0R:
740                         if(registers.CAN_RFR[RxFifo0].HasMessagesPending() == true)
741                         {
742                             Retval = RxFifo[RxFifo0].Peek().CAN_RHR;
743                         }
744                         break;
745 
746                     // RX mailboxes 1
747                     case registerOffset.CAN_RI1R:
748                         if(registers.CAN_RFR[RxFifo1].HasMessagesPending() == true)
749                         {
750                             Retval = RxFifo[RxFifo1].Peek().CAN_RIR;
751                         }
752                         break;
753                     case registerOffset.CAN_RDT1R:
754                         if(registers.CAN_RFR[RxFifo1].HasMessagesPending() == true)
755                         {
756                             Retval = RxFifo[RxFifo1].Peek().CAN_RDTR;
757                         }
758                         break;
759                     case registerOffset.CAN_RL1R:
760                         if(registers.CAN_RFR[RxFifo1].HasMessagesPending() == true)
761                         {
762                             Retval = RxFifo[RxFifo1].Peek().CAN_RLR;
763                         }
764                         break;
765                     case registerOffset.CAN_RH1R:
766                         if(registers.CAN_RFR[RxFifo1].HasMessagesPending() == true)
767                         {
768                             Retval = RxFifo[RxFifo1].Peek().CAN_RHR;
769                         }
770                         break;
771 
772                     default:
773                         this.LogUnhandledRead(offset);
774                         break;
775                 }
776             }
777 
778             return Retval;
779         }
780 
Reset()781         public void Reset()
782         {
783             registers.Reset(!IsSlave);
784 
785             if(!IsSlave)
786             {
787                 for(int i = 0; i < NumberOfFilterBanks; i++)
788                 {
789                     FilterBanks[i].Active = false;
790                     FilterBanks[i].Mode = FilterBankMode.FilterModeIdMask;
791                     FilterBanks[i].FifoAssignment = 0;
792                     FilterBanks[i].Scale = FilterBankScale.FilterScale16Bit;
793                 }
794                 UpdateFilterCANAssignment();
795             }
796         }
797 
798         public bool IsSlave => master != null;
799 
AddressIsWithinFilterRegistersArea(long address)800         private bool AddressIsWithinFilterRegistersArea(long address)
801         {
802             return (registerOffset)address >= registerOffset.CAN_FMR
803                 && (registerOffset)address <= registerOffset.CAN_F27R2;
804         }
805 
806         private enum registerOffset : uint
807         {
808             CAN_MCR = 0x00,
809             CAN_MSR = 0x04,
810             CAN_TSR = 0x08,
811             CAN_RF0R = 0x0C,
812             CAN_RF1R = 0x10,
813             CAN_IER = 0x14,
814             CAN_ESR = 0x18,
815             CAN_BTR = 0x1C,
816 
817             // TX mailboxes
818             CAN_TI0R = 0x180,
819             CAN_TDT0R = 0x184,
820             CAN_TDL0R = 0x188,
821             CAN_TDH0R = 0x18C,
822 
823             CAN_TI1R = 0x190,
824             CAN_TDT1R = 0x194,
825             CAN_TDL1R = 0x198,
826             CAN_TDH1R = 0x19C,
827 
828             CAN_TI2R = 0x1A0,
829             CAN_TDT2R = 0x1A4,
830             CAN_TDL2R = 0x1A8,
831             CAN_TDH2R = 0x1AC,
832 
833             // RX mailboxes
834             CAN_RI0R = 0x1B0,
835             CAN_RDT0R = 0x1B4,
836             CAN_RL0R = 0x1B8,
837             CAN_RH0R = 0x1BC,
838 
839             CAN_RI1R = 0x1C0,
840             CAN_RDT1R = 0x1C4,
841             CAN_RL1R = 0x1C8,
842             CAN_RH1R = 0x1CC,
843 
844             // Filter registers
845             CAN_FMR = 0x200,
846             CAN_FM1R = 0x204,
847             CAN_FS1R = 0x20C,
848             CAN_FFA1R = 0x214,
849             CAN_FA1R = 0x21C,
850 
851             // Filter bank registers
852             CAN_F0R1 = 0x240,
853             CAN_F27R2 = 0x31C,
854         }
855 
856         public enum FilterBankScale
857         {
858             FilterScale16Bit,
859             FilterScale32Bit
860         }
861 
862         public enum FilterBankMode
863         {
864             FilterModeIdMask,
865             FilterIdentifierList
866         }
867 
868         private class DeviceRegisters
869         {
870             // Constants
871             public const uint NUM_FILTERBANKS = 28;
872             public const uint NUM_FILTERBANK_REGS = 2 * NUM_FILTERBANKS;
873 
874             // Control registers
875             public MasterControlRegister CAN_MCR = new MasterControlRegister();
876             public MasterStatusRegister CAN_MSR = new MasterStatusRegister();
877             public TransmitStatusRegister CAN_TSR = new TransmitStatusRegister();
878             public ReceiveFifoRegister[] CAN_RFR = new ReceiveFifoRegister[NumberOfRxFifos];
879             public InterruptEnableRegister CAN_IER = new InterruptEnableRegister();
880             public ErrorStatusRegister CAN_ESR = new ErrorStatusRegister();
881             public BitTimingRegister CAN_BTR = new BitTimingRegister();
882 
883             // Filter registers
884             public FilterMasterRegister CAN_FMR = new FilterMasterRegister();
885             public FilterModeRegister CAN_FM1R = new FilterModeRegister();
886             public FilterScaleRegister CAN_FS1R = new FilterScaleRegister();
887             public FifoAssignmentRegister CAN_FFA1R = new FifoAssignmentRegister();
888             public FilterActiveRegister CAN_FA1R = new FilterActiveRegister();
889 
890             // Filter bank registers
891             public uint[] CAN_FiRx = new uint[NUM_FILTERBANK_REGS];
892 
893             // TX mailbox 0
894             public MailboxIdentifierRegister CAN_TI0R = new MailboxIdentifierRegister();
895             public uint CAN_TDT0R;
896             public uint CAN_TDL0R;
897             public uint CAN_TDH0R;
898 
899             // TX mailbox 1
900             public MailboxIdentifierRegister CAN_TI1R = new MailboxIdentifierRegister();
901             public uint CAN_TDT1R;
902             public uint CAN_TDL1R;
903             public uint CAN_TDH1R;
904 
905             // TX mailbox 2
906             public MailboxIdentifierRegister CAN_TI2R = new MailboxIdentifierRegister();
907             public uint CAN_TDT2R;
908             public uint CAN_TDL2R;
909             public uint CAN_TDH2R;
910 
DeviceRegisters()911             public DeviceRegisters()
912             {
913                 for(int i = 0; i < NumberOfRxFifos; i++)
914                 {
915                     CAN_RFR[i] = new ReceiveFifoRegister();
916                 }
917             }
918 
Reset(bool resetFilters = true)919             public void Reset(bool resetFilters = true)
920             {
921                 CAN_MCR.SetValue(0x00010002);
922                 CAN_MSR.SetResetValue(0x00000C02);
923                 CAN_TSR.SetResetValue(0x1C000000);
924                 CAN_RFR[RxFifo0].SetValue(0x0);
925                 CAN_RFR[RxFifo1].SetValue(0x0);
926                 CAN_IER.SetValue(0x0);
927                 CAN_ESR.SetResetValue(0x0);
928                 CAN_BTR.SetValue(0x01230000);
929 
930                 if(resetFilters)
931                 {
932                     // Filter Registers
933                     CAN_FMR.SetValue(0x2A1C0E01);
934                     CAN_FM1R.SetValue(0x0);
935                     CAN_FS1R.SetValue(0x0);
936                     CAN_FFA1R.SetValue(0x0);
937                     CAN_FA1R.SetValue(0x0);
938                 }
939             }
940 
941             public class MasterControlRegister
942             {
943                 public const uint DBF   = (1u << 16);
944                 public const uint RESET = (1u << 15);
945                 public const uint TTCM  = (1u << 7);
946                 public const uint ABOM  = (1u << 6);
947                 public const uint AWUM  = (1u << 5);
948                 public const uint NART  = (1u << 4);
949                 public const uint RFLM  = (1u << 3);
950                 public const uint TXFP  = (1u << 2);
951                 public const uint SLEEP = (1u << 1);
952                 public const uint INRQ  = (1u << 0);
953 
954                 public bool DebugFreeze;
955                 public bool Reset;
956                 public bool TimeTriggeredComMode;
957                 public bool AutoBusOffManagement;
958                 public bool AutoWakeUpMode;
959                 public bool NoAutoRetransmission;
960                 public bool RxFifoLockedMode;
961                 public bool TxFifoPriority;
962                 public bool SleepRequest;
963                 public bool InitRequest;
964 
SetValue(uint value)965                 public void SetValue(uint value)
966                 {
967                     DebugFreeze          = (value & DBF)   != 0;
968                     Reset                = (value & RESET) != 0;
969                     TimeTriggeredComMode = (value & TTCM)  != 0;
970                     AutoBusOffManagement = (value & ABOM)  != 0;
971                     AutoWakeUpMode       = (value & AWUM)  != 0;
972                     NoAutoRetransmission = (value & NART)  != 0;
973                     RxFifoLockedMode     = (value & RFLM)  != 0;
974                     TxFifoPriority       = (value & TXFP)  != 0;
975                     SleepRequest         = (value & SLEEP) != 0;
976                     InitRequest          = (value & INRQ)  != 0;
977                 }
978 
GetValue()979                 public uint GetValue()
980                 {
981                     var retVal =
982                         (DebugFreeze           ? DBF   : 0) |
983                         (TimeTriggeredComMode  ? TTCM  : 0) |
984                         (AutoBusOffManagement  ? ABOM  : 0) |
985                         (AutoWakeUpMode        ? AWUM  : 0) |
986                         (NoAutoRetransmission  ? NART  : 0) |
987                         (RxFifoLockedMode      ? RFLM  : 0) |
988                         (TxFifoPriority        ? TXFP  : 0) |
989                         (SleepRequest          ? SLEEP : 0) |
990                         (InitRequest ? INRQ : 0);
991                     return retVal;
992                 }
993             }
994 
995             public class MasterStatusRegister
996             {
997                 public const uint RX    = (1u << 11);
998                 public const uint SAMP  = (1u << 10);
999                 public const uint RXM   = (1u << 9);
1000                 public const uint TXM   = (1u << 8);
1001                 public const uint SLAKI = (1u << 4);
1002                 public const uint WKUI  = (1u << 3);
1003                 public const uint ERRI  = (1u << 2);
1004                 public const uint SLAK  = (1u << 1);
1005                 public const uint INAK  = (1u << 0);
1006 
1007                 public bool RxSignal;
1008                 public bool LastSamplePoint;
1009                 public bool RxMode;
1010                 public bool TxMode;
1011                 public bool SleepAckInterrupt;
1012                 public bool WakeupInterrupt;
1013                 public bool ErrorInterrupt;
1014                 public bool SleepAck;
1015                 public bool InitAck;
1016 
SetResetValue(uint value)1017                 public void SetResetValue(uint value)
1018                 {
1019                     RxSignal          = (value & RX)    != 0;
1020                     LastSamplePoint   = (value & SAMP)  != 0;
1021                     RxMode            = (value & RXM)   != 0;
1022                     TxMode            = (value & TXM)   != 0;
1023                     SleepAckInterrupt = (value & SLAKI) != 0;
1024                     WakeupInterrupt   = (value & WKUI)  != 0;
1025                     ErrorInterrupt    = (value & ERRI)  != 0;
1026                     SleepAck          = (value & SLAK)  != 0;
1027                     InitAck           = (value & INAK)  != 0;
1028                 }
1029 
SetValue(uint value)1030                 public void SetValue(uint value)
1031                 {
1032                     if((value & SLAKI) != 0)
1033                     {
1034                         SleepAckInterrupt = false;
1035                     }
1036                     if((value & WKUI) != 0)
1037                     {
1038                         WakeupInterrupt = false;
1039                     }
1040                     if((value & ERRI) != 0)
1041                     {
1042                         ErrorInterrupt = false;
1043                     }
1044                 }
1045 
GetValue()1046                 public uint GetValue()
1047                 {
1048                     var retVal =
1049                         (RxSignal          ? RX    : 0) |
1050                         (LastSamplePoint   ? SAMP  : 0) |
1051                         (RxMode            ? RXM   : 0) |
1052                         (TxMode            ? TXM   : 0) |
1053                         (SleepAckInterrupt ? SLAKI : 0) |
1054                         (WakeupInterrupt   ? WKUI  : 0) |
1055                         (ErrorInterrupt    ? ERRI  : 0) |
1056                         (SleepAck          ? SLAK  : 0) |
1057                         (InitAck           ? INAK  : 0);
1058                     return retVal;
1059                 }
1060             }
1061 
1062             public class ReceiveFifoRegister
1063             {
1064                 public const uint MaxMessagesInFifo = 3;
1065                 public const uint FULL = (1u << 3);
1066                 public const uint FOVR = (1u << 4);
1067                 public const uint RFOM = (1u << 5);
1068                 public const uint FMPMASK = 0x3;
1069 
1070                 public bool FifoFull = false;
1071                 public bool FifoOverrun = false;
1072                 public uint FifoMessagesPending = 0;
1073                 private Queue<CANMessage> RxFifo;
1074 
1075                 public UpdateInterruptLine UpdateInterruptLine;
1076 
SetRxFifo(Queue<CANMessage> RxFifo)1077                 public void SetRxFifo(Queue<CANMessage> RxFifo)
1078                 {
1079                     this.RxFifo = RxFifo;
1080                 }
1081 
SetValue(uint value)1082                 public void SetValue(uint value)
1083                 {
1084                     if((value & FULL) != 0)
1085                     {
1086                         FifoFull = false;
1087                     }
1088                     if((value & FOVR) != 0)
1089                     {
1090                         FifoOverrun = false;
1091                     }
1092                     if((value & RFOM) != 0)
1093                     {
1094                         if(RxFifo.Count > 0)
1095                         {
1096                             RxFifo.Dequeue();
1097                         }
1098                     }
1099                     if(UpdateInterruptLine != null)
1100                         UpdateInterruptLine();
1101                 }
1102 
GetValue()1103                 public uint GetValue()
1104                 {
1105                     var retVal =
1106                         (FifoFull    ? FULL : 0) |
1107                         (FifoOverrun ? FOVR : 0) |
1108                         ((uint)RxFifo.Count & FMPMASK);
1109                     return retVal;
1110                 }
1111 
HasMessagesPending()1112                 public bool HasMessagesPending()
1113                 {
1114                     return (RxFifo.Count > 0);
1115                 }
1116 
FifoEmpty()1117                 public bool FifoEmpty()
1118                 {
1119                     return (RxFifo.Count == 0);
1120                 }
1121 
ReceiveMessage(CANMessage msg, bool RxFifoLockedMode)1122                 public void ReceiveMessage(CANMessage msg, bool RxFifoLockedMode)
1123                 {
1124                     if(RxFifo.Count < 3)
1125                     {
1126                         RxFifo.Enqueue(msg);
1127                         if(RxFifo.Count == MaxMessagesInFifo)
1128                         {
1129                             FifoFull = true;
1130                         }
1131                     }
1132                     else if(RxFifoLockedMode == false)
1133                     {
1134                         // Keep 3 newest messages in queue and signal overrun
1135                         RxFifo.Dequeue();
1136                         RxFifo.Enqueue(msg);
1137                         FifoOverrun = true;
1138                     }
1139                     else
1140                     {
1141                         // Keep 3 oldest messages in queue and signal overrun
1142                         FifoOverrun = true;
1143                     }
1144                 }
1145             }
1146 
1147             public class InterruptEnableRegister
1148             {
1149                 public const uint TMEIE  = (1u << 0);
1150                 public const uint FMPIE0 = (1u << 1);
1151                 public const uint FFIE0  = (1u << 2);
1152                 public const uint FOVIE0 = (1u << 3);
1153                 public const uint FMPIE1 = (1u << 4);
1154                 public const uint FFIE1  = (1u << 5);
1155                 public const uint FOVIE1 = (1u << 6);
1156                 public const uint EWGIE  = (1u << 8);
1157                 public const uint EPVIE  = (1u << 9);
1158                 public const uint BOFIE  = (1u << 10);
1159                 public const uint LECIE  = (1u << 11);
1160                 public const uint ERRIE  = (1u << 15);
1161                 public const uint WKUIE  = (1u << 16);
1162                 public const uint SLKIE  = (1u << 17);
1163 
1164                 public bool TMEInterruptEnabled;
1165                 public bool FMP0InterruptEnabled;
1166                 public bool FF0InterruptEnabled;
1167                 public bool FOV0InterruptEnabled;
1168                 public bool FMP1InterruptEnabled;
1169                 public bool FF1InterruptEnabled;
1170                 public bool FOV1InterruptEnabled;
1171                 public bool EWGInterruptEnabled;
1172                 public bool EPVInterruptEnabled;
1173                 public bool BOFInterruptEnabled;
1174                 public bool LECInterruptEnabled;
1175                 public bool ERRInterruptEnabled;
1176                 public bool WKUInterruptEnabled;
1177                 public bool SLKInterruptEnabled;
1178 
SetValue(uint value)1179                 public void SetValue(uint value)
1180                 {
1181                     TMEInterruptEnabled  = (value & TMEIE)  != 0;
1182                     FMP0InterruptEnabled = (value & FMPIE0) != 0;
1183                     FF0InterruptEnabled  = (value & FFIE0)  != 0;
1184                     FOV0InterruptEnabled = (value & FOVIE0) != 0;
1185                     FMP1InterruptEnabled = (value & FMPIE1) != 0;
1186                     FF1InterruptEnabled  = (value & FFIE1)  != 0;
1187                     FOV1InterruptEnabled = (value & FOVIE1) != 0;
1188                     EWGInterruptEnabled  = (value & EWGIE)  != 0;
1189                     EPVInterruptEnabled  = (value & EPVIE)  != 0;
1190                     BOFInterruptEnabled  = (value & BOFIE)  != 0;
1191                     LECInterruptEnabled  = (value & LECIE)  != 0;
1192                     ERRInterruptEnabled  = (value & ERRIE)  != 0;
1193                     WKUInterruptEnabled  = (value & WKUIE)  != 0;
1194                     SLKInterruptEnabled  = (value & SLKIE)  != 0;
1195                 }
1196 
GetValue()1197                 public uint GetValue()
1198                 {
1199                     var retVal =
1200                         (TMEInterruptEnabled  ? TMEIE  : 0) |
1201                         (FMP0InterruptEnabled ? FMPIE0 : 0) |
1202                         (FF0InterruptEnabled  ? FFIE0  : 0) |
1203                         (FOV0InterruptEnabled ? FOVIE0 : 0) |
1204                         (FMP1InterruptEnabled ? FMPIE1 : 0) |
1205                         (FF1InterruptEnabled  ? FFIE1  : 0) |
1206                         (FOV1InterruptEnabled ? FOVIE1 : 0) |
1207                         (EWGInterruptEnabled  ? EWGIE  : 0) |
1208                         (EPVInterruptEnabled  ? EPVIE  : 0) |
1209                         (BOFInterruptEnabled  ? BOFIE  : 0) |
1210                         (LECInterruptEnabled  ? LECIE  : 0) |
1211                         (ERRInterruptEnabled  ? ERRIE  : 0) |
1212                         (WKUInterruptEnabled  ? WKUIE  : 0) |
1213                         (SLKInterruptEnabled  ? SLKIE  : 0);
1214                     return retVal;
1215                 }
1216             }
1217 
1218             public class ErrorStatusRegister
1219             {
1220                 public const uint EWGF = (1u << 0);
1221                 public const uint EPVF = (1u << 1);
1222                 public const uint BOFF = (1u << 2);
1223 
1224                 public const int LECSHIFT = 4;
1225                 public const uint LECMASK = 0x7;
1226                 public const int TECSHIFT = 16;
1227                 public const uint TECMASK = 0xFF;
1228                 public const int RECSHIFT = 24;
1229                 public const uint RECMASK = 0xFF;
1230 
1231                 public const uint LECNoError = 0x0;
1232                 public const uint LECBitDominantError = 0x5;
1233                 public const uint LECSetBySoftware = 0x7;
1234 
1235                 public bool ErrorWarningFlag;
1236                 public bool ErrorPassiveFlag;
1237                 public bool BusOffFlag;
1238 
1239                 public uint LastErrorCode;
1240                 public uint TransmitErrorCounter;
1241                 public uint ReceiveErrorCounter;
1242 
SetResetValue(uint value)1243                 public void SetResetValue(uint value)
1244                 {
1245                     ErrorWarningFlag = (value & EWGF) != 0;
1246                     ErrorPassiveFlag = (value & EPVF) != 0;
1247                     BusOffFlag = (value & BOFF) != 0;
1248                     LastErrorCode = (value >> LECSHIFT) & LECMASK;
1249                     TransmitErrorCounter = (value >> TECSHIFT) & TECMASK;
1250                     ReceiveErrorCounter = (value >> RECSHIFT) & RECMASK;
1251                 }
1252 
SetValue(uint value)1253                 public void SetValue(uint value)
1254                 {
1255                     LastErrorCode = (value >> LECSHIFT) & LECMASK;
1256                     TransmitErrorCounter = (value >> TECSHIFT) & TECMASK;
1257                     ReceiveErrorCounter = (value >> RECSHIFT) & RECMASK;
1258                 }
1259 
GetValue()1260                 public uint GetValue()
1261                 {
1262                     var retVal =
1263                         (ErrorWarningFlag ? EWGF : 0) |
1264                         (ErrorPassiveFlag ? EPVF : 0) |
1265                         (BusOffFlag      ? BOFF : 0) |
1266                         ((LastErrorCode & LECMASK) << LECSHIFT) |
1267                         ((TransmitErrorCounter & TECMASK) << TECSHIFT) |
1268                         ((ReceiveErrorCounter & RECMASK) << RECSHIFT);
1269                     return retVal;
1270                 }
1271 
SetLECBitDominantError()1272                 public void SetLECBitDominantError()
1273                 {
1274                     LastErrorCode = LECBitDominantError;
1275                 }
1276 
LECErrorPending()1277                 public bool LECErrorPending()
1278                 {
1279                     return (LastErrorCode > LECNoError) && (LastErrorCode < LECSetBySoftware);
1280                 }
1281             }
1282 
1283             public class BitTimingRegister
1284             {
1285                 public const uint SILM  = (1u << 31);
1286                 public const uint LBKM  = (1u << 30);
1287 
1288                 public bool SilentMode;
1289                 public bool LoopbackMode;
1290 
1291                 public uint RegValue;
1292 
SetValue(uint value)1293                 public void SetValue(uint value)
1294                 {
1295                     RegValue = value;
1296                     SilentMode = (value & SILM) != 0;
1297                     LoopbackMode = (value & LBKM) != 0;
1298                 }
1299 
GetValue()1300                 public uint GetValue()
1301                 {
1302                     return RegValue;
1303                 }
1304             }
1305 
1306             // CAN_TSR
1307             public class TransmitStatusRegister
1308             {
1309                 public const uint RQCP0 = (1u << 0);
1310                 public const uint TXOK0 = (1u << 1);
1311                 public const uint ALST0 = (1u << 2);
1312                 public const uint TERR0 = (1u << 3);
1313                 public const uint ABRQ0 = (1u << 7);
1314 
1315                 public const uint RQCP1 = (1u << 8);
1316                 public const uint TXOK1 = (1u << 9);
1317                 public const uint ALST1 = (1u << 10);
1318                 public const uint TERR1 = (1u << 11);
1319                 public const uint ABRQ1 = (1u << 15);
1320 
1321                 public const uint RQCP2 = (1u << 16);
1322                 public const uint TXOK2 = (1u << 17);
1323                 public const uint ALST2 = (1u << 18);
1324                 public const uint TERR2 = (1u << 19);
1325                 public const uint ABRQ2 = (1u << 23);
1326 
1327                 public const uint TME0  = (1u << 26);
1328                 public const uint TME1  = (1u << 27);
1329                 public const uint TME2  = (1u << 28);
1330 
1331                 private uint RegValue;
1332 
SetValue(uint value)1333                 public void SetValue(uint value)
1334                 {
1335                     if((value & TERR2) != 0)
1336                     {
1337                         RegValue &= ~(TERR2);
1338                     }
1339                     if((value & ALST2) != 0)
1340                     {
1341                         RegValue &= ~(ALST2);
1342                     }
1343                     if((value & TXOK2) != 0)
1344                     {
1345                         RegValue &= ~(TXOK2);
1346                     }
1347                     if((value & TERR1) != 0)
1348                     {
1349                         RegValue &= ~(TERR1);
1350                     }
1351                     if((value & ALST1) != 0)
1352                     {
1353                         RegValue &= ~(ALST1);
1354                     }
1355                     if((value & TXOK1) != 0)
1356                     {
1357                         RegValue &= ~(TXOK1);
1358                     }
1359                     if((value & TERR0) != 0)
1360                     {
1361                         RegValue &= ~(TERR1);
1362                     }
1363                     if((value & ALST0) != 0)
1364                     {
1365                         RegValue &= ~(ALST0);
1366                     }
1367                     if((value & TXOK0) != 0)
1368                     {
1369                         RegValue &= ~(TXOK0);
1370                     }
1371                     if((value & RQCP0) != 0)
1372                     {
1373                         RegValue &= ~(TXOK0 | ALST0 | TERR0 | RQCP0);
1374                     }
1375                     if((value & RQCP1) != 0)
1376                     {
1377                         RegValue &= ~(TXOK1 | ALST1 | TERR1 | RQCP1);
1378                     }
1379                     if((value & RQCP2) != 0)
1380                     {
1381                         RegValue &= ~(TXOK2 | ALST2 | TERR2 | RQCP2);
1382                     }
1383                 }
1384 
SetResetValue(uint value)1385                 public void SetResetValue(uint value)
1386                 {
1387                     RegValue = value;
1388                 }
1389 
GetValue()1390                 public uint GetValue()
1391                 {
1392                     return RegValue;
1393                 }
1394 
TxMailbox0Done()1395                 public void TxMailbox0Done()
1396                 {
1397                     RegValue |= (TME0 | TXOK0 | RQCP0);
1398                 }
1399 
TxMailbox1Done()1400                 public void TxMailbox1Done()
1401                 {
1402                     RegValue |= (TME1 | TXOK1 | RQCP1);
1403                 }
1404 
TxMailbox2Done()1405                 public void TxMailbox2Done()
1406                 {
1407                     RegValue |= (TME2 | TXOK2 | RQCP2);
1408                 }
1409 
ClearTxInterrupt(uint value)1410                 public bool ClearTxInterrupt(uint value)
1411                 {
1412                     return ((value & RQCP0) != 0);
1413                 }
1414 
MailboxRequestCompleted()1415                 public bool MailboxRequestCompleted()
1416                 {
1417                     var retVal =
1418                              ((RegValue & RQCP0) != 0) ||
1419                              ((RegValue & RQCP1) != 0) ||
1420                              ((RegValue & RQCP2) != 0);
1421                     return retVal;
1422                 }
1423             }
1424 
1425             public class FilterMasterRegister
1426             {
1427                 public const uint FINIT = (1u << 0);
1428 
1429                 public const int CAN2SBSHIFT = 8;
1430                 public const uint CAN2SBMASK = 0x3F;
1431 
1432                 public const int RESERVED1SHIFT = 14;
1433                 public const int RESERVED2SHIFT = 1;
1434                 public const uint RESERVED2MASK = 0x7F;
1435                 public const uint RESERVED1MASK = 0x3FFFF;
1436 
1437                 public bool FilterInitMode;
1438                 public uint CAN2StartBank;
1439                 public uint Reserved1;
1440                 public uint Reserved2;
1441 
SetValue(uint value)1442                 public void SetValue(uint value)
1443                 {
1444                     FilterInitMode = (value & FINIT) != 0;
1445                     CAN2StartBank = (value >> CAN2SBSHIFT) & CAN2SBMASK;
1446                     Reserved1 = (value >> RESERVED1SHIFT) & RESERVED1MASK;
1447                     Reserved2 = (value >> RESERVED2SHIFT) & RESERVED2MASK;
1448                 }
GetValue()1449                 public uint GetValue()
1450                 {
1451                     var retVal = (FilterInitMode ? FINIT : 0) |
1452                         ((CAN2StartBank & CAN2SBMASK) << CAN2SBSHIFT) |
1453                         ((Reserved1 & RESERVED1MASK) << RESERVED1SHIFT) |
1454                         ((Reserved2 & RESERVED2MASK) << RESERVED2SHIFT);
1455                     return retVal;
1456                 }
1457             }
1458 
1459             public class FilterActiveRegister
1460             {
1461                 public const uint REGMASK = 0xFFFFFFF;
1462 
1463                 private uint RegValue;
1464 
SetValue(uint value)1465                 public void SetValue(uint value)
1466                 {
1467                     RegValue = value & REGMASK;
1468                 }
1469 
GetValue()1470                 public uint GetValue()
1471                 {
1472                     return RegValue;
1473                 }
1474 
FilterActive(int filterIdx)1475                 public bool FilterActive(int filterIdx)
1476                 {
1477                     return (RegValue & (1u << filterIdx)) != 0;
1478                 }
1479             }
1480 
1481             public class FilterModeRegister
1482             {
1483                 private uint RegValue;
1484 
SetValue(uint value)1485                 public void SetValue(uint value)
1486                 {
1487                     RegValue = value;
1488                 }
1489 
GetValue()1490                 public uint GetValue()
1491                 {
1492                     return RegValue;
1493                 }
1494 
FilterMode(int filterIdx)1495                 public FilterBankMode FilterMode(int filterIdx)
1496                 {
1497                     if((RegValue & (1u << filterIdx)) != 0)
1498                     {
1499                         return FilterBankMode.FilterIdentifierList;
1500                     }
1501                     else
1502                     {
1503                         return FilterBankMode.FilterModeIdMask;
1504                     }
1505                 }
1506             }
1507 
1508             public class FilterScaleRegister
1509             {
1510                 private uint RegValue;
1511 
SetValue(uint value)1512                 public void SetValue(uint value)
1513                 {
1514                     RegValue = value;
1515                 }
1516 
GetValue()1517                 public uint GetValue()
1518                 {
1519                     return RegValue;
1520                 }
1521 
FilterScale(int filterIdx)1522                 public FilterBankScale FilterScale(int filterIdx)
1523                 {
1524                     if((RegValue & (1u << filterIdx)) != 0)
1525                     {
1526                         return FilterBankScale.FilterScale32Bit;
1527                     }
1528                     else
1529                     {
1530                         return FilterBankScale.FilterScale16Bit;
1531                     }
1532                 }
1533             }
1534 
1535             public class FifoAssignmentRegister
1536             {
1537                 private uint RegValue;
1538 
SetValue(uint value)1539                 public void SetValue(uint value)
1540                 {
1541                     RegValue = value;
1542                 }
1543 
GetValue()1544                 public uint GetValue()
1545                 {
1546                     return RegValue;
1547                 }
1548 
FifoAssignment(int filterIdx)1549                 public uint FifoAssignment(int filterIdx)
1550                 {
1551                     if((RegValue & (1u << filterIdx)) != 0)
1552                     {
1553                         return 1;
1554                     }
1555                     else
1556                     {
1557                         return 0;
1558                     }
1559                 }
1560             }
1561 
1562             public class MailboxIdentifierRegister
1563             {
1564 
1565                 public const uint TXRQ = (1u << 0);
1566                 private uint RegValue;
1567 
SetValue(uint value)1568                 public void SetValue(uint value)
1569                 {
1570                     RegValue = (value & 0xFFFFFFFE);
1571                 }
1572 
GetValue()1573                 public uint GetValue()
1574                 {
1575                     return RegValue;
1576                 }
1577 
TransmitMailboxRequest(uint value)1578                 public bool TransmitMailboxRequest(uint value)
1579                 {
1580                     return (value & TXRQ) != 0;
1581                 }
1582             }
1583         }
1584 
1585         public class CANMessage
1586         {
1587             public const int STIDSHIFT = 21;
1588             public const uint STIDMASK = 0x7FF;
1589             public const int EXIDSHIFT = 3;
1590             public const uint EXIDMASK = 0x3FFFF;
1591             public const int IDESHIFT = 2;
1592             public const uint IDEMASK = 0x1;
1593             public const int RTRSHIFT = 1;
1594             public const uint RTRMASK = 0x1;
1595 
1596             public const int TIMESHIFT = 16;
1597             public const uint TIMEMASK = 0xFFFF;
1598             public const int FMISHIFT = 8;
1599             public const uint FMIMASK = 0xFF;
1600             public const int DLCSHIFT = 0;
1601             public const uint DLCMASK = 0xF;
1602 
1603             public const uint RIRMASK =
1604                 (STIDMASK << STIDSHIFT) |
1605                 (EXIDMASK << EXIDSHIFT) |
1606                 (IDEMASK  << IDESHIFT)  |
1607                 (RTRMASK  << RTRSHIFT);
1608             public const uint RDTRMASK = (DLCMASK << DLCSHIFT);
1609 
1610             public uint CAN_RIR;
1611             public uint CAN_RDTR;
1612             public uint CAN_RLR;
1613             public uint CAN_RHR;
1614 
1615             public uint STID;
1616             public uint RTR;
1617             public uint IDE;
1618             public uint EXID;
1619             public uint DLC;
1620             public byte[] Data;
1621             public uint TimeStamp;
1622 
1623             public uint FilterMatchIndex;
1624             public uint RxFifo;
1625 
CANMessage(uint RIR, uint RDTR, uint RLR, uint RHR)1626             public CANMessage(uint RIR, uint RDTR, uint RLR, uint RHR)
1627             {
1628                 CAN_RIR = RIR & RIRMASK;
1629                 CAN_RDTR = RDTR & RDTRMASK;
1630                 CAN_RLR = RLR;
1631                 CAN_RHR = RHR;
1632 
1633                 // Not needed at Tx
1634                 //TimeStamp = (RDTR >> TIMESHIFT) & TIMEMASK;
1635 
1636                 ExtractRegisters();
1637             }
1638 
CANMessage(uint STID, uint EXID, uint RTR, uint IDE, uint DLC, byte[] Data, uint TimeStamp)1639             public CANMessage(uint STID, uint EXID, uint RTR,
1640                     uint IDE, uint DLC, byte[] Data, uint TimeStamp)
1641             {
1642                 this.STID = STID;
1643                 this.EXID = EXID;
1644                 this.RTR = RTR;
1645                 this.IDE = IDE;
1646                 this.DLC = DLC;
1647                 this.Data = Data;
1648                 this.TimeStamp = TimeStamp;
1649 
1650                 GenerateRegisters();
1651             }
1652 
CANMessage(CANMessageFrame message)1653             public CANMessage(CANMessageFrame message)
1654             {
1655                 CAN_RIR = (uint)message.Id & RIRMASK;
1656                 ExtractRIRRegister();
1657 
1658                 //this.TimeStamp = (Data[6] << 8) | Data[7];
1659                 this.DLC = (uint)message.Data.Length;
1660                 GenerateRDTRRegister();
1661 
1662                 this.Data = message.Data;
1663                 GenerateDataRegisters();
1664             }
1665 
GenerateRegisters()1666             public void GenerateRegisters()
1667             {
1668                 CAN_RIR =
1669                     ((STID & STIDMASK) << STIDSHIFT) |
1670                     ((EXID & EXIDMASK) << EXIDSHIFT) |
1671                     ((IDE  & IDEMASK)  << IDESHIFT)  |
1672                     ((RTR  & RTRMASK)  << RTRSHIFT);
1673 
1674                 GenerateRDTRRegister();
1675                 GenerateDataRegisters();
1676             }
1677 
GenerateRDTRRegister()1678             public void GenerateRDTRRegister()
1679             {
1680                 CAN_RDTR =
1681                     ((TimeStamp & TIMEMASK) << TIMESHIFT) |
1682                     ((FilterMatchIndex & FMIMASK) << FMISHIFT) |
1683                     ((DLC & DLCMASK) << DLCSHIFT);
1684             }
1685 
GenerateDataRegisters()1686             public void GenerateDataRegisters()
1687             {
1688                 var l = Data.Length;
1689                 CAN_RLR = 0U;
1690                 CAN_RLR |= (uint)((l > 0) ? Data[0] << 0  : 0);
1691                 CAN_RLR |= (uint)((l > 1) ? Data[1] << 8  : 0);
1692                 CAN_RLR |= (uint)((l > 2) ? Data[2] << 16 : 0);
1693                 CAN_RLR |= (uint)((l > 3) ? Data[3] << 24 : 0);
1694                 CAN_RHR = 0U;
1695                 CAN_RHR |= (uint)((l > 4) ? Data[4] << 0  : 0);
1696                 CAN_RHR |= (uint)((l > 5) ? Data[5] << 8  : 0);
1697                 CAN_RHR |= (uint)((l > 6) ? Data[6] << 16 : 0);
1698                 CAN_RHR |= (uint)((l > 7) ? Data[7] << 24 : 0);
1699             }
1700 
ExtractRegisters()1701             public void ExtractRegisters()
1702             {
1703                 ExtractRIRRegister();
1704                 ExtractRDTRRegister();
1705                 ExtractDataRegisters();
1706             }
1707 
ExtractRIRRegister()1708             public void ExtractRIRRegister()
1709             {
1710                 STID = (CAN_RIR >> STIDSHIFT) & STIDMASK;
1711                 EXID = (CAN_RIR >> EXIDSHIFT) & EXIDMASK;
1712                 IDE  = (CAN_RIR >> IDESHIFT) & IDEMASK;
1713                 RTR  = (CAN_RIR >> RTRSHIFT) & RTRMASK;
1714             }
1715 
ExtractRDTRRegister()1716             public void ExtractRDTRRegister()
1717             {
1718                 TimeStamp = (CAN_RDTR >> TIMESHIFT) & TIMEMASK;
1719                 DLC = (CAN_RDTR >> DLCSHIFT) & DLCMASK;
1720             }
1721 
ExtractDataRegisters()1722             public void ExtractDataRegisters()
1723             {
1724                 if(DLC > 0)
1725                 {
1726                     Data = new byte[DLC];
1727 
1728                     // Extract CAN_RLR
1729                     for(int i = 0; i < DLC && i < 4; i++)
1730                     {
1731                         Data[i] = (byte)((CAN_RLR >> (i * 8)) & 0xFF);
1732                     }
1733 
1734                     // Extract CAN_RHR
1735                     for(int i = 0; (i + 4) < DLC && i < 4; i++)
1736                     {
1737                         Data[i + 4] = (byte)((CAN_RHR >> (i * 8)) & 0xFF);
1738                     }
1739                 }
1740             }
1741         }
1742 
1743         public class Filter
1744         {
1745             public uint STID;
1746             public uint RTR;
1747             public uint IDE;
1748             public uint EXID;
1749             public uint EXIDMask;
1750         }
1751 
1752         public class FilterBank : IComparable<FilterBank>
1753         {
1754             public const int STIDSHIFT = 21;
1755             public const int STIDSHIFT2 = 5;
1756             public const uint STIDMASK = 0x7FF;
1757             public const uint STIDMASK2 = 0x7;
1758             public const int EXIDSHIFT = 3;
1759             public const int EXIDSHIFT2 = 16;
1760             public const int EXIDSHIFT3 = 0;
1761             public const int EXIDSHIFT4 = 15;
1762             public const uint EXIDMASK = 0x3FFFF;
1763             public const uint EXIDMASK2 = 0x7;
1764             public const int IDESHIFT = 2;
1765             public const int IDESHIFT2 = 20;
1766             public const int IDESHIFT3 = 4;
1767             public const uint IDEMASK = 0x1;
1768             public const int RTRSHIFT = 1;
1769             public const int RTRSHIFT2 = 19;
1770             public const int RTRSHIFT3 = 3;
1771             public const uint RTRMASK = 0x1;
1772 
1773             public bool Active;
1774             public FilterBankMode Mode;
1775             public FilterBankScale Scale;
1776             public uint FifoAssignment;
1777             public uint[] FR = new uint[2];
1778             public uint FirstFilterNumber;
1779             public bool BelongsToMaster;
1780 
FilterBank()1781             public FilterBank()
1782             {
1783                 Active = false;
1784                 Mode = FilterBankMode.FilterModeIdMask;
1785                 FifoAssignment = 0;
1786                 Scale = FilterBankScale.FilterScale16Bit;
1787                 BelongsToMaster = true;
1788             }
1789 
MatchMessage(CANMessage msg)1790             public bool MatchMessage(CANMessage msg)
1791             {
1792                 Filter[] filters = ExtractFilters();
1793                 int NumOfFilters = (Scale == FilterBankScale.FilterScale32Bit) ? 2 : 4;
1794                 uint FilterNumber = FirstFilterNumber;
1795 
1796                 if(Mode == FilterBankMode.FilterModeIdMask)
1797                 {
1798                     for(int i = 0; i < NumOfFilters / 2; i += 2, FilterNumber++)
1799                     {
1800                         int mask = i + 1;
1801                         if(
1802                                 ((filters[i].STID & filters[mask].STID) == (msg.STID & filters[mask].STID)) &&
1803                                 ((filters[i].EXID & filters[mask].EXID & filters[mask].EXIDMask) ==
1804                                  (msg.EXID & filters[mask].EXID & filters[mask].EXIDMask)) &&
1805                                 ((filters[i].IDE & filters[mask].IDE) == (msg.IDE & filters[mask].IDE)) &&
1806                                 ((filters[i].RTR & filters[mask].RTR) == (msg.RTR & filters[mask].RTR)) &&
1807                                 ((filters[i].STID & filters[mask].STID) == (msg.STID & filters[mask].STID))
1808                             )
1809                         {
1810                             msg.FilterMatchIndex = FilterNumber;
1811                             msg.RxFifo = FifoAssignment;
1812                             return true;
1813                         }
1814                     }
1815                 }
1816                 else
1817                 {
1818                     for(int i = 0; i < NumOfFilters; i++, FilterNumber++)
1819                     {
1820                         if(
1821                                 (filters[i].STID == msg.STID) &&
1822                                 ((filters[i].EXID & filters[i].EXIDMask) == (msg.EXID & filters[i].EXIDMask)) &&
1823                                 (filters[i].IDE == msg.IDE) &&
1824                                 (filters[i].RTR == msg.RTR)
1825                            )
1826                         {
1827                             msg.FilterMatchIndex = FilterNumber;
1828                             msg.RxFifo = FifoAssignment;
1829                             return true;
1830                         }
1831                     }
1832                 }
1833                 return false;
1834             }
1835 
ExtractFilters()1836             public Filter[] ExtractFilters()
1837             {
1838                 Filter[] filters;
1839 
1840                 if(Scale == FilterBankScale.FilterScale32Bit)
1841                 {
1842                     filters = new Filter[2];
1843                     for(int i = 0; i < 2; i++)
1844                     {
1845                         filters[i] = new Filter();
1846                         filters[i].STID = (FR[i] >> STIDSHIFT) & STIDMASK;
1847                         filters[i].EXID = (FR[i] >> EXIDSHIFT) & EXIDMASK;
1848                         filters[i].IDE  = (FR[i] >> IDESHIFT)  & IDEMASK;
1849                         filters[i].RTR  = (FR[i] >> RTRSHIFT)  & RTRMASK;
1850                         filters[i].EXIDMask = 0x3FFF;
1851                     }
1852                 }
1853                 else
1854                 {
1855                     filters = new Filter[4];
1856                     for(int i = 0; i < 4; i++)
1857                     {
1858                         filters[i] = new Filter();
1859                     }
1860                     filters[0].STID = (FR[0] >> STIDSHIFT) & STIDMASK;
1861                     filters[0].IDE  = (FR[0] >> IDESHIFT2) & IDEMASK;
1862                     filters[0].RTR  = (FR[0] >> RTRSHIFT2) & RTRMASK;
1863                     filters[0].EXID = ((FR[0] >> EXIDSHIFT2) & EXIDMASK2) << EXIDSHIFT4;
1864                     filters[0].EXIDMask = EXIDMASK2 << EXIDSHIFT4;
1865                     filters[1].STID = (FR[0] >> STIDSHIFT2) & STIDMASK;
1866                     filters[1].IDE  = (FR[0] >> IDESHIFT3) & IDEMASK;
1867                     filters[1].RTR  = (FR[0] >> RTRSHIFT3) & RTRMASK;
1868                     filters[1].EXID = ((FR[0] >> EXIDSHIFT3) & EXIDMASK2) << EXIDSHIFT4;
1869                     filters[1].EXIDMask = EXIDMASK2 << EXIDSHIFT4;
1870                     filters[2].STID = (FR[1] >> STIDSHIFT) & STIDMASK;
1871                     filters[2].IDE  = (FR[1] >> IDESHIFT2) & 0x1;
1872                     filters[2].RTR  = (FR[1] >> RTRSHIFT2) & 0x1;
1873                     filters[2].EXID = ((FR[1] >> EXIDSHIFT2) & EXIDMASK2) << EXIDSHIFT4;
1874                     filters[2].EXIDMask = EXIDMASK2 << EXIDSHIFT4;
1875                     filters[3].STID = (FR[1] >> STIDSHIFT2) & STIDMASK;
1876                     filters[3].IDE  = (FR[1] >> IDESHIFT3) & IDEMASK;
1877                     filters[3].RTR  = (FR[1] >> RTRSHIFT3) & RTRMASK;
1878                     filters[3].EXID = ((FR[1] >> EXIDSHIFT3) & EXIDMASK2) << EXIDSHIFT4;
1879                     filters[3].EXIDMask = EXIDMASK2 << EXIDSHIFT4;
1880                 }
1881 
1882                 return filters;
1883             }
1884 
CompareTo(FilterBank filterBank)1885             public int CompareTo(FilterBank filterBank)
1886             {
1887                 if(filterBank == null)
1888                     return 1;
1889 
1890                 // 32BitScale higher priority than 16BitScale
1891                 if(Scale > filterBank.Scale)
1892                     return 1;
1893 
1894                 // IdentifierList higher priority than IdMask
1895                 if(Mode > filterBank.Mode)
1896                     return 1;
1897 
1898                 // Lower FilterNumber has higher priority
1899                 if(FirstFilterNumber < filterBank.FirstFilterNumber)
1900                     return 1;
1901 
1902                 // Lower priority on this than filterBank
1903                 return -1;
1904             }
1905 
NumberOfFiltersInBank()1906             public uint NumberOfFiltersInBank()
1907             {
1908                 uint NumFiltersInBank = 4;
1909                 if(Scale == FilterBankScale.FilterScale32Bit)
1910                 {
1911                     NumFiltersInBank = 2;
1912                 }
1913                 if(Mode == FilterBankMode.FilterModeIdMask)
1914                 {
1915                     NumFiltersInBank /= 2;
1916                 }
1917                 return NumFiltersInBank;
1918             }
1919         }
1920 
1921         private readonly STMCAN master;
1922 
1923         private const int NumberOfInterruptLines = 4;
1924         private const int CAN_Tx = 0;
1925         private const int CAN_Rx0 = 1;
1926         private const int CAN_Rx1 = 2;
1927         private const int CAN_SCE = 3;
1928 
1929         private const int NumberOfRxFifos = 2;
1930         private const int RxFifo0 = 0;
1931         private const int RxFifo1 = 1;
1932         private const int NumberOfFilterBanks = 28;
1933 
1934         public event Action<CANMessageFrame> FrameSent;
1935         private DeviceRegisters registers;
1936         public IReadOnlyDictionary<int, IGPIO> Connections { get; private set; }
1937         private Queue<CANMessage>[] RxFifo = new Queue<CANMessage>[NumberOfRxFifos];
1938         public FilterBank[] FilterBanks;
1939         public List<FilterBank>[] FifoFiltersPrioritized = new List<FilterBank>[NumberOfRxFifos];
1940     }
1941 }
1942