1 //
2 // Copyright (c) 2010-2025 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.Collections.ObjectModel;
10 using System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.SPI;
15 using Antmicro.Renode.Peripherals.Miscellaneous;
16 using Antmicro.Renode.Peripherals.Wireless.IEEE802_15_4;
17 using static Antmicro.Renode.Peripherals.Wireless.IEEE802_15_4.PHYHeader802154; // for PHYType
18 using Antmicro.Renode.Utilities;
19 using Antmicro.Renode.Utilities.Collections;
20 
21 namespace Antmicro.Renode.Peripherals.Wireless
22 {
23     public sealed class CC1200: IRadio, ISPIPeripheral, INumberedGPIOOutput, IGPIOReceiver
24     {
CC1200()25         public CC1200()
26         {
27             CreateRegisters();
28             var dict = new Dictionary<int, IGPIO>();
29             //GPIO 0/1/2/3 are general purpose, GPIO4 is MISO
30             for(var i = 0; i < NumberOfGPIOs; ++i)
31             {
32                 dict[i] = new GPIO();
33             }
34             Connections = new ReadOnlyDictionary<int, IGPIO>(dict);
35             gpioConfigurations = new [] {gpio0Selection, gpio1Selection, gpio2Selection, gpio3Selection};
36             Reset();
37         }
38 
Reset()39         public void Reset()
40         {
41             wasSyncTransfered = false;
42             stateMachineMode = StateMachineMode.Off;
43             currentFrame = null;
44 
45             txFifo.Clear();
46             rxFifo.Clear();
47 
48             registers.Reset();
49             extendedRegisters.Reset();
50             frequency = 0;
51             foreach(var gpio in Connections.Values)
52             {
53                 gpio.Unset();
54             }
55         }
56 
57         private bool isChipSelect;
58         private bool initialized;
59         private IEnumRegisterField<GPIOSignal>[] gpioConfigurations;
60         private IFlagRegisterField is802154gEnabled;
61 
OnGPIO(int number, bool value)62         public void OnGPIO(int number, bool value)
63         {
64             if(!initialized && !value)
65             {
66                 // our gpio system uses `false` as defaults. Here it's a meaningful value. Let's ignore gpios until first `true` is received
67                 return;
68             }
69             initialized = true;
70             this.Log(LogLevel.Noisy, "Received a GPIO! Number {0}, value {1}", number, value);
71             if(number == 0) //0 is Chip Select line
72             {
73                 isChipSelect = !value;
74                 if(!isChipSelect)
75                 {
76                     FinishTransmission();
77                 }
78                 else if(stateMachineMode == StateMachineMode.Off)
79                 {
80                     stateMachineMode = StateMachineMode.Idle;
81                 }
82                 UpdateGPIOs();
83             }
84             else
85             {
86                 this.Log(LogLevel.Warning, "Unhandled GPIO {0}!", number);
87             }
88         }
89 
UpdateGPIOs()90         public void UpdateGPIOs()
91         {
92             for(var i = 0; i < gpioConfigurations.Length; ++i)
93             {
94                 var gpio = gpioConfigurations[i];
95                 switch(gpio.Value)
96                 {
97                     case GPIOSignal.RxFifoThreshold:
98                         Connections[i].Set((int)fifoThreshold.Value < rxFifo.Count);
99                         this.Log(LogLevel.Noisy, $"RX: threshold {fifoThreshold.Value}, fifo {rxFifo.Count}");
100                         break;
101                     case GPIOSignal.TxFifoThreshold:
102                         Connections[i].Set(127 - (int)fifoThreshold.Value <= txFifo.Count);
103                         break;
104                     case GPIOSignal.TxFifoFull:
105                         if(!Connections[i].IsSet)
106                         {
107                             Connections[i].Set(txFifo.Count == 128);
108                         }
109                         else
110                         {
111                             Connections[i].Set(txFifo.Count > 127 - (int)fifoThreshold.Value);
112                         }
113                         break;
114                     case GPIOSignal.PacketSync:
115                         if(wasSyncTransfered)
116                         {
117                             Connections[i].Blink();
118                         }
119                         wasSyncTransfered = false;
120                         break;
121                     case GPIOSignal.MARCStateStatus1:
122                         Connections[i].Set(
123                             stateMachineMode == StateMachineMode.ReceiveMode ||
124                             stateMachineMode == StateMachineMode.Idle);
125                         break;
126                     case GPIOSignal.MARCStateStatus0:
127                         Connections[i].Set(
128                             stateMachineMode == StateMachineMode.ReceiveMode ||
129                             stateMachineMode == StateMachineMode.TransmitMode);
130                         break;
131                     case GPIOSignal.ChipReadyN:
132                         Connections[i].Set(stateMachineMode == StateMachineMode.Off);
133                         break;
134                     default:
135                         // As GPIOs are set to unsupported mode on reset, this was changed to `Debug` to avoid flooding the log
136                         this.Log(LogLevel.Debug, "Unsupported GPIO mode on pin {0}: {1}", i, gpio.Value);
137                         continue; //continue not to log
138                 }
139                 this.Log(LogLevel.Noisy, "Setting up GPIO{0} ({1}) to {2}", i, gpio.Value, Connections[i].IsSet);
140             }
141             //We fake the MISO line here, by emulating (from CC1200 RM):
142             // "When CSn is pulled low, the MCU must wait until CC120X SO pin goes low before starting to transfer
143             // the header byte"
144             //Conversely, the MISO line should go high when CS is deasserted.
145             //Keep in mind this does not take special GPIO1 behavior (acting as MISO in certain conditions).
146             Connections[4].Set(!isChipSelect);
147             this.Log(LogLevel.Noisy, "Setting up MISO line (GPIO[4]) to {0}", Connections[4].IsSet);
148         }
149 
150         private enum State
151         {
152             WaitingForHeader,
153             WaitingForAddress,
154             WaitingForData,
155             Readout
156         }
157 
158         private const byte ExtendedRegisterAccessCommand = 0x2F;
159         private const byte CommandStrobeLow = 0x30;
160         private const byte CommandStrobeHigh = 0x3d;
161         private const byte BuffersOrFECOrFreeArea = 0x3e;
162         private const byte StandardFIFOAccess = 0x3f;
163 
164         private struct AccessDescriptor
165         {
166             public byte Address;
167             public bool IsRead;
168             public bool IsBurst; //todo: when does it end?
169             public Target Target;
170 
NextStateAntmicro.Renode.Peripherals.Wireless.CC1200.AccessDescriptor171             public State NextState(State state)
172             {
173                 switch(state)
174                 {
175                 case State.WaitingForHeader:
176                     if(Target == Target.Registers || Target == Target.StandardFIFO)
177                     {
178                         return IsRead ? State.Readout : State.WaitingForData;
179                     }
180                     else if(Target == Target.ExtendedRegisters || Target == Target.DirectFIFO || Target == Target.FECWorkspaceOrFreeArea)
181                     {
182                         return State.WaitingForAddress;
183                     }
184                     else if(Target == Target.CommandStrobe)
185                     {
186                         return State.WaitingForHeader;
187                     }
188                     //should not reach
189                     break;
190                 case State.WaitingForAddress:
191                     return IsRead ? State.Readout : State.WaitingForData;
192                 case State.WaitingForData:
193                 case State.Readout:
194                     return IsBurst ? state : State.WaitingForHeader;
195                 }
196                 //should not reach
197                 return State.WaitingForHeader;
198             }
199         }
200 
201         private enum Target
202         {
203             Registers,
204             ExtendedRegisters,
205             StandardFIFO,
206             DirectFIFO,
207             FECWorkspaceOrFreeArea,
208             CommandStrobe
209         }
210 
211         private AccessDescriptor access;
212         private State state;
213         private byte[] freeArea = new byte[0xFF];
214 
RunCommand(Command command)215         private void RunCommand(Command command)
216         {
217             this.Log(LogLevel.Noisy, "Running command: {0}", command);
218             switch(command)
219             {
220                 case Command.ResetChip:
221                     Reset(); //maybe should do less
222                     break;
223                 case Command.EnableAndCalibrateFrequencySynthesizer:
224                     stateMachineMode = StateMachineMode.FastTxReady;
225                     break;
226                 case Command.EnableRx:
227                     stateMachineMode = StateMachineMode.ReceiveMode;
228                     if(currentFrame != null)
229                     {
230                         HandleFrame(currentFrame);
231                         currentFrame = null;
232                     }
233                     break;
234                 case Command.EnableTx:
235                     stateMachineMode = StateMachineMode.TransmitMode;
236                     SendFrame();
237                     break;
238                 case Command.Idle:
239                     stateMachineMode = StateMachineMode.Idle;
240                     break;
241                 case Command.Sleep: //sleep should only be called in idle, and has no special state code. This is a warning hush
242                     stateMachineMode = StateMachineMode.Off;
243                     break;
244                 case Command.FlushRX:
245                     rxFifo.Clear();
246                     break;
247                 case Command.FlushTX:
248                     txFifo.Clear();
249                     break;
250                 case Command.NoOperation:
251                     //intentionally left blank
252                     break;
253                 default:
254                     this.Log(LogLevel.Warning, "Unsupported command {0} ({1})", command, (Registers)command);
255                     break;
256             }
257         }
258 
Transmit(byte data)259         public byte Transmit(byte data)
260         {
261             var status = GetStatus();
262             if(!isChipSelect || stateMachineMode == StateMachineMode.Off)
263             {
264                 this.Log(LogLevel.Error, "Trying to communicate with Chip Select disabled or in OFF state.");
265             }
266             if(state == State.WaitingForHeader)
267             {
268                 access = new AccessDescriptor
269                 {
270                     IsRead = (data & 0x80) != 0,
271                     IsBurst = (data & 0x40) != 0
272                 };
273                 var command = (byte)(data & 0x3F);
274                 this.Log(LogLevel.Noisy, "{2} radio: 0x{0:X}, {1} (raw 0x{3:X})", command, (Registers)command, (access.IsBurst ? "(Burst) " : String.Empty) + (access.IsRead ? "Read from" : "Write to"), data);
275 
276                 if(command < ExtendedRegisterAccessCommand)
277                 {
278                     access.Target = Target.Registers;
279                     access.Address = command;
280                 }
281                 else if(command == ExtendedRegisterAccessCommand)
282                 {
283                     access.Target = Target.ExtendedRegisters;
284                 }
285                 else if(command >= CommandStrobeLow && command <= CommandStrobeHigh)
286                 {
287                     access.Target = Target.CommandStrobe;
288                     RunCommand((Command)command);
289                 }
290                 else if(command == StandardFIFOAccess)
291                 {
292                     access.Target = Target.StandardFIFO;
293                 }
294                 else if(command == BuffersOrFECOrFreeArea) // && spi_direct_access_cfg == 0
295                 {
296                     access.Target = Target.DirectFIFO;
297                 }
298                 else if(command == BuffersOrFECOrFreeArea) // && spi_direct_access_cfg == 0
299                 {
300                     access.Target = Target.FECWorkspaceOrFreeArea;
301                 }
302                 state = access.NextState(state);
303                 this.Log(LogLevel.Noisy, "Access target: {0}, next state {1}", access.Target, state);
304 
305                 return status;
306             }
307             else if(state == State.WaitingForAddress)
308             {
309                 access.Address = data;
310                 state = access.NextState(state);
311                 return 0;
312             }
313             else if(state == State.WaitingForData)
314             {
315                 switch(access.Target)
316                 {
317                     case Target.Registers:
318                         this.Log(LogLevel.Debug, "Writing to Register 0x{0:X} ({1}), value 0x{2:X}", access.Address, (Registers)access.Address, data);
319                         registers.Write(access.Address, data);
320                         break;
321                     case Target.ExtendedRegisters:
322                         this.Log(LogLevel.Debug, "Writing to ExtendedRegister 0x{0:X} ({1}), value 0x{2:X}", access.Address, (ExtendedRegisters)access.Address, data);
323                         extendedRegisters.Write(access.Address, data);
324                         break;
325                     case Target.StandardFIFO:
326                         this.Log(LogLevel.Debug, "Writing to txFifo value 0x{0:X}", data);
327                         txFifo.Enqueue(data);
328                         break;
329                     case Target.DirectFIFO:
330                         //TODO: verify this
331                         //txFifo[access.Address] = data;
332                         break;
333                     case Target.FECWorkspaceOrFreeArea:
334                         freeArea[access.Address] = data;
335                         break;
336                 }
337                 state = access.NextState(state);
338                 return status;
339             }
340             else if(state == State.Readout)
341             {
342                 byte value;
343                 state = access.NextState(state);
344                 switch(access.Target)
345                 {
346                     case Target.Registers:
347                         value = registers.Read(access.Address);
348                         this.Log(LogLevel.Debug, "Reading from Register 0x{0:X} ({1}), value 0x{2:X}", access.Address, (Registers)access.Address, value);
349                         return value;
350                     case Target.ExtendedRegisters:
351                         value = extendedRegisters.Read(access.Address);
352                         this.Log(LogLevel.Debug, "Reading from ExtendedRegister 0x{0:X} ({1}), value 0x{2:X}", access.Address, (ExtendedRegisters)access.Address, value);
353                         return value;
354                     case Target.StandardFIFO:
355                         rxFifo.TryDequeue(out value);
356                         //underflow?
357                         this.Log(LogLevel.Debug, "Reading from rx fifo, value 0x{0:X}, {1} bytes left", value, rxFifo.Count);
358                         return value;
359                     case Target.DirectFIFO:
360                         return rxFifo.ElementAt(access.Address);
361                     case Target.FECWorkspaceOrFreeArea:
362                         return freeArea[access.Address];
363                     default:
364                         this.Log(LogLevel.Error, "Unhandled access target {0}", access.Target);
365                         return 0;
366                 }
367             }
368             else
369             {
370                 this.Log(LogLevel.Error, "Unhandled Transmit in state {0}", state);
371                 return 0;
372             }
373         }
374 
FinishTransmission()375         public void FinishTransmission()
376         {
377             this.Log(LogLevel.Noisy, "Finish transmission");
378             state = State.WaitingForHeader;
379         }
380 
ReceiveFrame(byte[] bytes, IRadio sender)381         public void ReceiveFrame(byte[] bytes, IRadio sender)
382         {
383             if(stateMachineMode == StateMachineMode.ReceiveMode)
384             {
385                 //this allows to have proper CCA values easily.
386                 this.DebugLog("Received frame {0}.", bytes.Select(x => "0x{0:X}".FormatWith(x)).Stringify());
387                 currentFrame = bytes;
388                 HandleFrame(bytes);
389                 currentFrame = null;
390             }
391             else
392             {
393                 currentFrame = bytes;
394                 this.DebugLog("Radio is not listening right now - this frame is being deffered.");
395             }
396         }
397 
398         public int Channel
399         {
400             get
401             {
402                 return ChannelValueFromFrequency(frequency);
403             }
404 
405             set
406             {
407                 this.Log(LogLevel.Info, "Setting channel to {0}", value);
408                 frequency = ChannelNumberToFrequency(value);
409             }
410         }
411 
412         public IReadOnlyDictionary<int, IGPIO> Connections
413         {
414             get; private set;
415         }
416 
417         public event Action<IRadio, byte[]> FrameSent;
418 
HandleFrame(byte[] bytes)419         private void HandleFrame(byte[] bytes)
420         {
421             if(bytes.Length <= 2)
422             {
423                 this.Log(LogLevel.Warning, "Received a frame with {0} bytes, ignoring...", bytes.Length);
424                 return;
425             }
426 
427             var phyHeader = new PHYHeader802154(bytes[0], bytes[1], is802154gEnabled.Value ? PHYType.Header802154g
428                     : PHYType.Header802154);
429 
430             var crcLength = is802154gEnabled.Value && !phyHeader.FCS2Byte ? 4 : 2;
431 
432             // Length filtering is common
433             switch(packetLengthConfig.Value)
434             {
435                 case PacketLengthConfig.Fixed:
436                     //TODO: this logic should be in registers
437                     if(phyHeader.Length != packetLengthByteConfig.Value ||
438                     (phyHeader.Length != 256 && packetLengthByteConfig.Value == 0) ||
439                     (phyHeader.Length > 128 && crcAutoflush.Value) ||
440                     (phyHeader.Length > 126 && crcAutoflush.Value && appendStatus.Value))
441                     {
442                         if(terminateOnBadPacket.Value)
443                         {
444                             stateMachineMode = StateMachineMode.Idle;
445                         }
446                         this.Log(LogLevel.Warning, "Dropping a packet of invalid length {0} in fixed length mode " +
447                                 "(expected length: {1}, crc autoflush? {2}, append status? {3})",
448                                 phyHeader.Length, packetLengthByteConfig.Value, crcAutoflush.Value, appendStatus.Value);
449                         return;
450                     }
451                     break;
452                 case PacketLengthConfig.VariableFirstByte:
453                     if((phyHeader.Length > packetLengthByteConfig.Value) ||
454                     (phyHeader.Length > 256 && packetLengthByteConfig.Value == 0) ||
455                     (phyHeader.Length > 127 && crcAutoflush.Value) ||
456                     (phyHeader.Length > 125 && crcAutoflush.Value && appendStatus.Value))
457                     {
458                         if(terminateOnBadPacket.Value)
459                         {
460                             stateMachineMode = StateMachineMode.Idle;
461                         }
462                         this.Log(LogLevel.Warning, "Dropping a packet of invalid length {0} in fixed length mode " +
463                                 "(max length: {1}, crc autoflush? {2}, append status? {3})",
464                                 phyHeader.Length, packetLengthByteConfig.Value, crcAutoflush.Value, appendStatus.Value);
465                         return;
466                     }
467                     break;
468                 case PacketLengthConfig.Variable5LSB:
469                     if((phyHeader.Length & 0x1f) > packetLengthByteConfig.Value)
470                     {
471                         if(terminateOnBadPacket.Value)
472                         {
473                             stateMachineMode = StateMachineMode.Idle;
474                         }
475                         this.Log(LogLevel.Warning, "Dropping a packet of invalid length {0} in fixed length mode " +
476                                 "(max length: {1})", phyHeader.Length & 0x1f);
477                         return;
478                     }
479                     break;
480                 // Infinite packet length is not currently supported
481             }
482 
483             // Additional address filtering for 802.15.4 packets
484             if(!is802154gEnabled.Value && (addressCheckConfig.Value != 0) && (deviceAddress.Value != phyHeader.Address))
485             {
486                 // Broadcast address bytes not permitted
487                 if(addressCheckConfig.Value == 1)
488                 {
489                     if(terminateOnBadPacket.Value)
490                     {
491                         stateMachineMode = StateMachineMode.Idle;
492                     }
493                     this.Log(LogLevel.Info, "Dropping a packet directed to 0x{0:X} (device address is 0x{1:X})", phyHeader.Address, deviceAddress.Value);
494                     return;
495                 }
496                 // Broadcast address (0xFF) not permitted
497                 else if(addressCheckConfig.Value == 2 && phyHeader.Address != 0x00)
498                 {
499                     if(terminateOnBadPacket.Value)
500                     {
501                         stateMachineMode = StateMachineMode.Idle;
502                     }
503                     this.Log(LogLevel.Info, "Dropping a packet directed to 0x{0:X} (device address is 0x{1:X})", phyHeader.Address, deviceAddress.Value);
504                     return;
505                 }
506                 // Both broadcast bytes permitted. Check if the address was not broadcast type
507                 else if(addressCheckConfig.Value == 3 && phyHeader.Address != 0x00 && phyHeader.Address != 0xFF)
508                 {
509                     if(terminateOnBadPacket.Value)
510                     {
511                         stateMachineMode = StateMachineMode.Idle;
512                     }
513                     this.Log(LogLevel.Info, "Dropping a packet directed to 0x{0:X} (device address is 0x{1:X})", phyHeader.Address, deviceAddress.Value);
514                     return;
515                 }
516             }
517 
518             // Prepare bytes with MPDU (MAC Protocol Data Unit) - first byte is skipped as it is a PHY Header start byte
519             var mpduBytes = bytes.Skip(1).ToArray();
520             var frame = new Frame(mpduBytes, crcPolynomial);
521 
522             crcOK.Value = frame.CheckCRC(crcInitialValue);
523             if(!crcOK.Value)
524             {
525                 this.Log(LogLevel.Warning, "The received packet has an invalid CRC");
526                 if(crcAutoflush.Value)
527                 {
528                     if(terminateOnBadPacket.Value)
529                     {
530                         stateMachineMode = StateMachineMode.Idle;
531                     }
532                     this.Log(LogLevel.Info, "Dropping a packet with wrong CRC");
533                     return;
534                 }
535             }
536 
537             // Get rid of CRC bytes
538             var fifoData = bytes.Take(bytes.Length - crcLength).ToList();
539 
540             // Append optional statuses
541             if(appendStatus.Value)
542             {
543                 // We ignore lowest 4 bits, as RSSI is 12-bit wide
544                 fifoData.Add((byte)((Rssi & 0xFF0) >> 4));
545                 fifoData.Add((byte)((uint)(crcOK.Value ? (1 << 7) : 0) | Lqi));
546             }
547 
548             // Filtering using MPDU is not present for CC1200.
549             // Just pass the bytes to FIFO.
550 
551             // We do not pass CRC to FIFO. Data passed to FIFO:
552             // [PHRA][PHRB][MPDU][Optional RSSI][Optional CRC_OK|LQI]
553             foreach(var data in fifoData)
554             {
555                 rxFifo.Enqueue(data);
556             }
557             // After receiving a good packet, change state
558             stateMachineMode = rxOffMode;
559 
560             // We should consider also if radio rx|tx_mode_autoack is enabled in this if statement
561             if(crcOK.Value && frame.AcknowledgeRequest && frame.Type != FrameType.Beacon && frame.Type != FrameType.ACK
562                     && stateMachineMode == StateMachineMode.TransmitMode && terminateOnBadPacket.Value)
563             {
564                 var ack = Frame.CreateACK(frame.DataSequenceNumber, true, crcInitialValue, crcPolynomial);
565                 TrySendFrame(ack.Bytes);
566             }
567             wasSyncTransfered = true;
568             UpdateGPIOs();
569         }
570 
SendFrame()571         private void SendFrame()
572         {
573             uint length;
574             int crcLength = 2;
575             IEnumerable<byte> data;
576             if(is802154gEnabled.Value)
577             {
578                 txFifo.TryDequeue(out var packetHeaderA);
579                 txFifo.TryDequeue(out var packetHeaderB);
580                 var packetHeader = new PHYHeader802154(packetHeaderA, packetHeaderB, is802154gEnabled.Value ? PHYType.Header802154g : PHYType.Header802154);
581                 if(packetHeader.ModeSwitch)
582                 {
583                     this.Log(LogLevel.Error, "Unsupported packet with Mode Switch on, dropping");
584                     txFifo.Clear();
585                     return;
586                 }
587                 if(!packetHeader.FCS2Byte)
588                 {
589                     crcLength = 4;
590                 }
591                 length = packetHeader.Length;
592                 data = new byte[] { packetHeaderA, packetHeaderB };
593             }
594             else
595             {
596                 txFifo.TryDequeue(out var lengthByte);
597                 length = lengthByte;
598                 data = new byte[] { lengthByte };
599             }
600             data = data.Concat(txFifo.DequeueAll()).ToArray();
601             // CRC is calculated over MPDU bytes - first byte is skipped as it is a PHY Header start byte
602             var mpduBytes = data.Skip(1).ToArray();
603 
604             IEnumerable<byte> crc;
605             if(crcEnabled)
606             {
607                 if(crcLength == 2)
608                 {
609                     crc = Frame.CalculateCRC(mpduBytes, (ushort)crcInitialValue, crcPolynomial);
610                 }
611                 else if(crcLength == 4)
612                 {
613                     // CRC32 is a special case when we do not use CRC configuration registers
614                     crc = Frame.CalculateCRC(mpduBytes, 0, CRCPolynomial.CRC32);
615                 }
616                 else
617                 {
618                     this.Log(LogLevel.Error, "Invalid length of the CRC to generate: {0}", crcLength);
619                     crc = new byte[0];
620                 }
621                 data = (data.Concat(crc).ToArray());
622             }
623             this.DebugLog("Sending frame {0}.", data.Select(x => "0x{0:X}".FormatWith(x)).Stringify());
624             TrySendFrame(data.ToArray());
625             stateMachineMode = txOffMode;
626             this.Log(LogLevel.Noisy, "Setting state to {0}", stateMachineMode);
627             wasSyncTransfered = true;
628             UpdateGPIOs();
629         }
630 
TrySendFrame(byte[] frame)631         private void TrySendFrame(byte[] frame)
632         {
633             var fs = FrameSent;
634             if(fs != null)
635             {
636                 fs.Invoke(this, frame);
637             }
638             else
639             {
640                 this.Log(LogLevel.Warning, "FrameSent is not initialized. Am I connected to medium?");
641             }
642         }
643 
GetStatus()644         private byte GetStatus()
645         {
646             var status = (byte)((byte)stateMachineMode << 4);
647             this.Log(LogLevel.Noisy, "Returning status 0x{0:X}", status);
648             return status;
649             // bits 0:3 are reserved, 7 is CHIP_RDYn, should always be zero
650         }
651 
ChannelValueFromFrequency(uint frequency)652         private int ChannelValueFromFrequency(uint frequency)
653         {
654             var actualFreq = frequency * 625 / 4096; // should be calculated from f_xosc, freqoff (equal to 0) and LO_Divider.
655             return (int)(actualFreq - 863125) * 1000 / 25000; // 902200 - center, 200000 - spacing, 1000 - Hz to kHz
656          //   return ((int)frequency - 11) / 5 + 11;
657         }
658 
ChannelNumberToFrequency(int channelNumber)659         private uint ChannelNumberToFrequency(int channelNumber)
660         {
661             //According to documentation, chapter 16:
662             //"Channels are numbered 11 through 26 and are 5MHz apart"
663             return (uint)(11 + 5 * (channelNumber - 11));
664         }
665 
CreateRegisters()666         private void CreateRegisters()
667         {
668             var dict = new Dictionary<long, ByteRegister>
669             {
670                 {(long)Registers.GPIO3Pin, new ByteRegister(this, 0x6)
671                     .WithTaggedFlag("GPIO3_ATRAN", 7)
672                     .WithTaggedFlag("GPIO3_INV", 6)
673                     .WithEnumField(0, 6, out gpio3Selection)
674                     .WithWriteCallback((_, __) => UpdateGPIOs())
675                 },
676                 {(long)Registers.GPIO2Pin, new ByteRegister(this, 0x7)
677                     .WithTaggedFlag("GPIO2_ATRAN", 7)
678                     .WithTaggedFlag("GPIO2_INV", 6)
679                     .WithEnumField(0, 6, out gpio2Selection)
680                     .WithWriteCallback((_, __) => UpdateGPIOs())
681                 },
682                 {(long)Registers.GPIO1Pin, new ByteRegister(this, 0x30)
683                     .WithTaggedFlag("GPIO1_ATRAN", 7)
684                     .WithTaggedFlag("GPIO1_INV", 6)
685                     .WithEnumField(0, 6, out gpio1Selection)
686                     .WithWriteCallback((_, __) => UpdateGPIOs())
687                 },
688                 {(long)Registers.GPIO0Pin, new ByteRegister(this, 0x3c)
689                     .WithTaggedFlag("GPIO0_ATRAN", 7)
690                     .WithTaggedFlag("GPIO0_INV", 6)
691                     .WithEnumField(0, 6, out gpio0Selection)
692                     .WithWriteCallback((_, __) => UpdateGPIOs())
693                 },
694                 {(long)Registers.Sync3Word, new ByteRegister(this, 0x93).WithValueField(0, 8)},
695                 {(long)Registers.Sync2Word, new ByteRegister(this, 0x0B).WithValueField(0, 8)},
696                 {(long)Registers.Sync1Word, new ByteRegister(this, 0x51).WithValueField(0, 8)},
697                 {(long)Registers.Sync0Word, new ByteRegister(this, 0xDE).WithValueField(0, 8)},
698                 {(long)Registers.FrequencyDeviation, new ByteRegister(this, 0x06).WithValueField(0, 8)},
699                 {(long)Registers.ModulationFormatAndFrequencyDeviation, new ByteRegister(this, 0x03)
700                     .WithValueField(0, 3, name: "DEV_E")
701                     .WithValueField(3, 3, name: "MOD_FORMAT")
702                     .WithValueField(6, 2, name: "MODEM_MODE")
703                 },
704                 {(long)Registers.DigitalDCRemoval, new ByteRegister(this, 0x4C)
705                     .WithValueField(0, 3, name: "DCFILT_BW")
706                     .WithValueField(3, 3, name: "DCFILT_BW_SETTLE")
707                     .WithFlag(6, name: "DCFILT_FREEZE_COEFF")
708                     .WithReservedBits(7, 1)
709                 },
710                 {(long)Registers.Preamble1, new ByteRegister(this, 0x14)
711                     .WithValueField(0, 2, name: "PREAMBLE_WORD")
712                     .WithValueField(2, 4, name: "NUM_PREAMBLE")
713                     .WithReservedBits(6, 2)
714                 },
715                 {(long)Registers.Preamble0, new ByteRegister(this, 0xDA)
716                     .WithValueField(0, 4, name: "PQT")
717                     .WithValueField(4, 3, name: "PQT_VALID_TIMEOUT")
718                     .WithFlag(7, name: "PQT_EN")
719                 },
720                 {(long)Registers.DigitalImageChannelCompensation, new ByteRegister(this, 0xC4)
721                     .WithValueField(0, 2, name: "IQIC_IMGCH_LEVEL_THR")
722                     .WithValueField(2, 2, name: "IQIC_BLEN")
723                     .WithValueField(4, 2, name: "IQIC_BLEN_SETTLE")
724                     .WithFlag(6, name: "IQIC_UPDATE_COEFF_EN")
725                     .WithFlag(7, name: "IQIC_EN")
726                 },
727                 {(long)Registers.FIFOConfiguration, new ByteRegister(this, 0x80)
728                     .WithValueField(0, 7, out fifoThreshold, name: "FIFO_THR")
729                     .WithFlag(7, out crcAutoflush, name: "CRC_AUTOFLUSH")
730                 },
731                 {(long)Registers.DeviceAddress, new ByteRegister(this)
732                     .WithValueField(0, 8, out deviceAddress, name: "DEV_ADDR")
733                 },
734                 {(long)Registers.PacketConfiguration2, new ByteRegister(this, 0x4)
735                     .WithTag("PKT_FORMAT", 0, 2)
736                     .WithTag("CCA_MODE", 2, 3)
737                     .WithFlag(5, out is802154gEnabled, name: "FG_MODE_EN")
738                     .WithTaggedFlag("BYTE_SWAP_EN", 6)
739                     .WithReservedBits(7, 1)
740                 },
741                 {(long)Registers.PacketConfiguration1, new ByteRegister(this, 0x3)
742                     .WithFlag(0, out appendStatus)
743                     .WithValueField(1, 2, writeCallback: (_, value) =>
744                         {
745                             switch(value)
746                             {
747                                 case 0:
748                                     crcEnabled = false;
749                                     break;
750                                 case 1:
751                                     crcEnabled = true;
752                                     crcPolynomial = CRCPolynomial.CRC16;
753                                     crcInitialValue = 0xFFFFFFFF;
754                                     break;
755                                 case 2:
756                                     crcEnabled = true;
757                                     crcPolynomial = CRCPolynomial.CRC16_CCITT;
758                                     crcInitialValue = 0x0;
759                                     break;
760                                 default:
761                                     Logger.Log(LogLevel.Warning, "Complement CRC not supported.");
762                                     break;
763                             }
764                         },
765                         valueProviderCallback: _ => 1, name: "CRC_CFG")
766                                                //TODO: ENUM
767                     .WithValueField(3, 2, out addressCheckConfig, name: "ADDR_CHECK_CFG")
768                     .WithTaggedFlag("PN9_SWAP_EN", 5)
769                     .WithTaggedFlag("WHITE_DATA", 6)
770                     .WithTaggedFlag("FEC_EN", 7)
771                 },
772                 {(long)Registers.PacketConfiguration0, new ByteRegister(this)
773                     .WithTaggedFlag("UART_SWAP_EN", 0)
774                     .WithTaggedFlag("UART_MODE_EN", 1)
775                     .WithTag("PKT_BIT_LEN", 2, 3)
776                     .WithEnumField(5, 2, out packetLengthConfig, name: "LENGTH_CONFIG")
777                 },
778                 {(long)Registers.RFENDConfiguration1, new ByteRegister(this)
779                     .WithTaggedFlag("RX_TIME_QUAL", 0)
780                     .WithTag("RX_TIME", 1, 3)
781                     .WithValueField(4, 2, writeCallback: (_, value) =>
782                     {
783                         switch(value)
784                         {
785                             case 0:
786                                 rxOffMode = StateMachineMode.Idle;
787                                 break;
788                             case 1:
789                                 rxOffMode = StateMachineMode.FastTxReady;
790                                 break;
791                             case 2:
792                                 rxOffMode = StateMachineMode.TransmitMode;
793                                 break;
794                             case 3:
795                                 rxOffMode = StateMachineMode.ReceiveMode;
796                                 break;
797                         }
798                     }, valueProviderCallback: _ =>
799                     {
800                         switch(rxOffMode)
801                         {
802                             case StateMachineMode.Idle:
803                                 return 0;
804                             case StateMachineMode.FastTxReady:
805                                 return 1;
806                             case StateMachineMode.TransmitMode:
807                                 return 2;
808                             case StateMachineMode.ReceiveMode:
809                             default: //it is 2bit anyway
810                                 return 3;
811                         }
812                     }, name: "RXOFF_MODE")
813                 },
814                 {(long)Registers.RFENDConfiguration0, new ByteRegister(this)
815                     .WithTag("ANT_DIV_RX_TERM_CFG", 0, 3)
816                     .WithFlag(3, out terminateOnBadPacket, name: "TERM_ON_BAD_PACKET_EN")
817                     .WithValueField(4, 2, writeCallback: (_, value) =>
818                     {
819                         switch(value)
820                         {
821                             case 0:
822                                 txOffMode = StateMachineMode.Idle;
823                                 break;
824                             case 1:
825                                 txOffMode = StateMachineMode.FastTxReady;
826                                 break;
827                             case 2:
828                                 txOffMode = StateMachineMode.TransmitMode;
829                                 break;
830                             case 3:
831                                 txOffMode = StateMachineMode.ReceiveMode;
832                                 break;
833                         }
834                     }, valueProviderCallback: _ =>
835                     {
836                         switch(txOffMode)
837                         {
838                             case StateMachineMode.Idle:
839                                 return 0;
840                             case StateMachineMode.FastTxReady:
841                                 return 1;
842                             case StateMachineMode.TransmitMode:
843                                 return 2;
844                             case StateMachineMode.ReceiveMode:
845                             default: //it is 2bit anyway
846                                 return 3;
847                         }
848                     }, name: "TXOFF_MODE")
849                 },
850                 {(long)Registers.PacketLength, new ByteRegister(this)
851                     .WithValueField(0, 8, out packetLengthByteConfig, name: "PACKET_LENGTH")
852                 },
853             };
854             registers = new ByteRegisterCollection(this, dict);
855 
856             var extDict = new Dictionary<long, ByteRegister>
857             {
858                 {(long)ExtendedRegisters.Frequency2, new ByteRegister(this)
859                     .WithValueField(0, 8, writeCallback: (_, value) => BitHelper.ReplaceBits(ref frequency, (uint)value, 8, 16))
860                 },
861                 {(long)ExtendedRegisters.Frequency1, new ByteRegister(this)
862                     .WithValueField(0, 8, writeCallback: (_, value) => BitHelper.ReplaceBits(ref frequency, (uint)value, 8, 8))
863                 },
864                 {(long)ExtendedRegisters.Frequency0, new ByteRegister(this)
865                     .WithValueField(0, 8, writeCallback: (_, value) => BitHelper.ReplaceBits(ref frequency, (uint)value, 8))
866                 },
867                 {(long)ExtendedRegisters.ReceivedSignalStrengthIndicator1, new ByteRegister(this)
868                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (Rssi & 0xff0) >> 4, name: "RSSI_11_4")
869                 },
870                 {(long)ExtendedRegisters.ReceivedSignalStrengthIndicator0, new ByteRegister(this)
871                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "RSSI_VALID")
872                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "CARRIER_SENSE_VALID")
873                     .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "CARRIER_SENSE") // 0 means "channel clear"
874                     .WithValueField(3, 4, FieldMode.Read, valueProviderCallback: _ => Rssi & 0xf, name: "RSSI_3_0") // Usually this part is 0
875                 },
876                 {(long)ExtendedRegisters.LinkQualityIndicator, new ByteRegister(this)
877                     .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: _ => Lqi, name: "LQI")
878                     .WithFlag(7, out crcOK, FieldMode.Read, name: "PKT_CRC_OK")
879                 },
880                 {(long)ExtendedRegisters.PartNumber, new ByteRegister(this)
881                     .WithValueField(0, 8, valueProviderCallback: _ => 0x20) //CC1200. 0x21 for CC1201
882                 },
883                 {(long)ExtendedRegisters.TxFIFONumberOfBytes, new ByteRegister(this)
884                     // Register does not show actual FIFO size, just <0, 15>, where 15 means that there could be more bytes in FIFO than 15
885                     .WithValueField(0, 4, valueProviderCallback: _ =>
886                     {
887                         if(txFifo.Count >= 0xF)
888                         {
889                             return 0xF;
890                         }
891                         return (uint)txFifo.Count & 0xF;
892                     }, name: "FIFO_TXBYTES")
893                     .WithReservedBits(4, 4)
894                 },
895                 {(long)ExtendedRegisters.RxFIFONumberOfBytes, new ByteRegister(this)
896                     // Register does not show actual FIFO size, just <0, 15>, where 15 means that there could be more bytes in FIFO than 15
897                     .WithValueField(0, 4, valueProviderCallback: _ =>
898                     {
899                         if(rxFifo.Count >= 0xF)
900                         {
901                             return 0xF;
902                         }
903                         return (uint)rxFifo.Count & 0xF;
904                     }, name: "FIFO_RXBYTES")
905                     .WithReservedBits(4, 4)
906                 },
907             };
908             extendedRegisters = new ByteRegisterCollection(this, extDict);
909         }
910 
911         private uint frequency;
912         private IValueRegisterField fifoThreshold;
913         private IFlagRegisterField appendStatus;
914         private IValueRegisterField packetLengthByteConfig;
915         private IEnumRegisterField<PacketLengthConfig> packetLengthConfig;
916 #region vars
917         private StateMachineMode stateMachineMode;
918 
919         private IEnumRegisterField<GPIOSignal> gpio3Selection;
920         private IEnumRegisterField<GPIOSignal> gpio2Selection;
921         private IEnumRegisterField<GPIOSignal> gpio1Selection;
922         private IEnumRegisterField<GPIOSignal> gpio0Selection;
923         private IFlagRegisterField crcAutoflush;
924 
925         private bool crcEnabled;
926         private bool wasSyncTransfered;
927 
928         private byte[] currentFrame;
929 
930         private readonly CircularBuffer<byte> txFifo = new CircularBuffer<byte>(0x80);
931         private readonly CircularBuffer<byte> rxFifo = new CircularBuffer<byte>(0x80);
932 
933         private ByteRegisterCollection registers;
934         private ByteRegisterCollection extendedRegisters;
935 
936         private const uint Rssi = 0xB60; // 0xB60 is a value of -74dBm - which is a good quality signal
937         private const uint Lqi = 105; // Approx values <50, 110> are good, where 110 is the best signal quality
938         private const int RegisterMemorySize = 0x80;
939         private const uint TxFifoMemoryStart = 0x100;
940         private const int TxFifoMemorySize = 0x80;
941         private const uint RxFifoMemoryStart = 0x180;
942         private const int RxFifoMemorySize = 0x80;
943         private const uint GeneralMemoryStart = 0x200;
944         private const int GeneralMemorySize = 0x180;
945         private const uint SourceAddressTableStart = 0x380;
946         private const int SourceAddressTableSize = 0x60;
947         private const uint SourceAddressMatchingResultStart = 0x3E0;
948         private const int SourceAddressMatchingResultSize = 0x4;
949         private const uint SourceAddressMatchingControlStart = 0x3E4;
950         private const int SourceAddressMatchingControlSize = 0x6;
951         private const uint LocalAddressInfoStart = 0x3EA;
952         private const int LocalAddressInfoSize = 0xC;
953         private const int NumberOfGPIOs = 5;
954 
955         private const int BroadcastPanIdentifier = 0xFFFF;
956         private const byte NoSourceIndex = 0x3F;
957 #endregion
958 
959         private StateMachineMode txOffMode;
960         private StateMachineMode rxOffMode;
961         private CRCPolynomial crcPolynomial;
962         private uint crcInitialValue;
963         private IValueRegisterField deviceAddress;
964         private IValueRegisterField addressCheckConfig;
965         private IFlagRegisterField terminateOnBadPacket;
966         private IFlagRegisterField crcOK;
967 
968         private enum PacketLengthConfig
969         {
970             Fixed,
971             VariableFirstByte,
972             Infinite,
973             Variable5LSB
974         }
975 
976         private enum GPIOSignal : byte
977         {
978             RxFifoThreshold = 0,
979             RxFifoThresholdOrPacketEnd = 1,
980             TxFifoThreshold = 2,
981             TxFifoFull = 3,
982             RxFifoOverflow = 4,
983             TxFifoUnderflow = 5,
984             PacketSync = 6,
985             CRCOk = 7,
986             SerialClock = 8,
987             SerialRxData = 9,
988         //    Reserved,
989             PreambleQualityReached = 11,
990             PreambleQualityValid = 12,
991             RSSIValid = 13,
992             RSSISignal = 14,
993             ClearChannelAssessment = 15,
994             CarrierSenseValid = 16,
995             CarrierSense = 17,
996             DSSSSignals = 18,
997             PacketCRCOk = 19,
998             MCUWakeup = 20,
999             DualSyncDetect = 21,
1000             AESCommandActive = 22,
1001             CommonLNAAndPARegulatorControl = 23,
1002             ControlExternalLNA = 24,
1003             ControlExternalPA = 25,
1004             IsNotIdle = 26,
1005       //      Reserved,
1006             ImageFound = 28,
1007             DataClockForDemodulator = 29,
1008             DataClockForModulator = 30,
1009             //reserved
1010             RSSIStepFound = 33,
1011             AESRunOrRSSIStepDetected = 34,
1012             Lock = 35,
1013             AntennaSelect = 36,
1014             MARCStateStatus1 = 37,
1015             MARCStateStatus0 = 38,
1016             TxOverflowOrRxUnderflow = 39,
1017             ChannelFilterSettled = 40,
1018             CollisionEvent = 41,
1019             RampingStarted = 42,
1020             PacketError = 43,
1021             AGCStableGain = 44,
1022             AGCUpdate = 45,
1023             ADC = 46,
1024             //reserved
1025             HighImpedance = 48,
1026             ExternalClock = 49,
1027             ChipReadyN = 50,
1028             HW0 = 51,
1029             //reserved
1030             Clock40K = 54,
1031             WOREvent0 = 55,
1032             WOREvent1 = 56,
1033             WOREvent2 = 57,
1034             //reserverd
1035             OscillatorStable = 59,
1036             ExternalOscillatorEnable = 60
1037         }
1038 
1039         private enum Command
1040         {
1041             ResetChip = 0x30,
1042             EnableAndCalibrateFrequencySynthesizer,
1043             EnterXOff,
1044             CalibrateAndDisableSynthesizer,
1045             EnableRx,
1046             EnableTx,
1047             Idle,
1048             AutomaticFrequencyCompensation,
1049             StartRXPollingSequence,
1050             Sleep,
1051             FlushRX,
1052             FlushTX,
1053             ResetEWORTimer,
1054             NoOperation
1055         }
1056 
1057         //only the states relevant for GetStatus are implemented
1058         private enum StateMachineMode
1059         {
1060             Idle = 0,
1061             ReceiveMode = 1,
1062             TransmitMode = 2,
1063             FastTxReady = 3,
1064             Calibrate = 4,
1065             Settling = 5,
1066             RxFIFOError = 6,
1067             TxFIFOError = 7,
1068             Off, //this is not a part of the docs, used for flow control
1069         }
1070 
1071         private enum Registers
1072         {
1073             GPIO3Pin = 0x0,
1074             GPIO2Pin = 0x1,
1075             GPIO1Pin = 0x2,
1076             GPIO0Pin = 0x3,
1077             Sync3Word = 0x4,
1078             Sync2Word = 0x5,
1079             Sync1Word = 0x6,
1080             Sync0Word = 0x7,
1081             SyncWord1 = 0x8,
1082             SyncWord0 = 0x9,
1083             FrequencyDeviation = 0xa,
1084             ModulationFormatAndFrequencyDeviation = 0xb,
1085             DigitalDCRemoval = 0xc,
1086             Preamble1 = 0xd,
1087             Preamble0 = 0xe,
1088             DigitalImageChannelCompensation = 0xf,
1089             ChannelFilter = 0x10,
1090             GeneralModemParameter1 = 0x11,
1091             GeneralModemParameter0 = 0x12,
1092             SymbolRate2 = 0x13,
1093             SymbolRate1 = 0x14,
1094             SymbolRate0 = 0x15,
1095             AGCReferenceLevel = 0x16,
1096             CarrierSenseThreshold = 0x17,
1097             RSSIOffset = 0x18,
1098             AutomaticGainControl3 = 0x19,
1099             AutomaticGainControl2 = 0x1a,
1100             AutomaticGainControl1 = 0x1b,
1101             AutomaticGainControl0 = 0x1c,
1102             FIFOConfiguration = 0x1d,
1103             DeviceAddress = 0x1e,
1104             FrequencySynthesizerCalibrationAndSettling = 0x1f,
1105             FrequencySynthesizerConfiguration = 0x20,
1106             EWORConfiguration1 = 0x21,
1107             EWORConfiguration0 = 0x22,
1108             Event0MSB = 0x23,
1109             Event0LSB = 0x24,
1110             RXDutyCycleMode = 0x25,
1111             PacketConfiguration2 = 0x26,
1112             PacketConfiguration1 = 0x27,
1113             PacketConfiguration0 = 0x28,
1114             RFENDConfiguration1 = 0x29,
1115             RFENDConfiguration0 = 0x2a,
1116             PowerAmplifier1 = 0x2b,
1117             PowerAmplifier0 = 0x2c,
1118             ASKConfiguration = 0x2d,
1119             PacketLength = 0x2e,
1120             ExtendedAddress = 0x2f,
1121 
1122             //command strobes
1123             SRES = 0x30,
1124             SFSTXON = 0x31,
1125             SXOFF = 0x32,
1126             SCAL = 0x33,
1127             SRX = 0x34,
1128             STX = 0x35,
1129             SIDLE = 0x36,
1130             SAFC = 0x37,
1131             SWOR = 0x38,
1132             SPWD = 0x39,
1133             SFRX = 0x3a,
1134             SFTX = 0x3b,
1135             SWORRST = 0x3c,
1136             SNOP = 0x3d,
1137         }
1138 
1139         private enum ExtendedRegisters
1140         {
1141             IFMixConfiguration = 0x0,
1142             FrequencyOffsetCorrection = 0x1,
1143             TimingOffsetCorrection = 0x2,
1144             MARCSpare = 0x3,
1145             ExternalClockFrequency = 0x4,
1146             GeneralModemParameter2 = 0x5,
1147             ExternalControl = 0x6,
1148             RCOscillatorCalibrationFine = 0x7,
1149             RCOscillatorCalibrationCourse = 0x8,
1150             RCOscillatorCalibrationClockOffset = 0x9,
1151             FrequencyOffsetMSB = 0xa,
1152             FrequencyOffsetLSB = 0xb,
1153             Frequency2 = 0xc,
1154             Frequency1 = 0xd,
1155             Frequency0 = 0xe,
1156             ADCConfiguration2 = 0xf,
1157             ADCConfiguration1 = 0x10,
1158             ADCConfiguration0 = 0x11,
1159             FrequencySynthesizerDigital1 = 0x12,
1160             FrequencySynthesizerDigital0 = 0x13,
1161             FrequencySynthesizerCalibration3 = 0x14,
1162             FrequencySynthesizerCalibration2 = 0x15,
1163             FrequencySynthesizerCalibration1 = 0x16,
1164             FrequencySynthesizerCalibration0 = 0x17,
1165             FrequencySynthesizerChargePump = 0x18,
1166             FrequencySynthesizerDivideByTwo = 0x19,
1167             DigitalSynthesizerModule1 = 0x1a,
1168             DigitalSynthesizerModule0 = 0x1b,
1169             FrequencySynthesizerDividerChain1 = 0x1c,
1170             FrequencySynthesizerDividerChain0 = 0x1d,
1171             FrequencySynthesizerLocalBias = 0x1e,
1172             FrequencySynthesizerPhaseFrequencyDetector = 0x1f,
1173             FrequencySynthesizerPrescaler = 0x20,
1174             FrequencySynthesizerDividerRegulator = 0x21,
1175             FrequencySynthesizerSpare = 0x22,
1176             FrequencySynthesizerVoltageControlOscillator4 = 0x23,
1177             FrequencySynthesizerVoltageControlOscillator3 = 0x24,
1178             FrequencySynthesizerVoltageControlOscillator2 = 0x25,
1179             FrequencySynthesizerVoltageControlOscillator1 = 0x26,
1180             FrequencySynthesizerVoltageControlOscillator0 = 0x27,
1181             GlobalBias6 = 0x28,
1182             GlobalBias5 = 0x29,
1183             GlobalBias4 = 0x2a,
1184             GlobalBias3 = 0x2b,
1185             GlobalBias2 = 0x2c,
1186             GlobalBias1 = 0x2d,
1187             GlobalBias0 = 0x2e,
1188             IntermediateFrequencyAmplifier = 0x2f,
1189             LowNoiseAmplifier = 0x30,
1190             RXMixer = 0x31,
1191             CrystalOscillator5 = 0x32,
1192             CrystalOscillator4 = 0x33,
1193             CrystalOscillator3 = 0x34,
1194             CrystalOscillator2 = 0x35,
1195             CrystalOscillator1 = 0x36,
1196             CrystalOscillator0 = 0x37,
1197             AnalogSpare = 0x38,
1198             PowerAmplifier3 = 0x39,
1199             //0x3A-0x3E not used, 0x3F-0x40 reserved, 0x41-0x63 not used
1200             EWORTimerCounterValueMSB = 0x64,
1201             EWORTimerCounterValueLSB = 0x65,
1202             EWORTimerCaptureValueMSB = 0x66,
1203             EWORTimerCaptureValueLSB = 0x67,
1204             MARCBuiltInSelfTest = 0x68,
1205             DCFilterOffsetIMSB = 0x69,
1206             DCFilterOffsetILSB = 0x6a,
1207             DCFilterOffsetQMSB = 0x6b,
1208             DCFilterOffsetQLSB = 0x6c,
1209             IQImbalanceValueIMSB = 0x6d,
1210             IQImbalanceValueILSB = 0x6e,
1211             IQImbalanceValueQMSB = 0x6f,
1212             IQImbalanceValueQLSB = 0x70,
1213             ReceivedSignalStrengthIndicator1 = 0x71,
1214             ReceivedSignalStrengthIndicator0 = 0x72,
1215             MARCState = 0x73,
1216             LinkQualityIndicator = 0x74,
1217             PreambleAndSyncWordError = 0x75,
1218             DemodulatorStatus = 0x76,
1219             FrequencyOffsetEstimateMSB = 0x77,
1220             FrequencyOffsetEstimateLSB = 0x78,
1221             AutomaticGainControl3 = 0x79,
1222             AutomaticGainControl2 = 0x7a,
1223             AutomaticGainControl1 = 0x7b,
1224             AutomaticGainControl0 = 0x7c,
1225             CustomFrequencyModulationRxData = 0x7d,
1226             CustomFrequencyModulationTxData = 0x7e,
1227             ASKSoftDecisionOutput = 0x7f,
1228             RandomNumberGeneratorValue = 0x80,
1229             SignalMagnitudeAfterCORDIC2 = 0x81,
1230             SignalMagnitudeAfterCORDIC1 = 0x82,
1231             SignalMagnitudeAfterCORDIC0 = 0x83,
1232             SignalAngularAfterCORDIC1 = 0x84,
1233             SignalAngularAfterCORDIC0 = 0x85,
1234             ChannelFilterDataI2 = 0x86,
1235             ChannelFilterDataI1 = 0x87,
1236             ChannelFilterDataI0 = 0x88,
1237             ChannelFilterDataQ2 = 0x89,
1238             ChannelFilterDataQ1 = 0x8a,
1239             ChannelFilterDataQ0 = 0x8b,
1240             GPIOStatus = 0x8c,
1241             FrequencySynthesizerCalibration = 0x8d,
1242             FrequencySynthesizerPhaseAdjust = 0x8e,
1243             PartNumber = 0x8f,
1244             PartVersion = 0x90,
1245             SerialStatus = 0x91,
1246             ModemStatus1 = 0x92,
1247             ModemStatus0 = 0x93,
1248             MARCStatus1 = 0x94,
1249             MARCStatus0 = 0x95,
1250             PowerAmplifierIntermediateFrequencyAmplifierTest = 0x96,
1251             FrequencySynthesizerTest = 0x97,
1252             FrequencySynthesizerPrescalerTest = 0x98,
1253             FrequencySynthesizerPrescalerOverride = 0x99,
1254             AnalogToDigitalConverterTest = 0x9a,
1255             DigitalDividerChainTest = 0x9b,
1256             AnalogTest = 0x9c,
1257             AnalogTestLVDS = 0x9d,
1258             AnalogTestMode = 0x9e,
1259             CrystalOscillatorTest1 = 0x9f,
1260             CrystalOscillatorTest0 = 0xa0,
1261             AdvancedEncryptionStandardStatus = 0xa1,
1262             ModemTest = 0xa2,
1263             //0xA3-0xD1 not used
1264             RxFIFOPointerFirstEntry = 0xd2,
1265             TxFIFOPointerFirstEntry = 0xd3,
1266             RxFIFOPointerLastEntry = 0xd4,
1267             TxFIFOPointerLastEntry = 0xd5,
1268             TxFIFONumberOfBytes = 0xd6,
1269             RxFIFONumberOfBytes = 0xd7,
1270             TxFIFONumberOfFreeEntries = 0xd8,
1271             RxFIFONumberOfFreeEntries = 0xd9,
1272             RxFIFOFirstByteWhenEmpty = 0xda,
1273             //0xDB-0xDF not used
1274             AdvancedEncryptionStandardKey15 = 0xe0,
1275             AdvancedEncryptionStandardKey14 = 0xe1,
1276             AdvancedEncryptionStandardKey13 = 0xe2,
1277             AdvancedEncryptionStandardKey12 = 0xe3,
1278             AdvancedEncryptionStandardKey11 = 0xe4,
1279             AdvancedEncryptionStandardKey10 = 0xe5,
1280             AdvancedEncryptionStandardKey9 = 0xe6,
1281             AdvancedEncryptionStandardKey8 = 0xe7,
1282             AdvancedEncryptionStandardKey7 = 0xe8,
1283             AdvancedEncryptionStandardKey6 = 0xe9,
1284             AdvancedEncryptionStandardKey5 = 0xea,
1285             AdvancedEncryptionStandardKey4 = 0xeb,
1286             AdvancedEncryptionStandardKey3 = 0xec,
1287             AdvancedEncryptionStandardKey2 = 0xed,
1288             AdvancedEncryptionStandardKey1 = 0xee,
1289             AdvancedEncryptionStandardKey0 = 0xef,
1290             AdvancedEncryptionStandardBuffer15 = 0xf0,
1291             AdvancedEncryptionStandardBuffer14 = 0xf1,
1292             AdvancedEncryptionStandardBuffer13 = 0xf2,
1293             AdvancedEncryptionStandardBuffer12 = 0xf3,
1294             AdvancedEncryptionStandardBuffer11 = 0xf4,
1295             AdvancedEncryptionStandardBuffer10 = 0xf5,
1296             AdvancedEncryptionStandardBuffer9 = 0xf6,
1297             AdvancedEncryptionStandardBuffer8 = 0xf7,
1298             AdvancedEncryptionStandardBuffer7 = 0xf8,
1299             AdvancedEncryptionStandardBuffer6 = 0xf9,
1300             AdvancedEncryptionStandardBuffer5 = 0xfa,
1301             AdvancedEncryptionStandardBuffer4 = 0xfb,
1302             AdvancedEncryptionStandardBuffer3 = 0xfc,
1303             AdvancedEncryptionStandardBuffer2 = 0xfd,
1304             AdvancedEncryptionStandardBuffer1 = 0xfe,
1305             AdvancedEncryptionStandardBuffer0 = 0xff,
1306         }
1307     }
1308 }
1309 
1310