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.Wireless.IEEE802_15_4;
16 using Antmicro.Renode.Utilities;
17 
18 namespace Antmicro.Renode.Peripherals.Wireless
19 {
20     public sealed class CC2520: IRadio, ISPIPeripheral, INumberedGPIOOutput, IGPIOReceiver
21     {
CC2520()22         public CC2520()
23         {
24             CreateRegisters();
25             RegisterInstructions();
26             var dict = new Dictionary<int, IGPIO>();
27             for(var i = 0; i < NumberOfGPIOs; ++i)
28             {
29                 dict[i] = new GPIO();
30             }
31             Connections = new ReadOnlyDictionary<int, IGPIO>(dict);
32             Reset();
33         }
34 
Reset()35         public void Reset()
36         {
37             isRxEnabled = false;
38             inReset = true;
39             vregEnabled = false;
40             oscillatorRunning = false;
41             wasLastFrameSent = false;
42 
43             currentFrame = null;
44 
45             txFifo.Clear();
46             rxFifo.Clear();
47             memory = new byte[GeneralMemorySize];
48             sourceAddressTable = new byte[SourceAddressTableSize];
49             sourceAddressMatchingResult = new byte[SourceAddressMatchingResultSize];
50             sourceAddressMatchingControl = new byte[SourceAddressMatchingControlSize];
51             localAddressInfo = new byte[LocalAddressInfoSize];
52 
53             localExtendedAddress = new Address(new ArraySegment<byte>(localAddressInfo, 0, 8));
54             localShortAddress = new Address(new ArraySegment<byte>(localAddressInfo, 10, 2));
55 
56             currentInstruction = null;
57 
58             registers.Reset();
59             foreach(var gpio in Connections.Values)
60             {
61                 gpio.Unset();
62             }
63         }
64 
OnGPIO(int number, bool value)65         public void OnGPIO(int number, bool value)
66         {
67             const int voltageRegulatorEnable = 0;
68             const int notReset = 1;
69             if(number == notReset)
70             {
71                 inReset = !value;
72                 if(!inReset)
73                 {
74                     oscillatorRunning = true;
75                 }
76             }
77             else if(number == voltageRegulatorEnable)
78             {
79                 vregEnabled = value;
80             }
81             else
82             {
83                 //we don't want to accidentally reset on another input
84                 return;
85             }
86             if(inReset && !vregEnabled)
87             {
88                 this.Log(LogLevel.Debug, "Resetting radio...");
89                 Reset();
90             }
91             UpdateInterrupts();
92         }
93 
Irqs()94         public bool[] Irqs()
95         {
96             return Connections.Values.Select(x => x.IsSet).ToArray();
97         }
98 
Transmit(byte data)99         public byte Transmit(byte data)
100         {
101             this.Log(LogLevel.Noisy, "Writing to radio: 0x{0:X}", data);
102             if(currentInstruction == null)
103             {
104                 if(!decoderRoot.TryParseOpcode(data, out currentInstruction))
105                 {
106                     this.Log(LogLevel.Error, "Cannot find opcode in value 0b{0} (0x{1:X})".FormatWith(Convert.ToString(data, 2).PadLeft(8,'0'), data));
107                     return 0;
108                 }
109                 this.Log(LogLevel.Debug, "Setting command to: {0}", currentInstruction.Name);
110             }
111             var returnValue = currentInstruction.Parse(data);
112             if(currentInstruction.IsFinished)
113             {
114                 currentInstruction = null;
115             }
116             return returnValue;
117         }
118 
FinishTransmission()119         public void FinishTransmission()
120         {
121             currentInstruction = null;
122             this.Log(LogLevel.Debug, "Finish transmission");
123         }
124 
ReceiveFrame(byte[] bytes, IRadio sender)125         public void ReceiveFrame(byte[] bytes, IRadio sender)
126         {
127             if(isRxEnabled)
128             {
129                 //this allows to have proper CCA values easily.
130                 currentFrame = bytes;
131                 HandleFrame(bytes);
132                 currentFrame = null;
133             }
134             else
135             {
136                 currentFrame = bytes;
137                 this.DebugLog("Radio is not listening right now - this frame is being deffered.");
138             }
139         }
140 
141         public int Channel
142         {
143             get
144             {
145                 return ChannelValueFromFrequency((uint)channel.Value);
146             }
147 
148             set
149             {
150                 this.Log(LogLevel.Info, "Setting channel to {0}", value);
151                 channel.Value = ChannelNumberToFrequency(value);
152             }
153         }
154 
155         public IReadOnlyDictionary<int, IGPIO> Connections
156         {
157             get; private set;
158         }
159 
160         public event Action<IRadio, byte[]> FrameSent;
161 
HandleFrame(byte[] bytes)162         private void HandleFrame(byte[] bytes)
163         {
164             Frame ackFrame = null;
165 
166             SetException(ExceptionFlags.StartOfFrameDelimiter);
167             var frame = new Frame(bytes);
168             var isCrcOk = frame.CheckCRC();
169 
170             var autoPendingResult = false;
171             byte sourceMatchingIndex = NoSourceIndex;
172 
173             if(frameFilteringEnabled.Value)
174             {
175                 if(!ShouldAcceptFrame(frame))
176                 {
177                     this.Log(LogLevel.Debug, "Not accepting the frame");
178                     return;
179                 }
180                 SetException(ExceptionFlags.RxFrameAccepted);
181 
182                 if(sourceMatchingEnabled.Value)
183                 {
184                     //algorithm described in the docs, chapter 20.3.3
185                     var sourceMatchingMask = 0u;
186                     if(frame.SourceAddressingMode == AddressingMode.ShortAddress)
187                     {
188                         uint sourceMatchingShortEnabled = (uint)((shortAddressMatchingEnabled[2].Value << 16) | (shortAddressMatchingEnabled[1].Value << 8) | shortAddressMatchingEnabled[0].Value);
189                         for(byte i = 0; i < 24; ++i)
190                         {
191                             var mask = 1u << i;
192                             if((sourceMatchingShortEnabled & mask) == 0)
193                             {
194                                 continue;
195                             }
196                             if(frame.AddressInformation.SourcePan == GetSourceAddressMatchingPanId(i)
197                                && frame.AddressInformation.SourceAddress.GetValue() == GetSourceAddressMatchingShortAddress(i))
198                             {
199                                 sourceMatchingMask |= mask;
200                                 if(sourceMatchingIndex == NoSourceIndex)
201                                 {
202                                     autoPendingResult = VerifyAutoPending(frame.SourceAddressingMode, frame.Type, i);
203                                     sourceMatchingIndex = (byte)(i | (autoPendingResult ? 1 << 6 : 0));
204                                 }
205                             }
206                         }
207                     }
208                     else if(frame.SourceAddressingMode == AddressingMode.ExtendedAddress)
209                     {
210                         uint sourceMatchingExtendedEnabled = (uint)((extendedAddressMatchingEnabled[2].Value << 16) | (extendedAddressMatchingEnabled[1].Value << 8) | extendedAddressMatchingEnabled[0].Value);
211                         for(byte i = 0; i < 12; ++i)
212                         {
213                             var mask = 3u << (2 * i);
214                             if((sourceMatchingExtendedEnabled & mask) == 0)
215                             {
216                                 continue;
217                             }
218                             if(frame.AddressInformation.SourceAddress.GetValue() == GetSourceAddressMatchingExtendedAddress(i))
219                             {
220                                 sourceMatchingMask |= mask;
221                                 if(sourceMatchingIndex == NoSourceIndex)
222                                 {
223                                     autoPendingResult = VerifyAutoPending(frame.SourceAddressingMode, frame.Type, i);
224                                     sourceMatchingIndex = (byte)(i | 0x20 | (autoPendingResult ? 1 << 6 : 0));
225                                 }
226                             }
227                         }
228                     }
229                     BitConverter.GetBytes(sourceMatchingMask).CopyTo(sourceAddressMatchingResult, 0);
230                     sourceAddressMatchingResult[3] = sourceMatchingIndex;
231                     SetException(ExceptionFlags.SourceMatchingDone);
232                     if(sourceMatchingIndex != NoSourceIndex)
233                     {
234                         SetException(ExceptionFlags.SourceMatchingFound);
235                     }
236                 }
237             }
238             if(autoCrc.Value)
239             {
240                 byte secondByte = 0;
241                 if(isCrcOk)
242                 {
243                     secondByte |= 1 << 7;
244                 }
245                 if(appendDataMode.Value)
246                 {
247                     //Theoretically sourceMatchingIndex might not be valid here if the matching was not performed.
248                     //This set of conditions is defined in the docs, though.
249                     secondByte |= sourceMatchingIndex;
250                 }
251                 else
252                 {
253                     secondByte |= 100; // correlation value 100 means near maximum quality
254                 }
255                 frame.Bytes[frame.Bytes.Length - 2] = 70; //as in CC2538
256                 frame.Bytes[frame.Bytes.Length - 1] = secondByte;
257             }
258             rxFifo.Enqueue(frame.Length);
259             foreach(var item in frame.Bytes)
260             {
261                 rxFifo.Enqueue(item);
262             }
263             //Not filtering for length because a full frame was received. This might be an issue in a more general sense, as we do not support partial frames.
264             SetException(ExceptionFlags.FifoThresholdReached);
265 
266             SetException(ExceptionFlags.RxFrameDone);
267             if(isCrcOk && autoAck.Value
268                     && frame.AcknowledgeRequest
269                     && frame.Type != FrameType.Beacon
270                     && frame.Type != FrameType.ACK)
271             {
272                 ackFrame = Frame.CreateACK(frame.DataSequenceNumber, autoPendingResult || pendingAlwaysOn.Value);
273             }
274             var frameSent = FrameSent;
275             if(frameSent != null && ackFrame != null)
276             {
277                 frameSent(this, ackFrame.Bytes);
278                 SetException(ExceptionFlags.TxAckDone);
279             }
280         }
281 
VerifyAutoPending(AddressingMode mode, FrameType type, byte i)282         bool VerifyAutoPending(AddressingMode mode, FrameType type, byte i)
283         {
284             if(!autoPendingFlag.Value)
285             {
286                 return false;
287             }
288             if(pendingDataRequestOnly.Value && type != FrameType.Data)
289             {
290                 return false;
291             }
292             var index = i / 8;
293             var position = (byte)(i % 8);
294             if(mode == AddressingMode.ShortAddress)
295             {
296                 //first three bytes are for extended addresses, then three short addresses
297                 index += 3;
298             }
299             return BitHelper.IsBitSet(sourceAddressMatchingControl[index], position);
300         }
301 
GetSourceAddressMatchingPanId(int i)302         private ushort GetSourceAddressMatchingPanId(int i)
303         {
304             return BitConverter.ToUInt16(sourceAddressTable, 4 * i);
305         }
306 
GetSourceAddressMatchingShortAddress(int i)307         private ushort GetSourceAddressMatchingShortAddress(int i)
308         {
309             return BitConverter.ToUInt16(sourceAddressTable, 4 * i + 2);
310         }
311 
GetSourceAddressMatchingExtendedAddress(int i)312         private ulong GetSourceAddressMatchingExtendedAddress(int i)
313         {
314             return BitConverter.ToUInt64(sourceAddressTable, 8 * i);
315         }
316 
ShouldAcceptFrame(Frame frame)317         private bool ShouldAcceptFrame(Frame frame)
318         {
319             var frameType = frame.Type;
320             switch(modifyFrameTypeFilter.Value)
321             {
322             case ModifyFieldTypeMode.InvertMSB:
323                 frameType = (FrameType)((int)frameType ^ 4);
324                 break;
325             case ModifyFieldTypeMode.SetMSB:
326                 frameType = (FrameType)((int)frameType | 4);
327                 break;
328             case ModifyFieldTypeMode.UnsetMSB:
329                 frameType = (FrameType)((int)frameType & 3);
330                 break;
331             }
332 
333             //1. Check minimum frame length
334             //2. Check reserved FCF bits
335             if((((frame.FrameControlField >> 7) & 7) & frameControlFieldReservedMask.Value) != 0)
336             {
337                 this.Log(LogLevel.Noisy, "Wrong FCF reserved field. Dropping frame.");
338                 return false;
339             }
340 
341             //3. Check frame version
342             if(frame.FrameVersion > maxFrameVersion.Value)
343             {
344                 this.Log(LogLevel.Noisy, "Frame version too high. Got 0x{0:X}, expected at most 0x{1:X}. Dropping frame.", frame.FrameVersion, maxFrameVersion.Value);
345                 return false;
346             }
347 
348             //4. Check address modes
349             if(frame.SourceAddressingMode == AddressingMode.Reserved)
350             {
351                 this.Log(LogLevel.Noisy, "Reserved source addressing mode. Dropping frame.");
352                 return false;
353             }
354             if(frame.DestinationAddressingMode == AddressingMode.Reserved)
355             {
356                 this.Log(LogLevel.Noisy, "Reserved destination addressing mode. Dropping frame.");
357                 return false;
358             }
359 
360             //5. Check destination address
361             if(frame.DestinationAddressingMode != AddressingMode.None)
362             {
363                 //this IntraPAN is kind of a guess. We could use source PAN Id instead, but the documentation says clearly: "If a destination PAN ID is included in the frame"
364                 if(!frame.IntraPAN && frame.AddressInformation.DestinationPan != GetPanId() && frame.AddressInformation.DestinationPan != BroadcastPanIdentifier)
365                 {
366                     this.Log(LogLevel.Noisy, "Invalid destination PAN: got 0x{0:X}, expected 0x{1:X} or 0x{2:X}. Dropping frame.", frame.AddressInformation.DestinationPan, GetPanId(), BroadcastPanIdentifier);
367                     return false;
368                 }
369                 if(frame.DestinationAddressingMode == AddressingMode.ShortAddress)
370                 {
371                     if(!frame.AddressInformation.DestinationAddress.IsShortBroadcast && !frame.AddressInformation.DestinationAddress.Equals(localShortAddress))
372                     {
373                         this.Log(LogLevel.Noisy, "Invalid destination short address (I'm {0}, but the message is directed to {1}). Dropping frame.", localShortAddress.GetValue(), frame.AddressInformation.DestinationAddress.GetValue());
374                         return false;
375                     }
376                 }
377                 // (5.3) check destination extended address
378                 else if(frame.DestinationAddressingMode == AddressingMode.ExtendedAddress)
379                 {
380                     if(!frame.AddressInformation.DestinationAddress.Equals(localExtendedAddress))
381                     {
382                         this.Log(LogLevel.Noisy, "Invalid destination extended address (I'm {0}, but the message is directed to {1}). Dropping frame.", localExtendedAddress.GetValue(), frame.AddressInformation.DestinationAddress.GetValue());
383                         return false;
384                     }
385                 }
386             }
387             //6. Check frame type
388             switch(frameType)
389             {
390             case FrameType.Beacon:
391                 if(!acceptBeaconFrames.Value
392                    || frame.Length < 9
393                    || frame.DestinationAddressingMode != AddressingMode.None
394                    || (frame.SourceAddressingMode != AddressingMode.ShortAddress && frame.SourceAddressingMode != AddressingMode.ExtendedAddress)
395                    || (frame.AddressInformation.SourcePan != BroadcastPanIdentifier && frame.AddressInformation.SourcePan != GetPanId()))
396                 {
397                     this.Log(LogLevel.Noisy, "Beacon frame not accepted. Dropping frame.");
398                     return false;
399                 }
400                 break;
401             case FrameType.Data:
402                 if(!acceptDataFrames.Value
403                    || frame.Length < 9
404                    || (frame.DestinationAddressingMode == AddressingMode.None && frame.SourceAddressingMode == AddressingMode.None)
405                    || (frame.DestinationAddressingMode == AddressingMode.None
406                        && (!panCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId())))
407                 {
408                     this.Log(LogLevel.Noisy, "Data frame not accepted. Dropping frame.");
409                     return false;
410                 }
411                 break;
412             case FrameType.ACK:
413                 if(!acceptAckFrames.Value || frame.Length != 5)
414                 {
415                     this.Log(LogLevel.Noisy, "ACK frame not accepted. Dropping frame.");
416                     return false;
417                 }
418                 break;
419             case FrameType.MACControl:
420                 if(!acceptMacCommandFrames.Value
421                    || frame.Length < 9
422                    || (frame.DestinationAddressingMode == AddressingMode.None
423                        && (!panCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId())))
424                 {
425                     this.Log(LogLevel.Noisy, "MAC control frame not accepted. Dropping frame.");
426                     return false;
427                 }
428                 break;
429             default:
430                 if(!acceptReservedFrames.Value || frame.Length < 9)
431                 {
432                     this.Log(LogLevel.Noisy, "Reserved frame not accepted. Dropping frame.");
433                     return false;
434                 }
435                 break;
436             }
437             return true;
438         }
439 
SendFrame()440         private void SendFrame()
441         {
442             var length = txFifo.Peek();
443             var data = txFifo.Skip(1).ToArray();
444             Frame frame;
445             if(autoCrc.Value)
446             {
447                 var crc = Frame.CalculateCRC(data);
448                 frame = new Frame(data.Concat(crc).ToArray());
449             }
450             else
451             {
452                 frame = new Frame(data);
453             }
454             if(length > frame.Length && !ignoreTxUnderflow.Value)
455             {
456                 SetException(ExceptionFlags.TxUnderflow);
457                 this.Log(LogLevel.Warning, "Frame dropped because of TX underflow. Expected length: {0}. Frame length: {1}.", length, frame.Length);
458                 return;
459                 //ignoreTxUnderflow should probably transmit whatever data is written to the tx fifo after this transfer. This would be difficult to model, as we do not support "wrong" frames yet.
460             }
461             this.DebugLog("Sending frame {0}.", frame.Bytes.Select(x => "0x{0:X}".FormatWith(x)).Stringify());
462             var frameSent = FrameSent;
463             if(frameSent != null)
464             {
465                 frameSent(this, frame.Bytes);
466             }
467             wasLastFrameSent = true;
468             SetException(ExceptionFlags.StartOfFrameDelimiter);
469             SetException(ExceptionFlags.TxFrameDone);
470         }
471 
SetException(ExceptionFlags flag)472         private void SetException(ExceptionFlags flag)
473         {
474             var regNumber = (int)flag / 8;
475             var bit = (int)flag % 8;
476             this.Log(LogLevel.Noisy, "Setting flag {0}", flag);
477             pendingExceptionFlag[regNumber].Value |= 1u << bit;
478             UpdateInterrupts();
479         }
480 
UnsetException(ExceptionFlags flag)481         private void UnsetException(ExceptionFlags flag)
482         {
483             var regNumber = (int)flag / 8;
484             var bit = (int)flag % 8;
485             this.Log(LogLevel.Noisy, "Unsetting flag {0}", flag);
486             pendingExceptionFlag[regNumber].Value &= ~(1u << bit);
487             UpdateInterrupts();
488         }
489 
IsExceptionSet(ExceptionFlags flag)490         private bool IsExceptionSet(ExceptionFlags flag)
491         {
492             var regNumber = (int)flag / 8;
493             var bit = (int)flag % 8;
494             return (pendingExceptionFlag[regNumber].Value & (1u << bit)) != 0;
495         }
496 
UpdateInterrupts()497         private void UpdateInterrupts()
498         {
499             Connections[(int)GPIOs.Cca].Set(currentFrame == null);
500             Connections[(int)GPIOs.Sfd].Set(IsExceptionSet(ExceptionFlags.StartOfFrameDelimiter));
501             Connections[(int)GPIOs.Fifop].Set(IsExceptionSet(ExceptionFlags.FifoThresholdReached));
502             Connections[(int)GPIOs.Fifo].Set(rxFifo.Count > 0 && rxFifo.Count <= RxFifoMemorySize);
503         }
504 
GetStatus()505         private byte GetStatus()
506         {
507             return (byte)(((oscillatorRunning ? 1 : 0) << 7)
508                           | ((isRxEnabled ? 1 : 0) << 6)
509                           | ((currentInstruction != null && currentInstruction.HighPriority.HasValue && currentInstruction.HighPriority.Value ? 1 : 0) << 3)
510                           | ((currentInstruction != null && currentInstruction.HighPriority.HasValue && !currentInstruction.HighPriority.Value ? 1 : 0) << 2)
511                           | ((isRxEnabled ? 1 : 0) << 0));
512             //bits 0 and 1 are responsible for RX/TX states. TX is active after STXON[CCA] command, so it's not interruptible with GetStatus read.
513             //RX is active when isRxEnabled == true, but TX is not active. Again, since cpu will not get status on TX, we ignore the second condition.
514             //DPU bits are mutually exclusive at the moment, but we should implement priorities someday, so I leave them as independent.
515             //EXCEPTION channel A and B bits should be implemented
516             //RSSI is always assumed to be valid in RX mode
517         }
518 
GetPanId()519         private uint GetPanId()
520         {
521             return (uint)((localAddressInfo[9] << 8) | localAddressInfo[8]);
522         }
523 
ChannelValueFromFrequency(uint frequency)524         private int ChannelValueFromFrequency(uint frequency)
525         {
526             //According to documentation, chapter 16:
527             //"Channels are numbered 11 through 26 and are 5MHz apart"
528             return ((int)frequency - 11) / 5 + 11;
529         }
530 
ChannelNumberToFrequency(int channelNumber)531         private uint ChannelNumberToFrequency(int channelNumber)
532         {
533             //According to documentation, chapter 16:
534             //"Channels are numbered 11 through 26 and are 5MHz apart"
535             return (uint)(11 + 5 * (channelNumber - 11));
536         }
537 
CreateRegisters()538         private void CreateRegisters()
539         {
540             var dict = new Dictionary<long, ByteRegister>
541             {
542                 {(long)Registers.FrameFiltering0, new ByteRegister(this, 0xD)
543                                 .WithValueField(4, 3, out frameControlFieldReservedMask, name: "FCF_RESERVED_MASK")
544                                 .WithValueField(2, 2, out maxFrameVersion, name: "MAX_FRAME_VERSION")
545                                 .WithFlag(1, out panCoordinator, name: "PAN_COORDINATOR")
546                                 .WithFlag(0, out frameFilteringEnabled, name: "FRAME_FILTER_EN")
547                 },
548                 {(long)Registers.FrameFiltering1, new ByteRegister(this, 0x78)
549                                 .WithFlag(7, out acceptReservedFrames, name: "ACCEPT_FT_4TO7_RESERVED")
550                                 .WithFlag(6, out acceptMacCommandFrames, name: "ACCEPT_FT_3_MAC_CMD")
551                                 .WithFlag(5, out acceptAckFrames, name: "ACCEPT_FT_2_ACK")
552                                 .WithFlag(4, out acceptDataFrames, name: "ACCEPT_FT_1_DATA")
553                                 .WithFlag(3, out acceptBeaconFrames, name: "ACCEPT_FT_0_BEACON")
554                                 .WithEnumField(1, 2, out modifyFrameTypeFilter, name: "MODIFY_FT_FILTER")
555                 },
556                 {(long)Registers.SourceMatching, new ByteRegister(this, 0x7)
557                                 .WithFlag(2, out pendingDataRequestOnly, name: "PEND_DATAREQ_ONLY")
558                                 .WithFlag(1, out autoPendingFlag, name: "AUTOPEND")
559                                 .WithFlag(0, out sourceMatchingEnabled, name: "SRC_MATCH_EN")
560                 },
561                 {(long)Registers.ShortAddressMatchingEnabled0, new ByteRegister(this)
562                                 .WithValueField(0, 8, out shortAddressMatchingEnabled[0], name: "SHORT_ADDR_EN[7:0]")
563                 },
564                 {(long)Registers.ShortAddressMatchingEnabled1, new ByteRegister(this)
565                                 .WithValueField(0, 8, out shortAddressMatchingEnabled[1], name: "SHORT_ADDR_EN[15:8]")
566                 },
567                 {(long)Registers.ShortAddressMatchingEnabled2, new ByteRegister(this)
568                                 .WithValueField(0, 8, out shortAddressMatchingEnabled[2], name: "SHORT_ADDR_EN[23:16]")
569                 },
570                 {(long)Registers.ExtendedAddressMatchingEnabled0, new ByteRegister(this)
571                                 .WithValueField(0, 8, out extendedAddressMatchingEnabled[0], name: "EXT_ADDR_EN[7:0]")
572                 },
573                 {(long)Registers.ExtendedAddressMatchingEnabled1, new ByteRegister(this)
574                                 .WithValueField(0, 8, out extendedAddressMatchingEnabled[1], name: "EXT_ADDR_EN[15:8]")
575                 },
576                 {(long)Registers.ExtendedAddressMatchingEnabled2, new ByteRegister(this)
577                                 .WithValueField(0, 8, out extendedAddressMatchingEnabled[2], name: "EXT_ADDR_EN[23:16]")
578                 },
579                 {(long)Registers.FrameControl0, new ByteRegister(this, 0x40)
580                                 .WithFlag(7, out appendDataMode, name: "APPEND_DATA_MODE")
581                                 .WithFlag(6, out autoCrc, name: "AUTOCRC")
582                                 .WithFlag(5, out autoAck, name: "AUTOACK")
583                                 .WithTag("ENERGY_SCAN", 4, 1)
584                                 .WithTag("RX_MODE", 2, 2) //I doubt these two will be useful, they are test modes
585                                 .WithTag("TX_MODE", 0, 2)
586                 },
587                 {(long)Registers.FrameControl1, new ByteRegister(this, 0x1)
588                                 .WithFlag(2, out pendingAlwaysOn, name: "PENDING_OR")
589                                 .WithFlag(1, out ignoreTxUnderflow, name: "IGNORE_TX_UNDERF")
590                                 .WithTag("SET_RXENMASK_ON_TX", 0, 1)
591                 },
592                 {(long)Registers.PendingExceptionFlags0, new ByteRegister(this)
593                                 .WithValueField(0, 8, out pendingExceptionFlag[0], FieldMode.Read | FieldMode.WriteZeroToClear, name: "EXCFLAG0")
594                 },
595                 {(long)Registers.PendingExceptionFlags1, new ByteRegister(this)
596                                 .WithValueField(0, 8, out pendingExceptionFlag[1], FieldMode.Read | FieldMode.WriteZeroToClear, name: "EXCFLAG1")
597                 },
598                 {(long)Registers.PendingExceptionFlags2, new ByteRegister(this)
599                                 .WithValueField(0, 8, out pendingExceptionFlag[2], FieldMode.Read | FieldMode.WriteZeroToClear, name: "EXCFLAG2")
600                 },
601                 {(long)Registers.ExceptionMaskA0, new ByteRegister(this)
602                                 .WithValueField(0, 8, out pendingExceptionMaskA[0], name: "EXCMASKA0")
603                 },
604                 {(long)Registers.ExceptionMaskA1, new ByteRegister(this)
605                                 .WithValueField(0, 8, out pendingExceptionMaskA[1], name: "EXCMASKA1")
606                 },
607                 {(long)Registers.ExceptionMaskA2, new ByteRegister(this)
608                                 .WithValueField(0, 8, out pendingExceptionMaskA[2], name: "EXCMASKA2")
609                 },
610                 {(long)Registers.ExceptionMaskB0, new ByteRegister(this)
611                                 .WithValueField(0, 8, out pendingExceptionMaskB[0], name: "EXCMASKB0")
612                 },
613                 {(long)Registers.ExceptionMaskB1, new ByteRegister(this)
614                                 .WithValueField(0, 8, out pendingExceptionMaskB[1], name: "EXCMASKB1")
615                 },
616                 {(long)Registers.ExceptionMaskB2, new ByteRegister(this)
617                                 .WithValueField(0, 8, out pendingExceptionMaskB[2], name: "EXCMASKB2")
618                 },
619                 {(long)Registers.FrequencyControl, new ByteRegister(this, 0x0B)
620                                 .WithValueField(0, 7, out channel, changeCallback: (_, chanVal) => this.Log(LogLevel.Info, "Setting channel to {0}", ChannelValueFromFrequency((uint)chanVal)), name: "FREQ")
621                 },
622                 {(long)Registers.TxPower, new ByteRegister(this, 0x6)
623                                 .WithValueField(0, 8, name: "PA_POWER")
624                 },
625                 {(long)Registers.FifoPControl, new ByteRegister(this, 0x40)
626                                 .WithValueField(0, 7, out fifopThreshold, name: "FIFOP_THR")
627                 },
628                 {(long)Registers.CCAThreshold, new ByteRegister(this, 0xE0)
629                                 .WithValueField(0, 8, name: "CCA_THR")
630                 },
631                 {(long)Registers.RSSIValidStatus, new ByteRegister(this)
632                                 .WithFlag(0, FieldMode.Read, valueProviderCallback: (_) => isRxEnabled, name: "RSSISTAT")
633                 },
634                 {(long)Registers.RxFirstByte, new ByteRegister(this)
635                                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => rxFifo.Count == 0 ? 0u : rxFifo.Peek(), name: "RXFIRST")
636                 },
637                 {(long)Registers.RxFifoCount, new ByteRegister(this)
638                                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => (byte)rxFifo.Count, name: "RXFIFOCNT")
639                 },
640                 {(long)Registers.TxFifoCount, new ByteRegister(this)
641                                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => (byte)txFifo.Count, name: "TXFIFOCNT")
642                 },
643                 {(long)Registers.ChipId, new ByteRegister(this, 0x84)
644                                 .WithValueField(0, 8, FieldMode.Read, name: "CHIPID")
645                 },
646                 {(long)Registers.ExternalClock, new ByteRegister(this, 0x20)
647                                 .WithTag("EXTCLOCK_EN", 5, 1) //if this is set and we have a gpio configured for external clock, then it means we need an internal timer implemented here.
648                                 .WithValueField(0, 5, name: "EXT_FREQ")
649                 },
650                 {(long)Registers.ModemControl0, new ByteRegister(this, 0x45)
651                                 .WithValueField(6, 2, name: "DEM_NUM_ZEROS")
652                                 .WithTag("DEMOD_AVG_MODE", 5, 1)
653                                 .WithTag("PREAMBLE_LENGTH", 1, 4)
654                                 .WithTag("TX_FILTER", 0, 1)
655                 },
656                 {(long)Registers.ModemControl1, new ByteRegister(this, 0x2E)
657                                 .WithFlag(5, name: "CORR_THR_SFD")
658                                 .WithValueField(0, 4, name: "CORR_THR")
659                 },
660                 {(long)Registers.RxModuleTuning, new ByteRegister(this, 0x29)
661                                 .WithValueField(0, 8)
662                 },
663                 {(long)Registers.SynthesizerTuning, new ByteRegister(this, 0x55)
664                                 .WithValueField(0, 8)
665                 },
666                 {(long)Registers.VCOTuning1, new ByteRegister(this, 0x29)
667                                 .WithValueField(0, 8)
668                 },
669                 {(long)Registers.AGCTuning1, new ByteRegister(this, 0xE)
670                                 .WithValueField(0, 8)
671                 },
672                 {(long)Registers.ADCTest0, new ByteRegister(this, 0x66)
673                                 .WithValueField(0, 8)
674                 },
675                 {(long)Registers.ADCTest1, new ByteRegister(this, 0xA)
676                                 .WithValueField(0, 8)
677                 },
678                 {(long)Registers.ADCTest2, new ByteRegister(this, 0x5)
679                                 .WithValueField(0, 8)
680                 },
681             };
682             registers = new ByteRegisterCollection(this, dict);
683         }
684 
ReadMemory(uint address)685         private byte ReadMemory(uint address)
686         {
687             byte value = 0;
688             if(address < RegisterMemorySize)
689             {
690                 if(!registers.TryRead(address, out value))
691                 {
692                     this.Log(LogLevel.Warning, "Failed to read register {0}", (Registers)address);
693                     if((address >= 0x64 && address <= 0x79))
694                     {
695                         //Other addresses do not trigger the exception
696                         SetException(ExceptionFlags.MemoryAddressError);
697                     }
698                     return 0;
699                 }
700                 this.Log(LogLevel.Debug, "Successfully read register {0}, value 0x{1:X}", (Registers)address, value);
701             }
702             else if(address >= TxFifoMemoryStart && address < TxFifoMemoryStart + TxFifoMemorySize)
703             {
704                 this.Log(LogLevel.Error, "Direct access to txFifo is not supported. Trying to access 0x{0:X}", address);
705             }
706             else if(address >= RxFifoMemoryStart && address < RxFifoMemoryStart + RxFifoMemorySize)
707             {
708                 this.Log(LogLevel.Error, "Direct access to rxFifo is not supported. Trying to access 0x{0:X}", address);
709             }
710             else if(address >= GeneralMemoryStart && address < GeneralMemoryStart + GeneralMemorySize)
711             {
712                 value = memory[address - GeneralMemoryStart];
713                 this.Log(LogLevel.Debug, "Read memory 0x{0:X}, value 0x{1:X}", address, value);
714             }
715             else if(address >= SourceAddressTableStart && address < SourceAddressTableStart + SourceAddressTableSize)
716             {
717                 value = sourceAddressTable[address - SourceAddressTableStart];
718                 this.Log(LogLevel.Debug, "Read sourceAddressTable 0x{0:X}, value 0x{1:X}", address, value);
719             }
720             else if(address >= SourceAddressMatchingResultStart && address < SourceAddressMatchingResultStart + SourceAddressMatchingResultSize)
721             {
722                 value = sourceAddressMatchingResult[address - SourceAddressMatchingResultStart];
723                 this.Log(LogLevel.Debug, "Read sourceAddressMatchingResult 0x{0:X}, value 0x{1:X}", address, value);
724             }
725             else if(address >= SourceAddressMatchingControlStart && address < SourceAddressMatchingControlStart + SourceAddressMatchingControlSize)
726             {
727                 value = sourceAddressMatchingControl[address - SourceAddressMatchingControlStart];
728                 this.Log(LogLevel.Debug, "Read sourceAddressMatchingControl 0x{0:X}, value 0x{1:X}", address, value);
729             }
730             else if(address >= LocalAddressInfoStart && address < LocalAddressInfoStart + LocalAddressInfoSize)
731             {
732                 value = localAddressInfo[address - LocalAddressInfoStart];
733                 this.Log(LogLevel.Debug, "Read localAddressInfo 0x{0:X}, value 0x{1:X}", address, value);
734             }
735             else
736             {
737                 SetException(ExceptionFlags.MemoryAddressError);
738             }
739             return value;
740         }
741 
WriteMemory(uint address, byte value)742         private void WriteMemory(uint address, byte value)
743         {
744             if(address < RegisterMemorySize)
745             {
746                 if(!registers.TryWrite(address, value))
747                 {
748                     this.Log(LogLevel.Warning, "Failed to write register {0}, value 0x{1:X}", (Registers)address, value);
749                     if((address >= 0x64 && address <= 0x79))
750                     {
751                         //Other addresses do not trigger the exception
752                         SetException(ExceptionFlags.MemoryAddressError);
753                     }
754                 }
755                 this.Log(LogLevel.Debug, "Successfully written register {0}, value 0x{1:X}", (Registers)address, value);
756             }
757             else if(address >= TxFifoMemoryStart && address < TxFifoMemoryStart + TxFifoMemorySize)
758             {
759                 this.Log(LogLevel.Error, "Direct access to txFifo is not supported. Trying to access 0x{0:X}, value 0x{1:X}", address, value);
760             }
761             else if(address >= RxFifoMemoryStart && address < RxFifoMemoryStart + RxFifoMemorySize)
762             {
763                 this.Log(LogLevel.Error, "Direct access to rxFifo is not supported. Trying to access 0x{0:X}, value 0x{1:X}", address, value);
764             }
765             else if(address >= GeneralMemoryStart && address < GeneralMemoryStart + GeneralMemorySize)
766             {
767                 memory[address - GeneralMemoryStart] = value;
768                 this.Log(LogLevel.Debug, "Written mem 0x{0:X}, value 0x{1:X}", address, value);
769             }
770             else if(address >= SourceAddressTableStart && address < SourceAddressTableStart + SourceAddressTableSize)
771             {
772                 sourceAddressTable[address - SourceAddressTableStart] = value;
773                 this.Log(LogLevel.Debug, "Written sourceAddressTable 0x{0:X}, value 0x{1:X}", address, value);
774             }
775             else if(address >= SourceAddressMatchingResultStart && address < SourceAddressMatchingResultStart + SourceAddressMatchingResultSize)
776             {
777                 sourceAddressMatchingResult[address - SourceAddressMatchingResultStart] = value;
778                 this.Log(LogLevel.Debug, "Written sourceAddressMatchingResult 0x{0:X}, value 0x{1:X}", address, value);
779             }
780             else if(address >= SourceAddressMatchingControlStart && address < SourceAddressMatchingControlStart + SourceAddressMatchingControlSize)
781             {
782                 sourceAddressMatchingControl[address - SourceAddressMatchingControlStart] = value;
783                 this.Log(LogLevel.Debug, "Written sourceAddressMatchingControl 0x{0:X}, value 0x{1:X}", address, value);
784             }
785             else if(address >= LocalAddressInfoStart && address < LocalAddressInfoStart + LocalAddressInfoSize)
786             {
787                 localAddressInfo[address - LocalAddressInfoStart] = value;
788                 this.Log(LogLevel.Debug, "Written localAddressInfo 0x{0:X}, value 0x{1:X}", address, value);
789             }
790             else
791             {
792                 SetException(ExceptionFlags.MemoryAddressError);
793             }
794         }
795 
RegisterInstructions()796         private void RegisterInstructions()
797         {
798             decoderRoot.AddOpcode(0x00, 8, () => new SNOP { Parent = this });
799             decoderRoot.AddOpcode(0x10, 4, () => new MEMRD { Parent = this });
800             decoderRoot.AddOpcode(0x20, 4, () => new MEMWR { Parent = this });
801             decoderRoot.AddOpcode(0x30, 8, () => new RXBUF { Parent = this });
802             decoderRoot.AddOpcode(0x32, 7, () => new RXBUFMOV { Parent = this });
803             decoderRoot.AddOpcode(0x3A, 8, () => new TXBUF { Parent = this });
804             decoderRoot.AddOpcode(0x40, 8, () => new SXOSCON { Parent = this });
805             decoderRoot.AddOpcode(0x42, 8, () => new SRXON { Parent = this });
806             decoderRoot.AddOpcode(0x44, 8, () => new STXONCCA { Parent = this });
807             decoderRoot.AddOpcode(0x45, 8, () => new SRFOFF { Parent = this });
808             decoderRoot.AddOpcode(0x46, 8, () => new SXOSCOFF { Parent = this });
809             decoderRoot.AddOpcode(0x47, 8, () => new SFLUSHRX { Parent = this });
810             decoderRoot.AddOpcode(0x48, 8, () => new SFLUSHTX { Parent = this });
811             decoderRoot.AddOpcode(0x80, 2, () => new REGRD { Parent = this });
812             decoderRoot.AddOpcode(0xC0, 2, () => new REGWR { Parent = this });
813         }
814 
815         private IValueRegisterField frameControlFieldReservedMask;
816         private IValueRegisterField maxFrameVersion;
817         private IFlagRegisterField panCoordinator;
818         private IFlagRegisterField frameFilteringEnabled;
819 
820         private IFlagRegisterField acceptBeaconFrames;
821         private IFlagRegisterField acceptDataFrames;
822         private IFlagRegisterField acceptAckFrames;
823         private IFlagRegisterField acceptMacCommandFrames;
824         private IFlagRegisterField acceptReservedFrames;
825 
826         private IEnumRegisterField<ModifyFieldTypeMode> modifyFrameTypeFilter;
827 
828         private IFlagRegisterField pendingDataRequestOnly;
829         private IFlagRegisterField autoPendingFlag;
830         private IFlagRegisterField sourceMatchingEnabled;
831 
832         private readonly IValueRegisterField[] shortAddressMatchingEnabled = new IValueRegisterField[3];
833         private readonly IValueRegisterField[] extendedAddressMatchingEnabled = new IValueRegisterField[3];
834 
835         private IFlagRegisterField autoCrc;
836         private IFlagRegisterField autoAck;
837         private IFlagRegisterField appendDataMode;
838 
839         private IFlagRegisterField ignoreTxUnderflow;
840         private IFlagRegisterField pendingAlwaysOn;
841 
842         private IValueRegisterField channel;
843 
844         private IValueRegisterField fifopThreshold;
845 
846         private readonly IValueRegisterField[] pendingExceptionFlag = new IValueRegisterField[3];
847         private readonly IValueRegisterField[] pendingExceptionMaskA = new IValueRegisterField[3];
848         private readonly IValueRegisterField[] pendingExceptionMaskB = new IValueRegisterField[3];
849 
850         private bool isRxEnabled;
851         private bool inReset;
852         private bool vregEnabled;
853         private bool oscillatorRunning;
854         private bool wasLastFrameSent;
855 
856         private byte[] currentFrame;
857 
858         private readonly Queue<byte> txFifo = new Queue<byte>();
859         private readonly Queue<byte> rxFifo = new Queue<byte>();
860         private byte[] memory;
861         private byte[] sourceAddressTable;
862         private byte[] sourceAddressMatchingResult;
863         private byte[] sourceAddressMatchingControl;
864         private byte[] localAddressInfo;
865         private Address localShortAddress;
866         private Address localExtendedAddress;
867 
868         private Instruction currentInstruction;
869         private ByteRegisterCollection registers;
870 
871         private SimpleInstructionDecoder<Instruction> decoderRoot = new SimpleInstructionDecoder<Instruction>();
872 
873         private const int RegisterMemorySize = 0x80;
874         private const uint TxFifoMemoryStart = 0x100;
875         private const int TxFifoMemorySize = 0x80;
876         private const uint RxFifoMemoryStart = 0x180;
877         private const int RxFifoMemorySize = 0x80;
878         private const uint GeneralMemoryStart = 0x200;
879         private const int GeneralMemorySize = 0x180;
880         private const uint SourceAddressTableStart = 0x380;
881         private const int SourceAddressTableSize = 0x60;
882         private const uint SourceAddressMatchingResultStart = 0x3E0;
883         private const int SourceAddressMatchingResultSize = 0x4;
884         private const uint SourceAddressMatchingControlStart = 0x3E4;
885         private const int SourceAddressMatchingControlSize = 0x6;
886         private const uint LocalAddressInfoStart = 0x3EA;
887         private const int LocalAddressInfoSize = 0xC;
888         private const int NumberOfGPIOs = 6;
889 
890         private const int BroadcastPanIdentifier = 0xFFFF;
891         private const byte NoSourceIndex = 0x3F;
892 
893         private abstract class Instruction
894         {
Parse(byte value)895             public byte Parse(byte value)
896             {
897                 CurrentByteCount++;
898                 return ParseInner(value);
899             }
900 
901             public CC2520 Parent { protected get; set; }
902             public string Name { get; private set; }
903             public bool IsFinished
904             {
905                 get
906                 {
907                     return CurrentByteCount == Length;
908                 }
909             }
910 
911             public bool? HighPriority { get; protected set; } //tristate, because non-null value sets DPUx_ACTIVE in status
912 
Instruction()913             protected Instruction()
914             {
915                 Name = GetType().Name;
916                 Length = 1;
917             }
918 
ParseInner(byte value)919             protected virtual byte ParseInner(byte value)
920             {
921                 return Parent.GetStatus();
922             }
923 
924             protected virtual bool IsCommandStrobe
925             {
926                 get { return Length == 1; }
927             }
928 
929             protected int Length;
930             protected int CurrentByteCount;
931             protected uint AddressA;
932             protected uint CountC;
933         }
934 
935         private sealed class SNOP : Instruction
936         {
937             protected override bool IsCommandStrobe
938             {
939                 get { return false; }
940             }
941         }
942 
943         private sealed class SXOSCON : Instruction
944         {
ParseInner(byte value)945             protected override byte ParseInner(byte value)
946             {
947                 Parent.oscillatorRunning = true;
948                 return base.ParseInner(value);
949             }
950 
951             protected override bool IsCommandStrobe
952             {
953                 get { return false; }
954             }
955         }
956 
957         private sealed class SRXON : Instruction
958         {
ParseInner(byte value)959             protected override byte ParseInner(byte value)
960             {
961                 Parent.isRxEnabled = true;
962                 if(Parent.currentFrame != null)
963                 {
964                     Parent.HandleFrame(Parent.currentFrame);
965                     Parent.currentFrame = null;
966                 }
967                 return base.ParseInner(value);
968             }
969         }
970 
971         private sealed class STXONCCA : Instruction
972         {
ParseInner(byte value)973             protected override byte ParseInner(byte value)
974             {
975                 Parent.SendFrame();
976                 return base.ParseInner(value);
977             }
978         }
979 
980         private sealed class SRFOFF : Instruction
981         {
ParseInner(byte value)982             protected override byte ParseInner(byte value)
983             {
984                 if(Parent.isRxEnabled && Parent.currentFrame != null)
985                 {
986                     Parent.SetException(ExceptionFlags.RxFrameAborted);
987                     Parent.currentFrame = null;
988                 }
989                 Parent.isRxEnabled = false;
990                 return base.ParseInner(value);
991             }
992         }
993 
994         private sealed class SXOSCOFF : Instruction
995         {
ParseInner(byte value)996             protected override byte ParseInner(byte value)
997             {
998                 if(Parent.isRxEnabled)
999                 {
1000                     Parent.SetException(ExceptionFlags.UsageError);
1001                     if(Parent.currentFrame != null)
1002                     {
1003                         Parent.SetException(ExceptionFlags.RxFrameAborted);
1004                         Parent.currentFrame = null;
1005                     }
1006                 }
1007                 Parent.oscillatorRunning = false;
1008                 return base.ParseInner(value);
1009             }
1010         }
1011 
1012         private sealed class MEMRD : Instruction
1013         {
MEMRD()1014             public MEMRD()
1015             {
1016                 Length = 0;
1017             }
1018 
ParseInner(byte value)1019             protected override byte ParseInner(byte value)
1020             {
1021                 switch(CurrentByteCount)
1022                 {
1023                 case 1:
1024                     AddressA = (uint)(value & 0xF) << 8;
1025                     return Parent.GetStatus();
1026                 case 2:
1027                     AddressA |= value;
1028                     return Parent.GetStatus();
1029                 default:
1030                     var registerValue = Parent.ReadMemory(AddressA);
1031                     AddressA = (AddressA + 1) % 0x3FF; //0x3FF is the highest RAM address. It is not explicitly stated that MEMWR/MEMRD should wrap
1032                     return registerValue;
1033                 }
1034             }
1035         }
1036 
1037         private sealed class MEMWR : Instruction
1038         {
MEMWR()1039             public MEMWR()
1040             {
1041                 Length = 0;
1042             }
1043 
ParseInner(byte value)1044             protected override byte ParseInner(byte value)
1045             {
1046                 switch(CurrentByteCount)
1047                 {
1048                 case 1:
1049                     AddressA = (uint)(value & 0xF) << 8;
1050                     return Parent.GetStatus();
1051                 case 2:
1052                     AddressA |= value;
1053                     return Parent.GetStatus();
1054                 default:
1055                     var registerValue = Parent.ReadMemory(AddressA);
1056                     Parent.WriteMemory(AddressA, value);
1057                     AddressA = (AddressA + 1) % 0x3FF; //0x3FF is the highest RAM address. It is not explicitly stated that MEMWR/MEMRD should wrap
1058                     return registerValue;
1059                 }
1060             }
1061         }
1062 
1063         private sealed class RXBUF : Instruction
1064         {
RXBUF()1065             public RXBUF()
1066             {
1067                 Length = 0;
1068             }
1069 
ParseInner(byte value)1070             protected override byte ParseInner(byte value)
1071             {
1072                 switch(CurrentByteCount)
1073                 {
1074                 case 1:
1075                     return base.ParseInner(value);
1076                 default:
1077                     if(Parent.rxFifo.Count > 0)
1078                     {
1079                         var data = Parent.rxFifo.Dequeue();
1080                         if(Parent.rxFifo.Count <= (int)Parent.fifopThreshold.Value)
1081                         {
1082                             Parent.UnsetException(ExceptionFlags.FifoThresholdReached);
1083                         }
1084                         Parent.UpdateInterrupts();
1085                         return data;
1086                     }
1087                     Parent.SetException(ExceptionFlags.RxUnderflow);
1088                     return 0;
1089                 }
1090             }
1091         }
1092 
1093         private sealed class TXBUF : Instruction
1094         {
TXBUF()1095             public TXBUF()
1096             {
1097                 Length = 0;
1098             }
1099 
ParseInner(byte value)1100             protected override byte ParseInner(byte value)
1101             {
1102                 switch(CurrentByteCount)
1103                 {
1104                 case 1:
1105                     return base.ParseInner(value);
1106                 default:
1107                     if(Parent.wasLastFrameSent)
1108                     {
1109                         Parent.txFifo.Clear();
1110                         Parent.wasLastFrameSent = false;
1111                     }
1112                     var count = Parent.txFifo.Count;
1113                     if(count <= TxFifoMemorySize)
1114                     {
1115                         Parent.txFifo.Enqueue(value);
1116                     }
1117                     else
1118                     {
1119                         Parent.SetException(ExceptionFlags.TxOverflow);
1120                     }
1121                     return (byte)count;
1122                 }
1123             }
1124         }
1125 
1126         private sealed class SFLUSHRX : Instruction
1127         {
ParseInner(byte value)1128             protected override byte ParseInner(byte value)
1129             {
1130                 Parent.rxFifo.Clear();
1131                 Parent.UnsetException(ExceptionFlags.FifoThresholdReached);
1132                 Parent.UpdateInterrupts();
1133                 return base.ParseInner(value);
1134             }
1135         }
1136 
1137         private sealed class SFLUSHTX : Instruction
1138         {
ParseInner(byte value)1139             protected override byte ParseInner(byte value)
1140             {
1141                 Parent.txFifo.Clear();
1142                 Parent.UpdateInterrupts();
1143                 return base.ParseInner(value);
1144             }
1145         }
1146 
1147         private sealed class REGRD : Instruction
1148         {
REGRD()1149             public REGRD()
1150             {
1151                 Length = 0;
1152             }
1153 
ParseInner(byte value)1154             protected override byte ParseInner(byte value)
1155             {
1156                 if(CurrentByteCount == 1)
1157                 {
1158                     AddressA = BitHelper.GetValue(value, 0, 6);
1159                     return base.ParseInner(value);
1160                 }
1161                 var registerValue = Parent.ReadMemory(AddressA);
1162                 AddressA = (AddressA + 1) % 0x7F; //the operation wraps on 0x7F
1163                 return registerValue;
1164             }
1165         }
1166 
1167         private sealed class REGWR : Instruction
1168         {
REGWR()1169             public REGWR()
1170             {
1171                 Length = 0;
1172             }
1173 
ParseInner(byte value)1174             protected override byte ParseInner(byte value)
1175             {
1176                 if(CurrentByteCount == 1)
1177                 {
1178                     AddressA = BitHelper.GetValue(value, 0, 6);
1179                     return Parent.GetStatus();
1180                 }
1181                 var registerValue = Parent.ReadMemory(AddressA);
1182                 Parent.WriteMemory(AddressA, value);
1183                 AddressA = (AddressA + 1) % 0x7F; //the operation wraps on 0x7F
1184                 return registerValue;
1185             }
1186         }
1187 
1188         private sealed class RXBUFMOV : Instruction
1189         {
RXBUFMOV()1190             public RXBUFMOV()
1191             {
1192                 Length = 4;
1193             }
1194 
ParseInner(byte value)1195             protected override byte ParseInner(byte value)
1196             {
1197                 switch(CurrentByteCount)
1198                 {
1199                 case 1:
1200                     HighPriority = (value & 0x1u) != 0;
1201                     return Parent.GetStatus();
1202                 case 2:
1203                     CountC = value;
1204                     return (byte)Parent.rxFifo.Count;
1205                 case 3:
1206                     AddressA = (uint)(value & 0xF) << 8;
1207                     return Parent.GetStatus();
1208                 default:
1209                     AddressA |= value;
1210                     if(Parent.rxFifo.Count < CountC)
1211                     {
1212                         Parent.SetException(ExceptionFlags.RxBufferMoveTimeout);
1213                         CountC = (uint)Parent.rxFifo.Count;
1214                         Parent.Log(LogLevel.Warning, "Rx buffer underflow during RXBUFMOV instruction. A status register should be set, but it's not well specified which one.");
1215                     }
1216                     for(var i = 0; i < CountC; ++i)
1217                     {
1218                         var data = Parent.rxFifo.Dequeue();
1219                         Parent.WriteMemory(AddressA, data);
1220                         AddressA++;
1221                         Parent.SetException(HighPriority.Value ? ExceptionFlags.DPUDoneHigh : ExceptionFlags.DPUDoneLow);
1222                     }
1223                     if(Parent.rxFifo.Count <= (int)Parent.fifopThreshold.Value)
1224                     {
1225                         Parent.UnsetException(ExceptionFlags.FifoThresholdReached);
1226                     }
1227                     Parent.UpdateInterrupts();
1228                     return Parent.GetStatus();
1229                 }
1230             }
1231         }
1232 
1233 
1234 
1235         private enum Registers
1236         {
1237             //FREG registers
1238             FrameFiltering0 = 0x00, //FRMFILT0
1239             FrameFiltering1 = 0x01,
1240             SourceMatching = 0x02,
1241             ShortAddressMatchingEnabled0 = 0x04,
1242             ShortAddressMatchingEnabled1 = 0x05,
1243             ShortAddressMatchingEnabled2 = 0x06,
1244             ExtendedAddressMatchingEnabled0 = 0x08,
1245             ExtendedAddressMatchingEnabled1 = 0x09,
1246             ExtendedAddressMatchingEnabled2 = 0x0A,
1247             FrameControl0 = 0x0C,
1248             FrameControl1 = 0x0D,
1249             RXENABLE0 = 0x0E,
1250             RXENABLE1 = 0x0F,
1251             PendingExceptionFlags0 = 0x10,
1252             PendingExceptionFlags1 = 0x11,
1253             PendingExceptionFlags2 = 0x12,
1254             ExceptionMaskA0 = 0x14,
1255             ExceptionMaskA1 = 0x15,
1256             ExceptionMaskA2 = 0x16,
1257             ExceptionMaskB0 = 0x18,
1258             ExceptionMaskB1 = 0x19,
1259             ExceptionMaskB2 = 0x1A,
1260             EXCBINDX0 = 0x1C,
1261             EXCBINDX1 = 0x1D,
1262             EXCBINDY0 = 0x1E,
1263             EXCBINDY1 = 0x1F,
1264             GPIOCTRL0 = 0x20,
1265             GPIOCTRL1 = 0x21,
1266             GPIOCTRL2 = 0x22,
1267             GPIOCTRL3 = 0x23,
1268             GPIOCTRL4 = 0x24,
1269             GPIOCTRL5 = 0x25,
1270             GPIOPOLARITY = 0x26,
1271             GPIOCTRL = 0x28,
1272             DPUCON = 0x2A,
1273             DPUSTAT = 0x2C,
1274             FrequencyControl = 0x2E,
1275             FREQTUNE = 0x2F,
1276             TxPower = 0x30,
1277             TXCTRL = 0x31,
1278             FSMSTAT0 = 0x32,
1279             FSMSTAT1 = 0x33,
1280             FifoPControl = 0x34,
1281             FSMCTRL = 0x35,
1282             CCAThreshold = 0x36,
1283             CCACTRL1 = 0x37,
1284             RSSI = 0x38,
1285             RSSIValidStatus = 0x39,
1286             RxFirstByte = 0x3C,
1287             RxFifoCount = 0x3E,
1288             TxFifoCount = 0x3F,
1289             //SREG registers
1290             ChipId = 0x40,
1291             Version = 0x42,
1292             ExternalClock = 0x44,
1293             ModemControl0 = 0x46,
1294             ModemControl1 = 0x47,
1295             FREQEST = 0x48,
1296             RxModuleTuning = 0x4A,
1297             SynthesizerTuning = 0x4C,
1298             FSCAL0 = 0x4E,
1299             VCOTuning1 = 0x4F,
1300             FSCAL2 = 0x50,
1301             FSCAL3 = 0x51,
1302             AGCCTRL0 = 0x52,
1303             AGCTuning1 = 0x53,
1304             AGCCTRL2 = 0x54,
1305             AGCCTRL3 = 0x55,
1306             ADCTest0 = 0x56,
1307             ADCTest1 = 0x57,
1308             ADCTest2 = 0x58,
1309             MDMTEST0 = 0x5A,
1310             MDMTEST1 = 0x5B,
1311             DACTEST0 = 0x5C,
1312             DACTEST1 = 0x5D,
1313             ATEST = 0x5E,
1314             DACTEST2 = 0x5F,
1315             PTEST0 = 0x60,
1316             PTEST1 = 0x61,
1317             RESERVED = 0x62,
1318             DPUBIST = 0x7A,
1319             ACTBIST = 0x7C,
1320             RAMBIST = 0x7E
1321         }
1322 
1323         private enum ExceptionFlags
1324         {
1325             RFIdle = 0,
1326             TxFrameDone = 1,
1327             TxAckDone = 2,
1328             TxUnderflow = 3,
1329             TxOverflow = 4,
1330             RxUnderflow = 5,
1331             RxOverflow = 7,
1332             RxEnableZero = 8,
1333             RxFrameDone = 9,
1334             RxFrameAccepted = 10,
1335             SourceMatchingDone = 11,
1336             SourceMatchingFound = 12,
1337             FifoThresholdReached = 13,
1338             StartOfFrameDelimiter = 14,
1339             DPUDoneLow = 15,
1340             DPUDoneHigh = 16,
1341             MemoryAddressError = 17,
1342             UsageError = 18,
1343             OperandError = 19,
1344             SPIError = 20,
1345             RFNoLock = 21,
1346             RxFrameAborted = 22,
1347             RxBufferMoveTimeout = 23
1348         }
1349 
1350         private enum GPIOs
1351         {
1352             //these are the default functions of reconfigurable gpios. This is not robust.
1353             Clock = 0,
1354             Fifo = 1,
1355             Fifop = 2,
1356             Cca = 3,
1357             Sfd = 4,
1358             In = 5
1359         }
1360 
1361         private enum ModifyFieldTypeMode
1362         {
1363             Leave,
1364             InvertMSB,
1365             SetMSB,
1366             UnsetMSB
1367         }
1368     }
1369 }
1370