1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Time;
16 using Antmicro.Renode.Utilities;
17 
18 namespace Antmicro.Renode.Peripherals.I2C
19 {
20     public class RenesasRA_IIC : SimpleContainer<II2CPeripheral>, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize
21     {
RenesasRA_IIC(IMachine machine)22         public RenesasRA_IIC(IMachine machine) : base(machine)
23         {
24             RegistersCollection = new ByteRegisterCollection(this);
25 
26             ReceiveIRQ = new GPIO();
27             TransmitIRQ = new GPIO();
28             TransmitEndIRQ = new GPIO();
29             ErrorOrEventIRQ = new GPIO();
30 
31             writeQueue = new Queue<byte>();
32             readQueue = new Queue<byte>();
33 
34             startCondition = new Condition(this, "Start", HandleStartCondition);
35             stopCondition = new Condition(this, "Stop", HandleStopCondition);
36             restartCondition = new Condition(this, "Restart", HandleRestartCondition);
37 
38             DefineRegisters();
39             Reset();
40         }
41 
ReadByte(long offset)42         public byte ReadByte(long offset)
43         {
44             return RegistersCollection.Read(offset);
45         }
46 
WriteByte(long offset, byte value)47         public void WriteByte(long offset, byte value)
48         {
49             RegistersCollection.Write(offset, value);
50         }
51 
Reset()52         public override void Reset()
53         {
54             RegistersCollection.Reset();
55             InternalReset();
56         }
57 
58         public ByteRegisterCollection RegistersCollection { get; }
59         public long Size => 0x20;
60 
61         public GPIO ReceiveIRQ { get; }
62         public GPIO TransmitIRQ { get; }
63         public GPIO TransmitEndIRQ { get; }
64         public GPIO ErrorOrEventIRQ { get; }
65 
DefineRegisters()66         private void DefineRegisters()
67         {
68             Registers.Control1.Define(this, 0x1F)
69                 .WithTaggedFlag("SDAI", 0)
70                 .WithTaggedFlag("SCLI", 1)
71                 .WithTaggedFlag("SDAO", 2)
72                 .WithTaggedFlag("SCLO", 3)
73                 .WithTaggedFlag("SOWP", 4)
74                 .WithTaggedFlag("CLO", 5)
75                 .WithFlag(6, out var iicReset, name: "IICRST")
76                 .WithFlag(7, out peripheralEnable, name: "ICE")
77                 .WithWriteCallback((_, __) =>
78                 {
79                     if(!iicReset.Value)
80                     {
81                         return;
82                     }
83 
84                     // Both IICRST and ICE fields are not affected by this reset operation.
85                     // See: Table 31.3 in RA6M5 Group User's Manual
86                     // We only need to save the value of ICE as we know IICRST is 1 here
87                     var peripheralEnableValue = peripheralEnable.Value;
88 
89                     if(peripheralEnable.Value)
90                     {
91                         InternalReset();
92                         this.DebugLog("Internal reset performed");
93                     }
94                     else
95                     {
96                         Reset();
97                         this.DebugLog("IIC reset performed");
98                     }
99 
100                     iicReset.Value = true;
101                     peripheralEnable.Value = peripheralEnableValue;
102                 });
103 
104             control2Register = Registers.Control2.Define(this)
105                 .WithReservedBits(0, 1)
106                 .WithFlag(1, out startCondition.RequestFlag, name: "ST",
107                     changeCallback: (_, __) =>
108                     {
109                         if(!startCondition.Requested)
110                         {
111                             return;
112                         }
113 
114                         if(!peripheralEnable.Value)
115                         {
116                             this.ErrorLog("Attempted to start transmission on a disabled peripheral, clearing the request");
117                             stopCondition.Requested = false;
118                             return;
119                         }
120 
121                         if(currentTransmissionState != TransmissionState.Idle)
122                         {
123                             this.WarningLog("Attempted to start a transaction while one is already running, clearing the request");
124                             startCondition.Requested = false;
125                             return;
126                         }
127 
128                         startCondition.TryPerform();
129                     })
130                 .WithFlag(2, out restartCondition.RequestFlag, name: "RS",
131                     changeCallback: (_, __) =>
132                     {
133                         if(!restartCondition.Requested)
134                         {
135                             return;
136                         }
137 
138                         if(!peripheralEnable.Value)
139                         {
140                             this.ErrorLog("Attempted to restart transmission on a disabled peripheral, clearing the request");
141                             restartCondition.Requested = false;
142                             return;
143                         }
144 
145                         // When reading the condition will be generated after the last read has been performed
146                         if(currentTransmissionState != TransmissionState.Read)
147                         {
148                             restartCondition.TryPerform();
149                         }
150                     })
151                 .WithFlag(3, out stopCondition.RequestFlag, name: "SP",
152                     changeCallback: (_, __) =>
153                     {
154                         // When reading the condition will be generated after the last read has been performed
155                         if(currentTransmissionState != TransmissionState.Read)
156                         {
157                             stopCondition.TryPerform();
158                         }
159                     })
160                 .WithReservedBits(4, 1)
161                 .WithFlag(5, name: "TRS",
162                     valueProviderCallback: _ => currentTransmissionState != TransmissionState.Read,
163                     changeCallback: (_, __) => this.WarningLog("Writing to TRS (Transmit/Receive Mode) is not supported in this model and has no effect"))
164                 .WithFlag(6, name: "MST",
165                     valueProviderCallback: _ => currentTransmissionState != TransmissionState.Idle,
166                     changeCallback: (_, __) => this.WarningLog("Writing to MST (Master/Slave Mode) is not supported in this model and has no effect"))
167                 .WithFlag(7, FieldMode.Read, name: "BBSY",
168                     valueProviderCallback: _ => currentTransmissionState != TransmissionState.Idle);
169 
170             Registers.Mode1.Define(this, 0x8)
171                 .WithTag("BC[2:0]", 0, 3)
172                 .WithTaggedFlag("BCWP", 3)
173                 .WithTag("CKS[2:0]", 4, 3)
174                 .WithTaggedFlag("MTWP", 7);
175 
176             Registers.Mode2.Define(this, 0x6)
177                 .WithTaggedFlag("TMOS", 0)
178                 .WithTaggedFlag("TMOL", 1)
179                 .WithTaggedFlag("TMOH", 2)
180                 .WithReservedBits(3, 1)
181                 .WithTag("SDDL[2:0]", 4, 3)
182                 .WithTaggedFlag("DLCS", 7);
183 
184             Registers.Mode3.Define(this)
185                 .WithTag("NF[1:0]", 0, 2)
186                 .WithTaggedFlag("ACKBR", 2)
187                 .WithFlag(3, out transmitNegativeAcknowledge, name: "ACKBT",
188                     changeCallback: (previous, _) =>
189                     {
190                         if(!transmitAcknowledgeWriteEnable.Value)
191                         {
192                             this.WarningLog("Attempted to set ACKBT (Transmit Acknowledge) without disabling write protection, ignoring");
193                             transmitNegativeAcknowledge.Value = previous;
194                         }
195                     })
196                 .WithFlag(4, out transmitAcknowledgeWriteEnable, name: "ACKWP")
197                 .WithTaggedFlag("RDRFS", 5)
198                 .WithTaggedFlag("WAIT", 6)
199                 .WithTaggedFlag("SMBS", 7);
200 
201             Registers.FunctionEnable.Define(this, 0x72)
202                 .WithTaggedFlag("TMOE", 0)
203                 .WithTaggedFlag("MALE", 1)
204                 .WithTaggedFlag("NALE", 2)
205                 .WithTaggedFlag("SALE", 3)
206                 .WithTaggedFlag("NACKE", 4)
207                 .WithTaggedFlag("NFE", 5)
208                 .WithTaggedFlag("SCLE", 6)
209                 .WithTaggedFlag("FMPE", 7);
210 
211             Registers.StatusEnable.Define(this, 0x9)
212                 .WithTaggedFlag("SAR0E", 0)
213                 .WithTaggedFlag("SAR1E", 1)
214                 .WithTaggedFlag("SAR2E", 2)
215                 .WithTaggedFlag("GCAE", 3)
216                 .WithReservedBits(4, 1)
217                 .WithTaggedFlag("DIDE", 5)
218                 .WithReservedBits(6, 1)
219                 .WithTaggedFlag("HOAE", 7);
220 
221             Registers.InterruptEnable.Define(this)
222                 .WithTaggedFlag("TMOIE", 0)
223                 .WithTaggedFlag("ALIE", 1)
224                 .WithFlag(2, out startInterrupt.Enable, name: "STIE")
225                 .WithFlag(3, out stopInterrupt.Enable, name: "SPIE")
226                 .WithFlag(4, out nackInterrupt.Enable, name: "NAKIE")
227                 .WithFlag(5, out receiveInterrupt.Enable, name: "RIE")
228                 .WithFlag(6, out transmitEndInterrupt.Enable, name: "TEIE")
229                 .WithFlag(7, out transmitInterrupt.Enable, name: "TIE")
230                 .WithChangeCallback((_, __) => UpdateInterrupts());
231 
232             status1Register = Registers.Status1.Define(this)
233                 .WithTaggedFlag("AAS0", 0)
234                 .WithTaggedFlag("AAS1", 1)
235                 .WithTaggedFlag("AAS2", 2)
236                 .WithTaggedFlag("GCA", 3)
237                 .WithReservedBits(4, 1)
238                 .WithTaggedFlag("DID", 5)
239                 .WithReservedBits(6, 1)
240                 .WithTaggedFlag("HOA", 7);
241 
242             status2Register = Registers.Status2.Define(this)
243                 .WithTaggedFlag("TMOF", 0)
244                 .WithTaggedFlag("AL", 1)
245                 .WithFlag(2, out startInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "START")
246                 .WithFlag(3, out stopInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "STOP")
247                 .WithFlag(4, out nackInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "NACKF")
248                 .WithFlag(5, out receiveInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "RDRF")
249                 .WithFlag(6, out transmitEndInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TEND")
250                 .WithFlag(7, out transmitInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TDRE")
251                 .WithChangeCallback((_, __) => UpdateInterrupts());
252 
253             for(var i = 0; i < SlaveAddressCount; i++)
254             {
255                 (Registers.SlaveAddressLower0 + 0x2 * i).Define(this)
256                     .WithTaggedFlag("SVA0", 0)
257                     .WithTag("SVA[6:0]", 1, 7);
258 
259                 (Registers.SlaveAddressUpper0 + 0x2 * i).Define(this)
260                     .WithTaggedFlag("FS", 0)
261                     .WithTag("SVA[1:0]", 1, 2)
262                     .WithReservedBits(3, 5);
263             }
264 
265             Registers.BitRateLowLevel.Define(this, 0xFF)
266                 .WithTag("BRL[4:0]", 0, 5)
267                 .WithReservedBits(5, 3, 0x7);
268 
269             Registers.BitRateHighLevel.Define(this, 0xFF)
270                 .WithTag("BRH[4:0]", 0, 5)
271                 .WithReservedBits(5, 3, 0x7);
272 
273             Registers.TransmitData.Define(this)
274                 .WithValueField(0, 8, FieldMode.Write, name: "ICDRT",
275                     writeCallback: (_, value) =>
276                     {
277                         // TXI and TEI flags should be automatically cleared by a write to the ICDRT register
278                         transmitInterrupt.Flag = false;
279                         transmitEndInterrupt.Flag = false;
280                         if(currentTransmissionState == TransmissionState.WriteAddress)
281                         {
282                             // In Renode I2C transmissions generally happen instantly. Since software may not be prepared for that
283                             // we artificially delay the start of the transaction by delaying the write of the target peripheral address
284                             // This is the best place for delays as software will always perform the address write regardless of how it
285                             // starts the transmission (either via the Start or Restart conditions)
286                             machine.ScheduleAction(addressWriteDelay, ___ =>
287                             {
288                                 WriteData((byte)value);
289                                 UpdateInterrupts();
290                             });
291                         }
292                         else
293                         {
294                             WriteData((byte)value);
295                         }
296                         UpdateInterrupts();
297                     });
298 
299             Registers.ReceiveData.Define(this)
300                 .WithValueField(0, 8, FieldMode.Read, name: "ICDRR",
301                     valueProviderCallback: _ =>
302                     {
303                         // RXI flag should be automatically cleared by reading the ICDRR register
304                         receiveInterrupt.Flag = false;
305                         var result = ReadData();
306                         UpdateInterrupts();
307                         return result;
308                     });
309 
310             Registers.WakeupUnit.Define(this, 0x10)
311                 .WithTaggedFlag("WUAFA", 0)
312                 .WithReservedBits(1, 3)
313                 .WithTaggedFlag("WUAFA", 4)
314                 .WithTaggedFlag("WUF", 5)
315                 .WithTaggedFlag("WUIE", 6)
316                 .WithTaggedFlag("WUE", 7);
317 
318             Registers.WakeupUnit2.Define(this, 0xFD)
319                 .WithTaggedFlag("WUSEN", 0)
320                 .WithTaggedFlag("WUASYF", 1)
321                 .WithTaggedFlag("WUSYF", 2)
322                 .WithReservedBits(3, 5);
323         }
324 
WriteData(byte value)325         private void WriteData(byte value)
326         {
327             switch(currentTransmissionState)
328             {
329                 case TransmissionState.WriteAddress:
330                 {
331                     if((value >> 3) == ExtendedAddressPrefix)
332                     {
333                         this.ErrorLog("10-bit addressing is currently not supported");
334                         nackInterrupt.Flag = true;
335                         return;
336                     }
337 
338                     var isRead = BitHelper.IsBitSet(value, 0);
339                     var address = value >> 1;
340                     if(!TryGetByAddress(address, out selectedPeripheral))
341                     {
342                         nackInterrupt.Flag = true;
343                         this.ErrorLog("Invalid slave peripheral address 0x{0:X}", address);
344                         return;
345                     }
346                     this.DebugLog("Selected peripheral 0x{0:X} ({1})", address, selectedPeripheral.GetName());
347                     currentTransmissionState = isRead ? TransmissionState.Read : TransmissionState.Write;
348                     receiveInterrupt.Flag = isRead;
349                     transmitInterrupt.Flag = !isRead;
350                     transmitEndInterrupt.Flag = transmitInterrupt.Flag;
351                     if(isRead)
352                     {
353                         // Software should discard the first read, as reading it is used for starting the transmission
354                         // on real hardware. Add a dummy value to make sure that a value read from a sensor is not
355                         // accidentally discarded.
356                         readQueue.Enqueue(0x0);
357                     }
358                     break;
359                 }
360                 case TransmissionState.Write:
361                     writeQueue.Enqueue(value);
362                     transmitInterrupt.Flag = true;
363                     transmitEndInterrupt.Flag = true;
364                     break;
365                 default:
366                     this.ErrorLog("Transmission state: {0} is not valid when writing data (value 0x{1:X})", currentTransmissionState, value);
367                     return;
368             }
369         }
370 
ReadData()371         private byte ReadData()
372         {
373             switch(currentTransmissionState)
374             {
375                 case TransmissionState.Read:
376                 {
377                     if(readQueue.Count == 0)
378                     {
379                         if(selectedPeripheral == null)
380                         {
381                             this.WarningLog("Attempted to perform a peripheral read without selecting one");
382                         }
383                         else
384                         {
385                             // From IIC controller's perspective there is no way to determine
386                             // how many bytes is software intending to read. Since some peripherals
387                             // assume that the entire read operation will be performed using a single `Read` call
388                             // we request more bytes, buffer them and return those values during subsequent reads
389                             // The amount of bytes to buffer was chosen randomly and may be adjusted if required.
390                             var data = selectedPeripheral.Read(ReadByteCount);
391                             this.DebugLog("Read {0} from peripheral", data.ToLazyHexString());
392                             readQueue.EnqueueRange(data);
393                         }
394                     }
395 
396                     if(!readQueue.TryDequeue(out var result))
397                     {
398                         this.ErrorLog("Empty read buffer, returning 0x0");
399                         nackInterrupt.Flag = true;
400                         return 0x0;
401                     }
402 
403                     // Issue Stop or Restart if a NACK was requested during the last read
404                     if(finishReading)
405                     {
406                         finishReading = false;
407                         // Perform restart if it was requested. Otherwise always stop
408                         if(!restartCondition.TryPerform())
409                         {
410                             stopCondition.Perform();
411                         }
412                         return result;
413                     }
414 
415                     finishReading = transmitNegativeAcknowledge.Value;
416                     receiveInterrupt.Flag = true;
417                     return result;
418                 }
419                 default:
420                     this.ErrorLog("Transmission state: {0} is not valid when reading data", currentTransmissionState);
421                     return 0x0;
422             }
423         }
424 
UpdateInterrupts()425         private void UpdateInterrupts()
426         {
427             var rxi = receiveInterrupt.InterruptState;
428             var txi = transmitInterrupt.InterruptState;
429             var tei = transmitEndInterrupt.InterruptState;
430             var eri = startInterrupt.InterruptState ||
431                       stopInterrupt.InterruptState ||
432                       nackInterrupt.InterruptState;
433 
434             // Both IICn_TXI and IICn_RXI interrupts are edge detected.
435             // See Note 1 and 2 in Table 31.10 in RA6M5 Group User's Manual
436             if(rxi)
437             {
438                 ReceiveIRQ.Blink();
439             }
440             if(txi)
441             {
442                 TransmitIRQ.Blink();
443             }
444             TransmitEndIRQ.Set(tei);
445             ErrorOrEventIRQ.Set(eri);
446 
447             this.DebugLog("{0}: {1}, {2}: {3}, {4}: {5}, {6}: {7}",
448                 nameof(ReceiveIRQ), rxi ? "Blinking" : "Not blinking",
449                 nameof(TransmitIRQ), txi ? "Blinking" : "Not blinking",
450                 nameof(TransmitEndIRQ), tei,
451                 nameof(ErrorOrEventIRQ), eri
452             );
453         }
454 
HandleStartCondition()455         private void HandleStartCondition()
456         {
457             currentTransmissionState = TransmissionState.WriteAddress;
458             transmitInterrupt.Flag = true;
459             startInterrupt.Flag = true;
460             stopInterrupt.Flag = false;
461         }
462 
HandleStopCondition()463         private void HandleStopCondition()
464         {
465             stopInterrupt.Flag = true;
466             startInterrupt.Flag = false;
467             transmitNegativeAcknowledge.Value = false;
468             transmitInterrupt.Flag = false;
469             transmitEndInterrupt.Flag = false;
470             finishReading = false;
471 
472             // Flush the transmit buffer to the peripheral
473             if(selectedPeripheral != null && currentTransmissionState == TransmissionState.Write)
474             {
475                 if(writeQueue.Count == 0)
476                 {
477                     this.WarningLog("No data in the write buffer, aborting transmission");
478                 }
479                 else
480                 {
481                     var content = writeQueue.ToArray();
482                     writeQueue.Clear();
483 
484                     this.DebugLog("Writing {0} to peripheral", content.ToLazyHexString());
485                     selectedPeripheral.Write(content);
486                 }
487             }
488 
489             // Reset transmission state
490             currentTransmissionState = TransmissionState.Idle;
491             selectedPeripheral?.FinishTransmission();
492             selectedPeripheral = null;
493             readQueue.Clear();
494             writeQueue.Clear();
495         }
496 
HandleRestartCondition()497         private void HandleRestartCondition()
498         {
499             stopCondition.Perform(silent: true);
500             startCondition.Perform(silent: true);
501         }
502 
InternalReset()503         private void InternalReset()
504         {
505             status1Register.Reset();
506             status2Register.Reset();
507             control2Register.Reset();
508 
509             ReceiveIRQ.Unset();
510             TransmitIRQ.Unset();
511             TransmitEndIRQ.Unset();
512             ErrorOrEventIRQ.Unset();
513 
514             currentTransmissionState = TransmissionState.Idle;
515             writeQueue.Clear();
516             readQueue.Clear();
517             selectedPeripheral = null;
518             finishReading = false;
519         }
520 
521         private InterruptConfig receiveInterrupt;
522         private InterruptConfig transmitInterrupt;
523         private InterruptConfig transmitEndInterrupt;
524         private InterruptConfig startInterrupt;
525         private InterruptConfig stopInterrupt;
526         private InterruptConfig nackInterrupt;
527 
528         private IFlagRegisterField transmitNegativeAcknowledge;
529         private IFlagRegisterField transmitAcknowledgeWriteEnable;
530         private IFlagRegisterField peripheralEnable;
531 
532         private ByteRegister status1Register;
533         private ByteRegister status2Register;
534         private ByteRegister control2Register;
535 
536         private TransmissionState currentTransmissionState;
537         private II2CPeripheral selectedPeripheral;
538         private bool finishReading;
539 
540         private readonly Queue<byte> writeQueue;
541         private readonly Queue<byte> readQueue;
542 
543         private readonly Condition startCondition;
544         private readonly Condition stopCondition;
545         private readonly Condition restartCondition;
546 
547         private static readonly TimeInterval addressWriteDelay = TimeInterval.FromMicroseconds(100);
548 
549         private const int SlaveAddressCount = 3;
550         private const int ExtendedAddressPrefix = 0x1E;
551         private const int ReadByteCount = 24;
552 
553         private struct InterruptConfig
554         {
555             public bool InterruptState => Enable.Value && Flag;
556             public bool Flag
557             {
558                 get => FlagField.Value;
559                 set => FlagField.Value = value;
560             }
561 
562             public IFlagRegisterField Enable;
563             public IFlagRegisterField FlagField;
564         }
565 
566         private class Condition
567         {
Condition(RenesasRA_IIC parent, string name, Action handler)568             public Condition(RenesasRA_IIC parent, string name, Action handler)
569             {
570                 this.parent = parent;
571                 this.name = name;
572                 this.handler = handler;
573             }
574 
TryPerform()575             public bool TryPerform()
576             {
577                 if(Requested)
578                 {
579                     Perform();
580                     return true;
581                 }
582                 return false;
583             }
584 
Perform(bool silent = false)585             public void Perform(bool silent = false)
586             {
587                 if(!silent)
588                 {
589                     parent.DebugLog("Handling {0} condition", name);
590                 }
591                 handler();
592                 RequestFlag.Value = false;
593                 parent.UpdateInterrupts();
594             }
595 
596             public bool Requested
597             {
598                 get => RequestFlag.Value;
599                 set => RequestFlag.Value = value;
600             }
601 
602             public IFlagRegisterField RequestFlag;
603 
604             private readonly RenesasRA_IIC parent;
605             private readonly string name;
606             private readonly Action handler;
607         }
608 
609         private enum TransmissionState
610         {
611             Idle,
612             WriteAddress,
613             Write,
614             Read,
615         }
616 
617         private enum Registers
618         {
619             Control1            = 0x00, // ICCR1
620             Control2            = 0x01, // ICCR2
621             Mode1               = 0x02, // ICMR1
622             Mode2               = 0x03, // ICMR2
623             Mode3               = 0x04, // ICMR3
624             FunctionEnable      = 0x05, // ICFER
625             StatusEnable        = 0x06, // ICSER
626             InterruptEnable     = 0x07, // ICIER
627             Status1             = 0x08, // ICSR1
628             Status2             = 0x09, // ICSR2
629             SlaveAddressLower0  = 0x0A, // SARL0
630             SlaveAddressUpper0  = 0x0B, // SARU0
631             SlaveAddressLower1  = 0x0C, // SARL1
632             SlaveAddressUpper1  = 0x0D, // SARU1
633             SlaveAddressLower2  = 0x0E, // SARL2
634             SlaveAddressUpper2  = 0x0F, // SARU2
635             BitRateLowLevel     = 0x10, // ICBRL
636             BitRateHighLevel    = 0x11, // ICBRH
637             TransmitData        = 0x12, // ICDRT
638             ReceiveData         = 0x13, // ICDRR
639             WakeupUnit          = 0x16, // ICWUR
640             WakeupUnit2         = 0x17, // ICWUR2
641         }
642     }
643 }
644