1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System.Linq;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Logging;
11 using System;
12 using System.Collections.Generic;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Utilities;
15 using Antmicro.Migrant;
16 using Antmicro.Renode.Peripherals.Wireless.IEEE802_15_4;
17 using Antmicro.Renode.Peripherals.Wireless.CC2538;
18 using Antmicro.Renode.Core.Structure.Registers;
19 
20 namespace Antmicro.Renode.Peripherals.Wireless
21 {
22     public class CC2538RF : IDoubleWordPeripheral, IBytePeripheral, IKnownSize, IRadio
23     {
CC2538RF()24         public CC2538RF()
25         {
26             rxLock = new object();
27             rxQueue = new Queue<Frame>();
28             txQueue = new Queue<byte>();
29 
30             shortAddress = new Address(AddressingMode.ShortAddress);
31             extendedAddress = new Address(AddressingMode.ExtendedAddress);
32             random = EmulationManager.Instance.CurrentEmulation.RandomGenerator;
33             IRQ = new GPIO();
34 
35             srcShortEnabled = new bool[24];
36             srcExtendedEnabled = new bool[12];
37             matchedSourceAddresses = new bool[24];
38             srcShortPendEnabled = new bool[24];
39             srcExtendedPendEnabled = new bool[12];
40             ffsmMemory = new uint[96];
41 
42             irqHandler = new InterruptHandler<InterruptRegister, InterruptSource>(IRQ);
43             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.StartOfFrameDelimiter, 1);
44             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.FifoP, 2);
45             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.SrcMatchDone, 3);
46             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.SrcMatchFound, 4);
47             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.FrameAccepted, 5);
48             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.RxPktDone, 6);
49             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag0, InterruptSource.RxMaskZero, 7);
50 
51             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.TxAckDone, 0);
52             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.TxDone, 1);
53             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.RfIdle, 2);
54             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.CommandStrobeProcessorManualInterrupt, 3);
55             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.CommandStrobeProcessorStop, 4);
56             irqHandler.RegisterInterrupt(InterruptRegister.IrqFlag1, InterruptSource.CommandStrobeProcessorWait, 5);
57 
58             var matchedSourceIndex = new DoubleWordRegister(this);
59             matchedSourceIndexField = matchedSourceIndex.DefineValueField(0, 8, FieldMode.Read | FieldMode.Write);
60 
61             var srcResMask = CreateRegistersGroup(3, this, 0, 8,
62                                 valueProviderCallback: ReadSrcResMaskRegister, writeCallback: WriteSrcResMaskRegister);
63             var srcExtendedAddressPendingEnabled = CreateRegistersGroup(3, this, 0, 8,
64                                 valueProviderCallback: ReadSrcExtendedAddressPendingEnabledRegister, writeCallback: WriteSrcExtendedAddressPendingEnabledRegister);
65             var srcShortAddressPendingEnabled = CreateRegistersGroup(3, this, 0, 8,
66                                 name: "SrcShortAddressPendingEnabled", valueProviderCallback: ReadSrcShortAddressPendingEnabledRegister, writeCallback: WriteSrcShortAddressPendingEnabledRegister);
67             var extAddress = CreateRegistersGroup(8, this, 0, 8,
68                                 valueProviderCallback: i => extendedAddress.Bytes[i], writeCallback: (i, @new) => extendedAddress.SetByte((byte)@new, i));
69             panId = CreateRegistersGroup(2, this, 0, 8);
70             var shortAddressRegister = CreateRegistersGroup(2, this, 0, 8,
71                                 valueProviderCallback: i => shortAddress.Bytes[i], writeCallback: (i, @new) => shortAddress.SetByte((byte)@new, i));
72 
73             var sourceExtendedAddressEnable = CreateRegistersGroup(3, this, 0, 8,
74                                 valueProviderCallback: ReadSourceExtendedAddressEnableRegister, writeCallback: WriteSourceExtendedAddressEnableRegister);
75             var sourceShortAddressEnable = CreateRegistersGroup(3, this, 0, 8,
76                                 valueProviderCallback: ReadSourceShortAddressEnableRegister, writeCallback: WriteSourceShortAddressEnableRegister);
77 
78             var frameHandling0 = new DoubleWordRegister(this, 0x40);
79             autoAck = frameHandling0.DefineFlagField(5);
80             autoCrc = frameHandling0.DefineFlagField(6);
81             appendDataMode = frameHandling0.DefineFlagField(7);
82 
83             var frameHandling1 = new DoubleWordRegister(this, 0x1);
84             pendingOr = frameHandling1.DefineFlagField(2);
85 
86             var sourceAddressMatching = new DoubleWordRegister(this, 0x7);
87             sourceAddressMatchingEnabled = sourceAddressMatching.DefineFlagField(0);
88             autoPendEnabled = sourceAddressMatching.DefineFlagField(1);
89             pendDataRequestOnly = sourceAddressMatching.DefineFlagField(2);
90 
91             var radioStatus0 = new DoubleWordRegister(this, 0).WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => (uint)fsmState)
92                                                               .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true);
93             var radioStatus1 = new DoubleWordRegister(this, 0).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => ReadRadioStatus1Register());
94             var rssiValidStatus = new DoubleWordRegister(this, 0x1).WithFlag(0, FieldMode.Read);
95 
96             var interruptMask = CreateRegistersGroup(2, this, 0, 8,
97                                  valueProviderCallback: i => irqHandler.GetRegisterMask(InterruptRegisterHelper.GetMaskRegister(i)),
98                                  writeCallback: (i, @new) => { irqHandler.SetRegisterMask(InterruptRegisterHelper.GetMaskRegister(i), (uint)@new); });
99             var randomData = new DoubleWordRegister(this, 0).WithValueField(0, 2, FieldMode.Read, valueProviderCallback: _ => (uint)(random.Next() & 3));
100 
101             var frameFiltering0 = new DoubleWordRegister(this, 0xD);
102             frameFilterEnabled = frameFiltering0.DefineFlagField(0);
103             isPanCoordinator = frameFiltering0.DefineFlagField(1);
104             maxFrameVersion = frameFiltering0.DefineValueField(2, 2);
105 
106             var frameFiltering1 = new DoubleWordRegister(this, 0x78);
107             acceptBeaconFrames = frameFiltering1.DefineFlagField(3);
108             acceptDataFrames = frameFiltering1.DefineFlagField(4);
109             acceptAckFrames = frameFiltering1.DefineFlagField(5);
110             acceptMacCmdFrames = frameFiltering1.DefineFlagField(6);
111             //Reset value set according to the documentation, but register value is caluculated from Channel value.
112             var frequencyControl = new DoubleWordRegister(this, 0xB).WithValueField(0, 7,
113                                 changeCallback: (_, value) => Channel = (int)(((value > 113 ? 113 : value) - 11) / 5 + 11), //FREQ = 11 + 5(channel - 11), maximum value is 113.
114                                 valueProviderCallback: (value) => 11 + 5 * ((uint)Channel - 11));
115 
116             var rfData = new DoubleWordRegister(this, 0).WithValueField(0, 8,
117                                 valueProviderCallback: _ => DequeueData(), writeCallback: (_, @new) => { EnqueueData((byte)@new); });
118             var interruptFlag = CreateRegistersGroup(2, this, 0, 8,
119                                 valueProviderCallback: i => irqHandler.GetRegisterValue(InterruptRegisterHelper.GetValueRegister(i)),
120                                 writeCallback: (i, @new) => { irqHandler.SetRegisterValue(InterruptRegisterHelper.GetValueRegister(i), (uint)@new); });
121             var commandStrobeProcessor = new DoubleWordRegister(this, 0).WithValueField(0, 8, FieldMode.Write, writeCallback: (_, @new) => { HandleSFRInstruction((uint)@new); });
122 
123             var rxFifoBytesCount = new DoubleWordRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => GetRxFifoBytesCount());
124 
125             var addresses = new Dictionary<long, DoubleWordRegister>
126             {
127                 { (uint)Register.RfData, rfData },
128                 { (uint)Register.CommandStrobeProcessor, commandStrobeProcessor },
129                 { (uint)Register.FrameFiltering0, frameFiltering0 },
130                 { (uint)Register.FrameFiltering1, frameFiltering1 },
131                 { (uint)Register.SourceAddressMatching, sourceAddressMatching },
132                 { (uint)Register.FrameHandling0, frameHandling0 },
133                 { (uint)Register.FrameHandling1, frameHandling1 },
134                 { (uint)Register.RadioStatus0, radioStatus0 },
135                 { (uint)Register.RadioStatus1, radioStatus1 },
136                 { (uint)Register.RssiValidStatus, rssiValidStatus },
137                 { (uint)Register.RandomData, randomData },
138                 { (uint)Register.SourceAddressMatchingResult, matchedSourceIndex },
139                 { (uint)Register.FrequencyControl, frequencyControl },
140                 { (uint)Register.RxFifoBytesCount, rxFifoBytesCount }
141             };
142 
143             RegisterGroup(addresses, (uint)Register.InterruptFlag, interruptFlag);
144             RegisterGroup(addresses, (uint)Register.SourceExtendedAdressEnable, sourceExtendedAddressEnable);
145             RegisterGroup(addresses, (uint)Register.SourceShortAddressEnable, sourceShortAddressEnable);
146             RegisterGroup(addresses, (uint)Register.InterruptMask, interruptMask);
147             RegisterGroup(addresses, (uint)Register.SourceAddressMatchingResultMask, srcResMask);
148             RegisterGroup(addresses, (uint)Register.SourceExtendedAddressPendingEnabled, srcExtendedAddressPendingEnabled);
149             RegisterGroup(addresses, (uint)Register.SourceShortAddressPendingEnabled, srcShortAddressPendingEnabled);
150             RegisterGroup(addresses, (uint)Register.ExtendedAddress, extAddress);
151             RegisterGroup(addresses, (uint)Register.PanId, panId);
152             RegisterGroup(addresses, (uint)Register.ShortAddressRegister, shortAddressRegister);
153 
154             registers = new DoubleWordRegisterCollection(this, addresses);
155 
156             Reset();
157         }
158 
ReadDoubleWord(long offset)159         public uint ReadDoubleWord(long offset)
160         {
161             uint result = 0u;
162             if(offset >= FfsmMemoryStart && offset <= FfsmMemoryEnd)
163             {
164                 result = ffsmMemory[offset - FfsmMemoryStart];
165             }
166             else if(offset < RxFifoMemorySize)
167             {
168                 lock(rxLock)
169                 {
170                     // dividedOffset represents the position in the packet queue, assuming that the "Length" byte is also stored there.
171                     // Since we do not store the lenght along with the packet, we handle it with increasedFrameIndex variable.
172                     // The offset is shifted, as it seems that the driver accesses each byte as it was a double word value.
173                     var dividedOffset = offset >> 2;
174                     var increasedFrameIndex = 1;
175                     do
176                     {
177                         if(rxQueue.Count < increasedFrameIndex)
178                         {
179                             break;
180                         }
181 
182                         if(dividedOffset == increasedFrameIndex - 1)
183                         {
184                             //return size of the current frame
185                             result = (uint)rxQueue.ElementAt(increasedFrameIndex - 1).Bytes.Count();
186                             break;
187                         }
188                         if(increasedFrameIndex + rxQueue.ElementAt(increasedFrameIndex - 1).Bytes.Count() > dividedOffset)
189                         {
190                             //return specific byte from the current frame
191                             result = rxQueue.ElementAt(increasedFrameIndex - 1).Bytes[dividedOffset - increasedFrameIndex];
192                             break;
193                         }
194 
195                         dividedOffset -= rxQueue.ElementAt(increasedFrameIndex - 1).Bytes.Count();
196                         increasedFrameIndex++;
197                     } while(dividedOffset > 0);
198                 }
199             }
200             else
201             {
202                 result = registers.Read(offset);
203             }
204 
205             return result;
206         }
207 
WriteDoubleWord(long offset, uint value)208         public void WriteDoubleWord(long offset, uint value)
209         {
210             if(offset >= 0x400 && offset <= 0x57C)
211             {
212                 ffsmMemory[offset - 0x400] = value;
213                 return;
214             }
215 
216             registers.Write(offset, value);
217             return;
218         }
219 
220         //used by uDMA
ReadByte(long offset)221         public byte ReadByte(long offset)
222         {
223             if(offset == (long)Register.RfData)
224             {
225                 return DequeueData();
226             }
227             this.Log(LogLevel.Warning, "{0} does not implement byte reads apart from {1} (0x{2:X}).", GetType().Name, "RFData", (long)Register.RfData);
228             this.LogUnhandledRead(offset);
229             return 0;
230         }
231 
232         //used by uDMA
WriteByte(long offset, byte value)233         public void WriteByte(long offset, byte value)
234         {
235             if(offset == (long)Register.RfData) // RF data
236             {
237                 EnqueueData(value);
238                 return;
239             }
240             this.Log(LogLevel.Warning, "{0} does not implement byte writes apart from {1} (0x{2:X}).", GetType().Name, "RFData", (long)Register.RfData);
241             this.LogUnhandledWrite(offset, value);
242         }
243 
Reset()244         public void Reset()
245         {
246             lock(rxLock)
247             {
248                 registers.Reset();
249 
250                 currentFrameOffset = -1;
251                 txPendingCounter = 0;
252                 fsmState = FSMStates.Idle;
253                 rxQueue.Clear();
254 
255                 Array.Clear(srcShortEnabled, 0, srcShortEnabled.Length);
256                 Array.Clear(srcShortPendEnabled, 0, srcShortPendEnabled.Length);
257                 Array.Clear(matchedSourceAddresses, 0, matchedSourceAddresses.Length);
258                 Array.Clear(srcExtendedEnabled, 0, srcExtendedEnabled.Length);
259                 Array.Clear(srcExtendedPendEnabled, 0, srcExtendedPendEnabled.Length);
260                 Array.Clear(ffsmMemory, 0, ffsmMemory.Length);
261 
262                 irqHandler.Reset();
263                 txQueue.Clear();
264 
265                 Channel = ChannelResetValue;
266             }
267         }
268 
ReceiveFrame(byte[] bytes, IRadio sender)269         public void ReceiveFrame(byte[] bytes, IRadio sender)
270         {
271             irqHandler.RequestInterrupt(InterruptSource.StartOfFrameDelimiter);
272 
273             Frame ackFrame = null;
274             var frame = new Frame(bytes);
275 
276             var crcOK = frame.CheckCRC();
277             if(autoCrc.Value && !crcOK)
278             {
279                 this.Log(LogLevel.Warning, "Received frame with wrong CRC");
280             }
281 
282             if(frameFilterEnabled.Value)
283             {
284                 if(!ShouldWeAcceptThisFrame(frame))
285                 {
286                     this.DebugLog("Not accepting a frame");
287                     return;
288                 }
289 
290                 irqHandler.RequestInterrupt(InterruptSource.FrameAccepted);
291             }
292 
293             lock(rxLock)
294             {
295                 var autoPendingBit = false;
296                 var index = NoSourceIndex;
297                 if(sourceAddressMatchingEnabled.Value && crcOK) //todo: verify if this should not only run when frameFilterEnabled, as in CC2520
298                 {
299                     switch(frame.SourceAddressingMode)
300                     {
301                         case AddressingMode.ShortAddress:
302                             for(var i = 0u; i < srcShortEnabled.Length; i++)
303                             {
304                                 if(!srcShortEnabled[i])
305                                 {
306                                     continue;
307                                 }
308                                 if(frame.AddressInformation.SourcePan == GetShortPanIdFromRamTable(i)
309                                    && frame.AddressInformation.SourceAddress.GetValue() == GetShortSourceAddressFromRamTable(i))
310                                 {
311                                     matchedSourceAddresses[i] = true;
312                                     autoPendingBit |= srcShortPendEnabled[i];
313                                     if(index == NoSourceIndex)
314                                     {
315                                         index = i;
316                                     }
317                                 }
318                             }
319                             break;
320                         case AddressingMode.ExtendedAddress:
321                             for(var i = 0u; i < srcExtendedEnabled.Length; i++)
322                             {
323                                 if(!srcExtendedEnabled[i])
324                                 {
325                                     continue;
326                                 }
327                                 if(frame.AddressInformation.SourceAddress.GetValue() == GetExtendedSourceAddressFromRamTable(i))
328                                 {
329                                     matchedSourceAddresses[2 * i] = true;
330                                     matchedSourceAddresses[2 * i + 1] = true;
331                                     autoPendingBit |= srcExtendedPendEnabled[i];
332                                     if(index == NoSourceIndex)
333                                     {
334                                         index = i | 0x20;
335                                     }
336                                 }
337                             }
338                             break;
339                     }
340 
341                     matchedSourceIndexField.Value = index;
342 
343                     autoPendingBit &= autoPendEnabled.Value
344                                         && frameFilterEnabled.Value
345                                         && (!pendDataRequestOnly.Value
346                                             || (frame.Type == FrameType.MACControl
347                                                 && frame.Payload.Count > 0
348                                                 && frame.Payload[0] == 0x4));
349 
350                     BitHelper.SetBit(ref index, 6, autoPendingBit);
351                     if(index != NoSourceIndex)
352                     {
353                         irqHandler.RequestInterrupt(InterruptSource.SrcMatchFound);
354                     }
355                     irqHandler.RequestInterrupt(InterruptSource.SrcMatchDone);
356                 }
357 
358                 if(autoCrc.Value)
359                 {
360                     var rssi = 70; // why 70?
361                     var secondByte = crcOK ? (1u << 7) : 0;
362                     if(appendDataMode.Value)
363                     {
364                         secondByte |= index & 0x7F;
365                     }
366                     else
367                     {
368                         secondByte |= 100; // correlation value 100 means near maximum quality
369                     }
370                     frame.Bytes[frame.Bytes.Length - 2] = (byte)rssi;
371                     frame.Bytes[frame.Bytes.Length - 1] = (byte)secondByte;
372                 }
373 
374                 rxQueue.Enqueue(frame);
375                 irqHandler.RequestInterrupt(InterruptSource.FifoP);
376                 if(crcOK && autoAck.Value
377                     && frame.AcknowledgeRequest
378                     && frame.Type != FrameType.Beacon
379                     && frame.Type != FrameType.ACK)
380                 {
381                     ackFrame = Frame.CreateACK(frame.DataSequenceNumber, pendingOr.Value | autoPendingBit);
382                 }
383             }
384 
385             var frameSent = FrameSent;
386             if(frameSent != null && ackFrame != null)
387             {
388                 frameSent(this, ackFrame.Bytes);
389                 irqHandler.RequestInterrupt(InterruptSource.TxAckDone);
390             }
391 
392             irqHandler.RequestInterrupt(InterruptSource.RxPktDone);
393         }
394 
395         public int Channel { get; set; }
396         public event Action<IRadio, byte[]> FrameSent;
397         public GPIO IRQ { get; private set; }
398         public long Size { get { return 0x1000; } }
399 
GetRxFifoBytesCount()400 	private uint GetRxFifoBytesCount()
401         {
402             lock(rxLock)
403             {
404                 //takes only first packet into account plus 1 byte that indicates its size
405                 return rxQueue.Count > 0 ? (uint)rxQueue.Peek().Bytes.Length + 1 : 0u;
406 	    }
407 	}
408 
CreateRegistersGroup(int size, IPeripheral parent, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, uint> writeCallback = null, Func<int, uint> valueProviderCallback = null, string name = null)409 	private static DoubleWordRegister[] CreateRegistersGroup(int size, IPeripheral parent, int position, int width,
410             FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, uint> writeCallback = null, Func<int, uint> valueProviderCallback = null, string name = null)
411         {
412             var result = new DoubleWordRegister[size];
413             for(var i = 0; i < size; i++)
414             {
415                 var j = i;
416                 result[i] = new DoubleWordRegister(parent)
417                     .WithValueField(position, width, mode, name: name + j,
418                         valueProviderCallback: _ =>
419                         {
420                             if(valueProviderCallback != null)
421                             {
422                                 return valueProviderCallback(j);
423                             }
424                             return 0;
425                         },
426                         writeCallback: (_, @new) =>
427                         {
428                             if(writeCallback != null)
429                             {
430                                 writeCallback(j, (uint)@new);
431                             }
432                         });
433             }
434             return result;
435         }
436 
RegisterGroup(Dictionary<long, DoubleWordRegister> collection, long initialAddress, DoubleWordRegister[] group)437         private static void RegisterGroup(Dictionary<long, DoubleWordRegister> collection, long initialAddress, DoubleWordRegister[] group)
438         {
439             for(var i = 0; i < group.Length; i++)
440             {
441                 collection.Add(initialAddress + 0x4 * i, group[i]);
442             }
443         }
444 
ReadRadioStatus1Register()445         private uint ReadRadioStatus1Register()
446         {
447             if(txPendingCounter > 0)
448             {
449                 txPendingCounter--;
450             }
451 
452             lock(rxLock)
453             {
454                 return (rxQueue.Count == 0 ? 0u : 3 << 6) // FIFO, FIFOP
455                     | 1u << 4 // clear channel assessment
456                     | (txPendingCounter > 0 ? 2u : 0);
457             }
458         }
459 
WriteSourceShortAddressEnableRegister(int index, uint value)460         private void WriteSourceShortAddressEnableRegister(int index, uint value)
461         {
462             for(byte i = 0; i < 8; i++)
463             {
464                 srcShortEnabled[i + 8 * index] = BitHelper.IsBitSet(value, i);
465             }
466         }
467 
ReadSourceShortAddressEnableRegister(int index)468         private uint ReadSourceShortAddressEnableRegister(int index)
469         {
470             var result = 0u;
471             for(byte i = 0; i < 8; i++)
472             {
473                 if(srcShortEnabled[i + 8 * index])
474                 {
475                     BitHelper.SetBit(ref result, i, true);
476                 }
477             }
478             return result;
479         }
480 
WriteSourceExtendedAddressEnableRegister(int index, uint value)481         private void WriteSourceExtendedAddressEnableRegister(int index, uint value)
482         {
483             for(var i = 0; i < 4; i++)
484             {
485                 srcExtendedEnabled[i + 4 * index] = BitHelper.IsBitSet(value, (byte)(2 * i));
486             }
487         }
488 
ReadSourceExtendedAddressEnableRegister(int index)489         private uint ReadSourceExtendedAddressEnableRegister(int index)
490         {
491             var result = 0u;
492             for(var i = 0; i < 4; i++)
493             {
494                 if(srcExtendedEnabled[i + 4 * index])
495                 {
496                     BitHelper.SetBit(ref result, (byte)(2 * i), true);
497                 }
498             }
499             return result;
500         }
501 
ReadSrcResMaskRegister(int id)502         private uint ReadSrcResMaskRegister(int id)
503         {
504             var result = 0u;
505             for(byte i = 0; i < 8; i++)
506             {
507                 BitHelper.SetBit(ref result, i, matchedSourceAddresses[i + 8 * id]);
508             }
509             return result;
510         }
511 
WriteSrcResMaskRegister(int index, uint value)512         private void WriteSrcResMaskRegister(int index, uint value)
513         {
514             for(byte i = 0; i < 8; i++)
515             {
516                 matchedSourceAddresses[i + 8 * index] = BitHelper.IsBitSet(value, i);
517             }
518         }
519 
ReadSrcExtendedAddressPendingEnabledRegister(int index)520         private uint ReadSrcExtendedAddressPendingEnabledRegister(int index)
521         {
522             var result = 0u;
523             for(var i = 0; i < 4; i++)
524             {
525                 if(srcExtendedPendEnabled[i + 4 * index])
526                 {
527                     BitHelper.SetBit(ref result, (byte)(2 * i), true);
528                 }
529             }
530             return result;
531         }
532 
WriteSrcExtendedAddressPendingEnabledRegister(int index, uint value)533         private void WriteSrcExtendedAddressPendingEnabledRegister(int index, uint value)
534         {
535             for(var i = 0; i < 4; i++)
536             {
537                 srcExtendedPendEnabled[i + 4 * index] = BitHelper.IsBitSet(value, (byte)(2 * i));
538             }
539         }
540 
ReadSrcShortAddressPendingEnabledRegister(int index)541         private uint ReadSrcShortAddressPendingEnabledRegister(int index)
542         {
543             var result = 0u;
544             for(byte i = 0; i < 8; i++)
545             {
546                 BitHelper.SetBit(ref result, i, srcShortPendEnabled[i + 8 * index]);
547             }
548             return result;
549         }
550 
WriteSrcShortAddressPendingEnabledRegister(int index, uint value)551         private void WriteSrcShortAddressPendingEnabledRegister(int index, uint value)
552         {
553             for(byte i = 0; i < 8; i++)
554             {
555                 srcShortPendEnabled[i + 8 * index] = BitHelper.IsBitSet(value, i);
556             }
557         }
558 
HandleSFRInstruction(uint value)559         private void HandleSFRInstruction(uint value)
560         {
561             switch((CSPInstructions)value)
562             {
563                 case CSPInstructions.TxOn:
564                     fsmState = FSMStates.Tx;
565                     txPendingCounter = TxPendingCounterInitialValue;
566                     SendData();
567                     break;
568                 case CSPInstructions.RxOn:
569                     fsmState = FSMStates.Rx;
570                     break;
571                 case CSPInstructions.RfOff:
572                     fsmState = FSMStates.Idle;
573                     break;
574                 case CSPInstructions.RxFifoFlush:
575                     lock(rxLock)
576                     {
577                         if(rxQueue.Count != 0)
578                         {
579                             this.Log(LogLevel.Warning, "Dropping unreceived frame.");
580                             currentFrameOffset = -1;
581                             rxQueue.Clear();
582                         }
583                     }
584                     break;
585                 case CSPInstructions.TxFifoFlush:
586                     txQueue.Clear();
587                     break;
588                 default:
589                     this.Log(LogLevel.Warning, "Unsupported CSP instruction {0}.", value);
590                     break;
591             }
592         }
593 
DequeueData()594         private byte DequeueData()
595         {
596             lock(rxLock)
597             {
598                 if(rxQueue.Count == 0)
599                 {
600                     this.Log(LogLevel.Warning, "Trying to dequeue data from empty RX FIFO.");
601                     return 0x0;
602                 }
603 
604                 var currentFrame = rxQueue.Peek();
605                 if(currentFrameOffset == -1)
606                 {
607                     // we need to send packet length first
608                     currentFrameOffset++;
609                     return currentFrame.Length;
610                 }
611                 var result = currentFrame.Bytes[currentFrameOffset++];
612                 if(currentFrameOffset == currentFrame.Bytes.Length)
613                 {
614                     rxQueue.Dequeue();
615                     currentFrameOffset = -1;
616 
617                     if(rxQueue.Count > 0)
618                     {
619                         irqHandler.RequestInterrupt(InterruptSource.FifoP);
620                     }
621                 }
622 
623                 return result;
624             }
625         }
626 
EnqueueData(byte value)627         private void EnqueueData(byte value)
628         {
629             this.NoisyLog("Enqueuing data: 0x{0:X}.", value);
630             txQueue.Enqueue((byte)(value & 0xFF));
631         }
632 
SendData()633         private void SendData()
634         {
635             if(txQueue.Count == 0)
636             {
637                 this.Log(LogLevel.Warning, "Attempted to transmit an empty frame.");
638                 return;
639             }
640 
641             irqHandler.RequestInterrupt(InterruptSource.StartOfFrameDelimiter);
642 
643             //ignore the first byte, it's length. Don't drop it though, as the same packet might get resent.
644             var crc = Frame.CalculateCRC(txQueue.Skip(1));
645             var frame = new Frame(txQueue.Skip(1).Concat(crc).ToArray());
646 
647             this.DebugLog("Sending frame {0}.", frame.Bytes.Select(x => "0x{0:X}".FormatWith(x)).Stringify());
648             var fs = FrameSent;
649             if(fs != null)
650             {
651                 fs.Invoke(this, frame.Bytes);
652             }
653             else
654             {
655                 this.Log(LogLevel.Warning, "FrameSent is not initialized. Am I connected to medium?");
656             }
657 
658             irqHandler.RequestInterrupt(InterruptSource.TxDone);
659         }
660 
ShouldWeAcceptThisFrame(Frame frame)661         private bool ShouldWeAcceptThisFrame(Frame frame)
662         {
663             // (1) check if length is ok
664             // (2) check reserved FCF bits
665             // for now we assume it is fine - let's be optimistic. Note - it is implemented in CC2520.
666 
667             // (3) check FCF version
668             if(frame.FrameVersion > maxFrameVersion.Value)
669             {
670                 this.Log(LogLevel.Noisy, "Wrong frame version.");
671                 return false;
672             }
673 
674             // (4) check source/destination addressing mode
675             if(frame.SourceAddressingMode == AddressingMode.Reserved || frame.DestinationAddressingMode == AddressingMode.Reserved)
676             {
677                 this.Log(LogLevel.Noisy, "Wrong addressing mode.");
678                 return false;
679             }
680 
681             // (5) check destination address
682             if(frame.DestinationAddressingMode != AddressingMode.None)
683             {
684                 // (5.1) check destination PAN
685                 if(frame.AddressInformation.DestinationPan != BroadcastPanIdentifier && frame.AddressInformation.DestinationPan != GetPanId())
686                 {
687                     this.Log(LogLevel.Noisy, "Wrong destination PAN.");
688                     return false;
689                 }
690                 // (5.2) check destination short address
691                 if(frame.DestinationAddressingMode == AddressingMode.ShortAddress)
692                 {
693                     if(!frame.AddressInformation.DestinationAddress.IsShortBroadcast && !frame.AddressInformation.DestinationAddress.Equals(shortAddress))
694                     {
695                         this.Log(LogLevel.Noisy, "Wrong destination short address.");
696                         return false;
697                     }
698                 }
699                 // (5.3) check destination extended address
700                 else if(frame.DestinationAddressingMode == AddressingMode.ExtendedAddress)
701                 {
702                     if(!frame.AddressInformation.DestinationAddress.Equals(extendedAddress))
703                     {
704                         this.Log(LogLevel.Noisy, "Wrong destination extended address (i'm {0}, but the message is directed to {1}.", extendedAddress.GetValue(), frame.AddressInformation.DestinationAddress.GetValue());
705                         return false;
706                     }
707                 }
708             }
709 
710             // (6) check frame type
711             //todo: not implemented reserved types (implemented in cc2520)
712             switch(frame.Type)
713             {
714                 case FrameType.Beacon:
715                     if(!acceptBeaconFrames.Value
716                         || frame.Length < 9
717                         || frame.DestinationAddressingMode != AddressingMode.None
718                         || (frame.SourceAddressingMode != AddressingMode.ShortAddress && frame.SourceAddressingMode != AddressingMode.ExtendedAddress)
719                         || (frame.AddressInformation.SourcePan != BroadcastPanIdentifier && frame.AddressInformation.SourcePan != GetPanId()))
720                     {
721                         this.Log(LogLevel.Noisy, "Wrong beacon frame.");
722                         return false;
723                     }
724                     break;
725                 case FrameType.Data:
726                     if(!acceptDataFrames.Value
727                         || frame.Length < 9
728                         || (frame.DestinationAddressingMode == AddressingMode.None
729                             && (!isPanCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId())))
730                     {
731                         this.Log(LogLevel.Noisy, "Wrong data frame.");
732                         return false;
733                     }
734                     break;
735                 case FrameType.ACK:
736                     if(!acceptAckFrames.Value || frame.Length != 5)
737                     {
738                         this.Log(LogLevel.Noisy, "Wrong ACK frame.");
739                         return false;
740                     }
741                     break;
742                 case FrameType.MACControl:
743                     if(!acceptMacCmdFrames.Value
744                         || frame.Length < 9
745                         || (frame.DestinationAddressingMode == AddressingMode.None
746                             && (!isPanCoordinator.Value || frame.AddressInformation.SourcePan != GetPanId())))
747                     {
748                         this.Log(LogLevel.Noisy, "Wrong MAC control frame.");
749                         return false;
750                     }
751                     break;
752                 default:
753                     return false;
754             }
755 
756             return true;
757         }
758 
GetPanId()759         private uint GetPanId()
760         {
761             return (panId[1].Value << 8) | panId[0].Value;
762         }
763 
GetShortPanIdFromRamTable(uint id)764         private ushort GetShortPanIdFromRamTable(uint id)
765         {
766             return (ushort)((ffsmMemory[16 * id] << 8) | (ffsmMemory[16 * id + 1]));
767         }
768 
GetShortSourceAddressFromRamTable(uint id)769         private ushort GetShortSourceAddressFromRamTable(uint id)
770         {
771             return (ushort)((ffsmMemory[16 * id + 2] << 8) | (ffsmMemory[16 * id + 3]));
772         }
773 
GetExtendedSourceAddressFromRamTable(uint id)774         private ulong GetExtendedSourceAddressFromRamTable(uint id)
775         {
776             return ((ffsmMemory[32 * id] << 7 * 8) | (ffsmMemory[32 * id + 1] << 6 * 8)
777                            | (ffsmMemory[32 * id + 2] << 5 * 8) | (ffsmMemory[32 * id + 3] << 4 * 8)
778                            | (ffsmMemory[32 * id + 4] << 3 * 8) | (ffsmMemory[32 * id + 5] << 2 * 8)
779                            | (ffsmMemory[32 * id + 6] << 8) | ffsmMemory[32 * id + 7]);
780         }
781 
782         private int txPendingCounter;
783         private int currentFrameOffset;
784         private FSMStates fsmState;
785 
786         private readonly DoubleWordRegisterCollection registers;
787         private readonly IFlagRegisterField autoAck;
788         private readonly IFlagRegisterField autoCrc;
789         private readonly IFlagRegisterField frameFilterEnabled;
790         private readonly IFlagRegisterField sourceAddressMatchingEnabled;
791         private readonly IFlagRegisterField autoPendEnabled;
792         private readonly IFlagRegisterField pendDataRequestOnly;
793         private readonly IFlagRegisterField appendDataMode;
794         private readonly IFlagRegisterField pendingOr;
795         private readonly IValueRegisterField matchedSourceIndexField;
796         private readonly IFlagRegisterField acceptBeaconFrames;
797         private readonly IFlagRegisterField acceptAckFrames;
798         private readonly IFlagRegisterField acceptDataFrames;
799         private readonly IFlagRegisterField acceptMacCmdFrames;
800         private readonly IFlagRegisterField isPanCoordinator;
801         private readonly IValueRegisterField maxFrameVersion;
802         private readonly DoubleWordRegister[] panId;
803         private readonly bool[] srcShortEnabled;
804         private readonly bool[] srcShortPendEnabled;
805         private readonly bool[] srcExtendedEnabled;
806         private readonly bool[] srcExtendedPendEnabled;
807         private readonly bool[] matchedSourceAddresses;
808         private readonly uint[] ffsmMemory;
809         private readonly object rxLock;
810         private readonly InterruptHandler<InterruptRegister, InterruptSource> irqHandler;
811         private readonly Address shortAddress;
812         private readonly Address extendedAddress;
813         private readonly Queue<Frame> rxQueue;
814         private readonly Queue<byte> txQueue;
815         [Constructor]
816         private readonly PseudorandomNumberGenerator random;
817 
818         private const uint NoSourceIndex = 0x3F;
819         private const int BroadcastPanIdentifier = 0xFFFF;
820         private const int RamTableBaseAddress = 0x40088400;
821         //HACK! TX_ACTIVE is required to be set as 1 few times in a row for contiki
822         private const int TxPendingCounterInitialValue = 4;
823         private const int ChannelResetValue = 11;
824         private const uint FfsmMemoryStart = 0x400;
825         private const uint FfsmMemoryEnd = 0x57C;
826         private const uint RxFifoMemorySize = 0x200;
827 
828         private enum CSPInstructions
829         {
830             RfOff = 0xDF,
831             RxOn = 0xE3,
832             TxOn = 0xE9,
833             RxFifoFlush = 0xED,
834             TxFifoFlush = 0xEE
835         }
836 
837         private enum FSMStates
838         {
839             Idle = 0x00,
840             Rx = 0x07,
841             Tx = 0x22
842         }
843 
844         private enum Register
845         {
846             //not groupped
847             SourceAddressMatchingResult = 0x58C,
848             FrameFiltering0 = 0x600,
849             FrameFiltering1 = 0x604,
850             SourceAddressMatching = 0x608,
851             FrameHandling0 = 0x624,
852             FrameHandling1 = 0x628,
853             FrequencyControl = 0x63C,
854             RadioStatus0 = 0x648,
855             RadioStatus1 = 0x64C,
856             RssiValidStatus = 0x664,
857             RandomData = 0x69C,
858             RfData = 0x828,
859             CommandStrobeProcessor = 0x838,
860             RxFifoBytesCount = 0x66C,
861 
862             //register groups
863             SourceAddressMatchingResultMask = 0x580,
864             SourceExtendedAddressPendingEnabled = 0x590,
865             SourceShortAddressPendingEnabled = 0x59C,
866             ExtendedAddress = 0x5A8,
867             PanId = 0x5C8,
868             ShortAddressRegister = 0x5D0,
869             SourceShortAddressEnable = 0x60C,
870             SourceExtendedAdressEnable = 0x618,
871             InterruptMask = 0x68C,
872             InterruptFlag = 0x830,
873         }
874     }
875 }
876 
877