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