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.Concurrent; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Peripherals.Miscellaneous; 16 using Antmicro.Renode.Time; 17 using Antmicro.Renode.Utilities; 18 19 namespace Antmicro.Renode.Peripherals.Wireless 20 { 21 public class NRF52840_Radio : BasicDoubleWordPeripheral, IRadio, IKnownSize, INRFEventProvider 22 { NRF52840_Radio(IMachine machine)23 public NRF52840_Radio(IMachine machine) : base(machine) 24 { 25 IRQ = new GPIO(); 26 interruptManager = new InterruptManager<Events>(this, IRQ, "RadioIrq"); 27 shorts = new Shorts(); 28 events = new IFlagRegisterField[(int)Events.PHYEnd + 1]; 29 rxBuffer = new ConcurrentQueue<KeyValuePair<byte[], IRadio>>(); 30 DefineRegisters(); 31 Reset(); 32 } 33 Reset()34 public override void Reset() 35 { 36 radioState = State.Disabled; 37 interruptManager.Reset(); 38 base.Reset(); 39 addressPrefixes = new byte[8]; 40 while(rxBuffer.TryDequeue(out var _)) { } 41 } 42 FakePacket()43 public void FakePacket() 44 { 45 ReceiveFrame(new byte[]{0xD6, 0xBE, 0x89, 0x8E, 0x60, 0x11, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x2, 0x1, 0x6, 0x7, 0x3, 0xD, 0x18, 0xF, 0x18, 0xA, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, null); 46 } 47 ReceiveFrame(byte[] frame, IRadio sender)48 public void ReceiveFrame(byte[] frame, IRadio sender) 49 { 50 if(radioState != State.RxIdle) 51 { 52 rxBuffer.Enqueue(new KeyValuePair<byte[], IRadio>(frame, sender)); 53 return; 54 } 55 56 var addressLength = (int)baseAddressLength.Value + 1; 57 var headerLengthInAir = HeaderLengthInAir(); 58 var headerLengthInRAM = HeaderLengthInRAM(); 59 60 var dataAddress = (uint)packetPointer.Value; 61 sysbus.WriteBytes(frame, address: dataAddress, startingIndex: addressLength, count: headerLengthInRAM); 62 var payloadLength = Math.Min(frame[addressLength + (int)s0Length.Value], (byte)maxPacketLength.Value); 63 sysbus.WriteBytes(frame, address: (ulong)(dataAddress + headerLengthInRAM), startingIndex: addressLength + headerLengthInAir, count: payloadLength); 64 65 var crcLen = 4; 66 ScheduleRadioEvents((uint)(headerLengthInAir + payloadLength + crcLen)); 67 } 68 69 public event Action<IRadio, byte[]> FrameSent; 70 71 public event Action<uint> EventTriggered; 72 73 public int Channel 74 { 75 get 76 { 77 return bluetoothLEChannelMap.TryGetValue(Frequency, out var result) 78 ? result 79 : -1; 80 } 81 82 set 83 { 84 throw new RecoverableException("Setting channel manually is not supported"); 85 } 86 } 87 88 public long Size => 0x1000; 89 90 public uint Frequency => (frequencyMap.Value ? 2360 : 2400U) + (uint)frequency.Value; 91 92 public GPIO IRQ { get; } 93 DefineTask(Registers register, Action callback, string name)94 private void DefineTask(Registers register, Action callback, string name) 95 { 96 register.Define(this, name: name) 97 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if(value) callback(); }) 98 .WithReservedBits(1, 31) 99 ; 100 } 101 DefineEvent(Registers register, Action callbackOnSet, Events @event, string name)102 private void DefineEvent(Registers register, Action callbackOnSet, Events @event, string name) 103 { 104 register.Define(this, name: name) 105 .WithFlag(0, out events[(int)@event], writeCallback: (_, value) => 106 { 107 if(value) 108 { 109 callbackOnSet(); 110 } 111 else 112 { 113 interruptManager.SetInterrupt(@event, false); 114 } 115 }) 116 .WithReservedBits(1, 31) 117 ; 118 } 119 DefineRegisters()120 private void DefineRegisters() 121 { 122 DefineTask(Registers.TxEnable, TxEnable, "TASKS_TXEN"); 123 124 DefineTask(Registers.RxEnable, RxEnable, "TASKS_RXEN"); 125 126 DefineTask(Registers.Start, Start, "TASKS_START"); 127 128 DefineTask(Registers.Disable, Disable, "TASKS_DISABLE"); 129 130 DefineEvent(Registers.Ready, () => this.Log(LogLevel.Error, "Trying to trigger READY event, not supported"), Events.Ready, "EVENTS_READY"); 131 DefineEvent(Registers.AddressSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger ADDRESS event, not supported"), Events.Address, "EVENTS_ADDRESS"); 132 DefineEvent(Registers.PayloadSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger PAYLOAD event, not supported"), Events.Payload, "EVENTS_PAYLOAD"); 133 DefineEvent(Registers.PacketSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger END event, not supported"), Events.End, "EVENTS_END"); 134 DefineEvent(Registers.BitCounterMatch, () => this.Log(LogLevel.Error, "Trying to trigger BCMATCH event, not supported"), Events.BitCountMatch, "EVENTS_BCMATCH"); 135 DefineEvent(Registers.RSSIEnd, () => this.Log(LogLevel.Error, "Trying to trigger RSSIEnd event, not supported"), Events.RSSIEnd, "EVENTS_RSSIEND"); 136 DefineEvent(Registers.CRCOk, () => this.Log(LogLevel.Error, "Trying to trigger CRCOk event, not supported"), Events.CRCOk, "EVENTS_CRCOK"); 137 138 DefineEvent(Registers.RadioDisabled, Disable, Events.Disabled, "EVENTS_DISABLED"); 139 140 DefineEvent(Registers.TxReady, TxEnable, Events.TxReady, "EVENTS_TXREADY"); 141 142 DefineEvent(Registers.RxReady, RxEnable, Events.RxReady, "EVENTS_RXREADY"); 143 144 // Notice: while the whole Shorts register is implemented, we don't necessarily 145 // support all the mentioned events and tasks 146 Registers.Shorts.Define(this) 147 .WithFlag(0, out shorts.ReadyStart, name: "READY_START") 148 .WithFlag(1, out shorts.EndDisable, name: "END_DISABLE") 149 .WithFlag(2, out shorts.DisabledTxEnable, name: "DISABLED_TXEN") 150 .WithFlag(3, out shorts.DisabledRxEnable, name: "DISABLED_RXEN") 151 .WithFlag(4, out shorts.AddressRSSIStart, name: "ADDRESS_RSSISTART") 152 .WithFlag(5, out shorts.EndStart, name: "END_START") 153 .WithFlag(6, out shorts.AddressBitCountStart, name: "ADDRESS_BCSTART") 154 .WithFlag(8, out shorts.DisabledRSSIStop, name: "DISABLED_RSSISTOP") 155 .WithFlag(11, out shorts.RxReadyCCAStart, name: "RXREADY_CCASTART") 156 .WithFlag(12, out shorts.CCAIdleTxEnable, name: "CCAIDLE_TXEN") 157 .WithFlag(13, out shorts.CCABusyDisable, name: "CCABUSY_DISABLE") 158 .WithFlag(14, out shorts.FrameStartBitCountStart, name: "FRAMESTART_BCSTART") 159 .WithFlag(15, out shorts.ReadyEnergyDetectStart, name: "READY_EDSTART") 160 .WithFlag(16, out shorts.EnergyDetectEndDisable, name: "EDEND_DISABLE") 161 .WithFlag(17, out shorts.CCAIdleStop, name: "CCAIDLE_STOP") 162 .WithFlag(18, out shorts.TxReadyStart, name: "TXREADY_START") 163 .WithFlag(19, out shorts.RxReadyStart, name: "RXREADY_START") 164 .WithFlag(20, out shorts.PHYEndDisable, name: "PHYEND_DISABLE") 165 .WithFlag(21, out shorts.PHYEndStart, name: "PHYEND_START") 166 .WithReservedBits(22, 10) 167 ; 168 169 RegistersCollection.AddRegister((long)Registers.InterruptEnable, 170 interruptManager.GetInterruptEnableSetRegister<DoubleWordRegister>()); 171 172 RegistersCollection.AddRegister((long)Registers.InterruptDisable, 173 interruptManager.GetInterruptEnableClearRegister<DoubleWordRegister>()); 174 175 Registers.CRCStatus.Define(this) 176 .WithFlag(0, name: "CRCSTATUS", valueProviderCallback: _ => true) // we assume here that CRCs are always ok 177 .WithReservedBits(1, 31) 178 ; 179 180 Registers.PacketPointer.Define(this) 181 .WithValueField(0, 32, out packetPointer, name: "PACKETPTR") 182 ; 183 184 Registers.Frequency.Define(this, name: "FREQUENCY") 185 .WithValueField(0, 7, out frequency, name: "FREQUENCY") 186 .WithReservedBits(7, 1) 187 .WithFlag(8, out frequencyMap, name: "MAP") 188 .WithReservedBits(9, 23) 189 ; 190 191 Registers.TxPower.Define(this, name: "TXPOWER") 192 .WithValueField(0, 8, name: "TXPOWER") // just RW 193 .WithReservedBits(8, 24) 194 ; 195 196 Registers.Mode.Define(this, name: "MODE") 197 .WithValueField(0, 4, name: "MODE") // just RW 198 .WithReservedBits(4, 24) 199 ; 200 201 Registers.PacketConfiguration0.Define(this, name: "PCNF0") 202 .WithValueField(0, 4, out lengthFieldLength, name: "LFLEN") 203 .WithReservedBits(4, 4) 204 .WithValueField(8, 1, out s0Length, name: "S0LEN") 205 .WithReservedBits(9, 7) 206 .WithValueField(16, 4, out s1Length, name: "S1LEN") 207 .WithFlag(20, out s1Include, name: "S1INCL") 208 .WithReservedBits(21, 1) 209 .WithValueField(22, 2, out codeIndicatorLength, name: "CILEN") 210 .WithTag("PLEN", 24, 2) 211 .WithFlag(26, out crcIncludedInLength, name: "CRCINC") 212 .WithReservedBits(27, 2) 213 .WithValueField(29, 2, out termLength, name: "TERMLEN") 214 .WithReservedBits(31, 1) 215 ; 216 217 Registers.PacketConfiguration1.Define(this, name: "PCNF1") 218 .WithValueField(0, 8, out maxPacketLength, name: "MAXLEN") 219 .WithValueField(8, 8, out staticLength, name: "STATLEN") 220 .WithValueField(16, 3, out baseAddressLength, name: "BALEN") 221 .WithReservedBits(19, 5) 222 .WithTaggedFlag("ENDIAN", 24) 223 .WithTaggedFlag("WHITEEN", 25) 224 .WithReservedBits(26, 6) 225 ; 226 227 Registers.BaseAddress0.Define(this) 228 .WithValueField(0, 32, out baseAddress0, name: "BASE0") 229 ; 230 231 Registers.BaseAddress1.Define(this) 232 .WithValueField(0, 32, out baseAddress1, name: "BASE1") 233 ; 234 235 Registers.Prefix0.Define(this, name: "PREFIX0") 236 .WithValueFields(0, 8, 4, writeCallback: (i, _, value) => addressPrefixes[i] = (byte)value, name: "AP") 237 ; 238 239 Registers.Prefix1.Define(this, name: "PREFIX1") 240 .WithValueFields(0, 8, 4, writeCallback: (i, _, value) => addressPrefixes[4 + i] = (byte)value, name: "AP") 241 ; 242 243 Registers.TxAddress.Define(this, name: "TXADDRESS") 244 .WithValueField(0, 3, out txAddress, name: "TXADDRESS") 245 .WithReservedBits(3, 29) 246 ; 247 248 Registers.RxAddresses.Define(this, name: "RXADDRESSES") 249 .WithFlags(0, 8, out rxAddressEnabled, name: "ADDR") 250 ; 251 252 Registers.CRCConfiguration.Define(this, name: "CRCCNF") 253 .WithValueField(0, 2, out crcLength, name: "LEN") 254 .WithReservedBits(2, 6) 255 .WithEnumField(8, 2, out crcSkipAddress, name: "SKIPADDR") 256 .WithReservedBits(10, 21) 257 ; 258 259 Registers.CRCPolynomial.Define(this, name: "CRCPOLY") 260 .WithValueField(0, 24, out crcPolynomial, name: "CRCPOLY") 261 .WithReservedBits(24, 8) 262 ; 263 264 Registers.CRCInitialValue.Define(this, name: "CRCINIT") 265 .WithValueField(0, 24, out crcInitialValue, name: "CRCINIT") 266 .WithReservedBits(24, 8) 267 ; 268 269 Registers.RSSISample.Define(this, name: "RSSISAMPLE") 270 .WithValueField(0, 32, valueProviderCallback: _ => DefaultRSSISample, name: "RSSISAMPLE"); 271 ; 272 273 Registers.State.Define(this, name: "STATE") 274 .WithEnumField<DoubleWordRegister, State>(0, 4, FieldMode.Read, valueProviderCallback: _ => radioState, name: "STATE") 275 .WithReservedBits(4, 28) 276 ; 277 278 Registers.BitCounterCompare.Define(this, name: "BCC") 279 .WithValueField(0, 32, out bitCountCompare) 280 ; 281 282 Registers.ModeConfiguration0.Define(this, 0x200) 283 .WithTaggedFlag("RU", 0) 284 .WithReservedBits(1, 7) 285 .WithTag("DTX", 8, 2) 286 .WithReservedBits(10, 22) 287 ; 288 289 Registers.CCAControl.Define(this, 0x052D0000, name: "CCACTRL") 290 .WithEnumField(0, 3, out ccaMode, name: "CCAMODE") 291 .WithReservedBits(3, 5) 292 .WithTag("CCAEDTHRES", 8, 8) 293 .WithTag("CCACORRTHRES", 16, 8) 294 .WithTag("CCACORRCNT", 24, 8) 295 ; 296 297 Registers.PowerControl.Define(this, 1, name: "POWER") 298 //TODO: radio should be disabled with powerOn == false 299 .WithFlag(0, out powerOn, changeCallback: (_, value) => { if(!value) Reset(); }, name: "POWER") 300 .WithReservedBits(1, 31) 301 ; 302 } 303 LogUnhandledShort(IFlagRegisterField field, string shortName)304 private void LogUnhandledShort(IFlagRegisterField field, string shortName) 305 { 306 if(field.Value) 307 { 308 this.Log(LogLevel.Error, $"Unhandled short {shortName}!"); 309 } 310 } 311 312 private void SetEvent(Events @event) 313 { 314 interruptManager.SetInterrupt(@event); 315 events[(int)@event].Value = true; 316 EventTriggered?.Invoke((uint)@event * 4 + 0x100); 317 } 318 Disable()319 private void Disable() 320 { 321 radioState = State.Disabled; 322 SetEvent(Events.Disabled); 323 LogUnhandledShort(shorts.DisabledRSSIStop, nameof(shorts.DisabledRSSIStop)); 324 LogUnhandledShort(shorts.DisabledRxEnable, nameof(shorts.DisabledRxEnable)); 325 LogUnhandledShort(shorts.DisabledTxEnable, nameof(shorts.DisabledTxEnable)); 326 } 327 328 // These comments sum up some details gathered from the documentation. 329 // 330 // Packet: 331 // preamble, address (base + prefix), CI, TERM1, S0, LENGTH, S1, PAYLOAD, STATIC PAYLOAD (from STATLEN), CRC, TERM2 332 333 // Packet data stored in RAM: 334 // S0, Length, S1, Payload 335 336 // CRC: 337 // start with address, start with CI or start with L1 338 339 // S0 + Length + S1 + payload <= 258 bytes 340 341 // transmit sequence 342 // TXEn -> State.TxRampup -> Event.Ready -> State.TxIdle. Start -> State.Tx. Sending data: P, A, --> Event.Address, S0, L, S1, Payload, --> Event.Payload, CRC, --> Event.End (data finished) -> State.TxIdle. 343 // Disable -> State.TxDisable -> Event.Disabled 344 345 // transmit sequence with shortcuts 346 // TXEn -> State.TxRampup -> Event.Ready shortcut to Start, Event.End shortcut to Disable 347 348 // transmit multiple packets 349 // no shortcut end->disable. After Event.End, send start 350 351 // receive sequence 352 // RXEn -> State.RxRampup -> Event.Ready -> State.RxIdle. Start->State.Rx. Receiving data: P, A --> Event.Address, s0, l, s1, payload --> Event.Payload, crc -->Event.End (data finished) --> State.RxIdle 353 // Disable --> State.RxDisable -> Event.Disabled 354 TxEnable()355 private void TxEnable() 356 { 357 radioState = State.TxIdle; 358 // we're skipping rampup, it's instant 359 360 SetEvent(Events.Ready); 361 SetEvent(Events.TxReady); 362 363 if(shorts.ReadyStart.Value || shorts.TxReadyStart.Value) 364 { 365 Start(); 366 } 367 LogUnhandledShort(shorts.ReadyEnergyDetectStart, nameof(shorts.ReadyEnergyDetectStart)); 368 } 369 RxEnable()370 private void RxEnable() 371 { 372 radioState = State.RxIdle; 373 // we're skipping rampup, it's instant 374 375 SetEvent(Events.Ready); 376 SetEvent(Events.RxReady); 377 378 if(shorts.ReadyStart.Value || shorts.RxReadyStart.Value) 379 { 380 Start(); 381 } 382 LogUnhandledShort(shorts.ReadyEnergyDetectStart, nameof(shorts.ReadyEnergyDetectStart)); 383 } 384 Start()385 private void Start() 386 { 387 // common task for both reception and transmission 388 if(radioState == State.TxIdle) 389 { 390 SendPacket(); 391 } 392 else if(radioState == State.RxIdle) 393 { 394 // Can only receive one packet per enable 395 if(rxBuffer.TryDequeue(out var pair)) 396 { 397 ReceiveFrame(pair.Key, pair.Value); 398 } 399 } 400 else 401 { 402 this.Log(LogLevel.Error, "Triggered the Start task in an unexpected state {0}", radioState.ToString()); 403 } 404 } 405 HeaderLengthInAir()406 private int HeaderLengthInAir() 407 { 408 return (int)Math.Ceiling((s0Length.Value * 8 + lengthFieldLength.Value + s1Length.Value) / 8.0); 409 } 410 HeaderLengthInRAM()411 private int HeaderLengthInRAM() 412 { 413 int ret = (int)s0Length.Value + (int)Math.Ceiling(lengthFieldLength.Value / 8.0) + (int)Math.Ceiling(s1Length.Value / 8.0); 414 if(s1Length.Value == 0 && s1Include.Value) 415 { 416 ret += 1; 417 } 418 return ret; 419 } 420 SendPacket()421 private void SendPacket() 422 { 423 var dataAddress = (uint)packetPointer.Value; 424 var headerLengthInAir = HeaderLengthInAir(); 425 var addressLength = (int)baseAddressLength.Value + 1; 426 var headerLengthInRAM = HeaderLengthInRAM(); 427 if(headerLengthInAir != headerLengthInRAM) 428 { 429 this.Log(LogLevel.Noisy, "Header length difference between onAir={0} and inRam={1}", headerLengthInAir, headerLengthInRAM); 430 } 431 432 var data = new byte[addressLength + headerLengthInRAM + (uint)maxPacketLength.Value]; 433 FillCurrentAddress(data, 0, (uint)txAddress.Value); 434 435 sysbus.ReadBytes(dataAddress, headerLengthInRAM, data, addressLength); 436 this.Log(LogLevel.Noisy, "Header: {0} S0 {1} Length {2} S1 {3} s1inc {4}", Misc.PrettyPrintCollectionHex(data), s0Length.Value, lengthFieldLength.Value, s1Length.Value, s1Include.Value); 437 var payloadLength = data[addressLength + (uint)s0Length.Value]; 438 if(payloadLength > maxPacketLength.Value) 439 { 440 this.Log(LogLevel.Error, "Payload length ({0}) longer than the max packet length ({1}), trimming...", payloadLength, maxPacketLength.Value); 441 payloadLength = (byte)maxPacketLength.Value; 442 } 443 sysbus.ReadBytes((ulong)(dataAddress + headerLengthInRAM), payloadLength, data, addressLength + headerLengthInAir); 444 this.Log(LogLevel.Noisy, "Data: {0} Maxlen {1} statlen {2}", Misc.PrettyPrintCollectionHex(data), maxPacketLength.Value, staticLength.Value); 445 446 FrameSent?.Invoke(this, data); 447 448 var crcLen = 4; 449 ScheduleRadioEvents((uint)(headerLengthInAir + payloadLength + crcLen)); 450 451 LogUnhandledShort(shorts.EndStart, nameof(shorts.EndStart)); // not sure how to support it. It's instant from our perspective. 452 } 453 ScheduleRadioEvents(uint packetLen)454 private void ScheduleRadioEvents(uint packetLen) 455 { 456 var timeSource = machine.LocalTimeSource; 457 var now = timeSource.ElapsedVirtualTime; 458 459 // @note Transmit times assume 1M PHY. Low level BLE firmware 460 // usually takes into account the active phy when calculating 461 // timing delays, so we might need to do that. 462 463 // Bit-counter 464 var bcMatchTime = now + TimeInterval.FromMicroseconds(bitCountCompare.Value); 465 var bcMatchTimeStamp = new TimeStamp(bcMatchTime, timeSource.Domain); 466 467 // End event 468 var endTime = now + TimeInterval.FromMicroseconds((uint)(packetLen) * 8); 469 var endTimeStamp = new TimeStamp(endTime, timeSource.Domain); 470 471 var disableTime = endTime + TimeInterval.FromMicroseconds(10); 472 var disableTimeStamp = new TimeStamp(disableTime, timeSource.Domain); 473 474 // Address modelled as happening immediatley and serves as anchor 475 // point for other events. RIOT triggers IRQ from it. 476 SetEvent(Events.Address); 477 478 // RSSI sample period is 0.25 us. Acceptable to model as happening 479 // immediatley upon start 480 if(shorts.AddressRSSIStart.Value) 481 { 482 SetEvent(Events.RSSIEnd); 483 } 484 485 // Schedule a single bit-counter compare event not eariler than 486 // `bitCountCompare` microseconds from now. 487 // This is sufficient for BLE with RIOT stack, however it is possible to use bit 488 // counter to generate successive events, which this model will not 489 // support. 490 if(shorts.AddressBitCountStart.Value) 491 { 492 timeSource.ExecuteInSyncedState(_ => 493 { 494 SetEvent(Events.BitCountMatch); 495 }, bcMatchTimeStamp); 496 } 497 498 // Schedule "end" events all at once, simulating the transmision time 499 // as 8 microseconds-per-byte. Timing distinction between events here doesn't 500 // seem important 501 timeSource.ExecuteInSyncedState(_ => 502 { 503 SetEvent(Events.Payload); 504 SetEvent(Events.End); 505 SetEvent(Events.CRCOk); 506 }, endTimeStamp); 507 508 // BLE stacks use disabled event as common processing trigger. 509 timeSource.ExecuteInSyncedState(_ => 510 { 511 if(shorts.EndDisable.Value) 512 { 513 Disable(); 514 } 515 }, disableTimeStamp); 516 } 517 FillCurrentAddress(byte[] data, int startIndex, uint logicalAddress)518 private void FillCurrentAddress(byte[] data, int startIndex, uint logicalAddress) 519 { 520 // based on 6.20.2 Address configuration 521 var baseAddress = (uint)(logicalAddress == 0 ? baseAddress0.Value : baseAddress1.Value); 522 var baseBytes = BitConverter.GetBytes(baseAddress); 523 var i = 0; 524 if(baseAddressLength.Value > 4) 525 { 526 this.Log(LogLevel.Error, "Trying to fill the current address, but the base address length is too large ({0}). Limiting to 4.", baseAddressLength.Value); 527 baseAddressLength.Value = 4; 528 } 529 for(var j = 4 - baseAddressLength.Value; j < 4; i++, j++) // we're not supporting BALEN > 4. I don't know how should it work. 530 { 531 data[startIndex + i] = baseBytes[j]; 532 } 533 data[startIndex + i] = addressPrefixes[logicalAddress]; 534 } 535 536 private const int DefaultRSSISample = 10; 537 538 private readonly ConcurrentQueue<KeyValuePair<byte[], IRadio>> rxBuffer; 539 private Shorts shorts; 540 private byte[] addressPrefixes; 541 private State radioState; 542 private InterruptManager<Events> interruptManager; 543 544 private IFlagRegisterField[] events; 545 private IValueRegisterField packetPointer; 546 private IValueRegisterField frequency; 547 private IFlagRegisterField frequencyMap; 548 private IValueRegisterField lengthFieldLength; 549 private IValueRegisterField s0Length; 550 private IValueRegisterField s1Length; 551 private IFlagRegisterField s1Include; 552 private IValueRegisterField codeIndicatorLength; 553 private IFlagRegisterField crcIncludedInLength; 554 private IValueRegisterField termLength; 555 private IValueRegisterField maxPacketLength; 556 private IValueRegisterField staticLength; 557 private IValueRegisterField baseAddressLength; 558 private IValueRegisterField baseAddress0; 559 private IValueRegisterField baseAddress1; 560 private IValueRegisterField txAddress; 561 private IFlagRegisterField[] rxAddressEnabled; 562 563 private IValueRegisterField bitCountCompare; 564 565 private IValueRegisterField crcLength; 566 private IEnumRegisterField<CRCAddressHandling> crcSkipAddress; 567 private IValueRegisterField crcPolynomial; 568 private IValueRegisterField crcInitialValue; 569 private IEnumRegisterField<CCAMode> ccaMode; 570 private IFlagRegisterField powerOn; 571 572 private readonly Dictionary<uint, int> bluetoothLEChannelMap = new Dictionary<uint, int>() 573 { 574 { 2402, 37 }, 575 { 2404, 0 }, 576 { 2406, 1 }, 577 { 2408, 2 }, 578 { 2410, 3 }, 579 { 2412, 4 }, 580 { 2414, 5 }, 581 { 2416, 6 }, 582 { 2418, 7 }, 583 { 2420, 8 }, 584 { 2422, 9 }, 585 { 2424, 10 }, 586 { 2426, 38 }, 587 { 2428, 11 }, 588 { 2430, 12 }, 589 { 2432, 13 }, 590 { 2434, 14 }, 591 { 2436, 15 }, 592 { 2438, 16 }, 593 { 2440, 17 }, 594 { 2442, 18 }, 595 { 2444, 19 }, 596 { 2446, 20 }, 597 { 2448, 21 }, 598 { 2450, 22 }, 599 { 2452, 23 }, 600 { 2454, 24 }, 601 { 2456, 25 }, 602 { 2458, 26 }, 603 { 2460, 27 }, 604 { 2462, 28 }, 605 { 2464, 29 }, 606 { 2466, 30 }, 607 { 2468, 31 }, 608 { 2470, 32 }, 609 { 2472, 33 }, 610 { 2474, 34 }, 611 { 2476, 35 }, 612 { 2478, 36 }, 613 { 2480, 39 }, 614 }; 615 616 private struct Shorts 617 { 618 public IFlagRegisterField ReadyStart; 619 public IFlagRegisterField EndDisable; 620 public IFlagRegisterField DisabledTxEnable; 621 public IFlagRegisterField DisabledRxEnable; 622 public IFlagRegisterField AddressRSSIStart; 623 public IFlagRegisterField EndStart; 624 public IFlagRegisterField AddressBitCountStart; 625 public IFlagRegisterField DisabledRSSIStop; 626 public IFlagRegisterField RxReadyCCAStart; 627 public IFlagRegisterField CCAIdleTxEnable; 628 public IFlagRegisterField CCABusyDisable; 629 public IFlagRegisterField FrameStartBitCountStart; 630 public IFlagRegisterField ReadyEnergyDetectStart; 631 public IFlagRegisterField EnergyDetectEndDisable; 632 public IFlagRegisterField CCAIdleStop; 633 public IFlagRegisterField TxReadyStart; 634 public IFlagRegisterField RxReadyStart; 635 public IFlagRegisterField PHYEndDisable; 636 public IFlagRegisterField PHYEndStart; 637 } 638 639 private enum CRCAddressHandling 640 { 641 Include = 0, 642 Skip = 1, 643 IEEE802154 = 2 644 } 645 646 private enum State 647 { 648 Disabled = 0, 649 RxRampup = 1, 650 RxIdle = 2, 651 Rx = 3, 652 RxDisable = 4, 653 TxRampup = 9, 654 TxIdle = 10, 655 Tx = 11, 656 TxDisable = 12, 657 } 658 659 private enum Events 660 { 661 Ready = 0, 662 Address = 1, 663 Payload = 2, 664 End = 3, 665 Disabled = 4, 666 DeviceAddressMatch = 5, 667 DeviceAddressMiss = 6, 668 RSSIEnd = 7, 669 BitCountMatch = 10, 670 CRCOk = 12, 671 CRCError = 13, 672 FrameStart = 14, 673 EnergyDetectEnd = 15, 674 EnergyDetectStopped = 16, 675 CCAIdle = 17, 676 CCABusy = 18, 677 CCAStopped = 19, 678 RateBoost = 20, 679 TxReady = 21, 680 RxReady = 22, 681 MACHeaderMatch = 23, 682 Sync = 26, 683 PHYEnd = 27 684 } 685 686 private enum CCAMode 687 { 688 EdMode, 689 CarrierMode, 690 CarrierAndEdMode, 691 CarrierOrEdMode, 692 EdMoteTest1 693 } 694 695 private enum Registers 696 { 697 TxEnable = 0x000, 698 RxEnable = 0x004, 699 Start = 0x008, 700 Stop = 0x00C, 701 Disable = 0x010, 702 RSSIStart = 0x014, 703 RSSIStop = 0x018, 704 BitCounterStart = 0x01C, 705 BitCounterStop = 0x020, 706 EnergyDetectStart = 0x024, 707 EnergyDetectStop = 0x028, 708 CCAStart = 0x02C, 709 CCAStop = 0x030, 710 Ready = 0x100, 711 AddressSentOrReceived = 0x104, 712 PayloadSentOrReceived = 0x108, 713 PacketSentOrReceived = 0x10C, 714 RadioDisabled = 0x110, 715 DeviceMatch = 0x114, 716 DeviceMiss = 0x118, 717 RSSIEnd = 0x11C, 718 BitCounterMatch = 0x128, 719 CRCOk = 0x130, 720 CRCError = 0x134, 721 FrameStartReceived = 0x138, 722 EnergyDetectEnd = 0x13C, 723 EnergyDetectStopped = 0x140, 724 CCAIdle = 0x144, 725 CCABusy = 0x148, 726 CCAStopped = 0x14C, 727 RateBoost = 0x150, 728 TxReady = 0x154, 729 RxReady = 0x158, 730 MACHeaderMatch = 0x15C, 731 Sync = 0x168, 732 PHYEnd = 0x16C, 733 Shorts = 0x200, 734 InterruptEnable = 0x304, 735 InterruptDisable = 0x308, 736 CRCStatus = 0x400, 737 RxMatch = 0x408, 738 RxCRC = 0x40C, 739 DeviceAddressMatchIndex = 0x410, 740 PayloadStatus = 0x414, 741 PacketPointer = 0x504, 742 Frequency = 0x508, 743 TxPower = 0x50C, 744 Mode = 0x510, 745 PacketConfiguration0 = 0x514, 746 PacketConfiguration1 = 0x518, 747 BaseAddress0 = 0x51C, 748 BaseAddress1 = 0x520, 749 Prefix0 = 0x524, 750 Prefix1 = 0x528, 751 TxAddress = 0x52C, 752 RxAddresses = 0x530, 753 CRCConfiguration = 0x534, 754 CRCPolynomial = 0x538, 755 CRCInitialValue = 0x53C, 756 InterframeSpacing = 0x544, 757 RSSISample = 0x548, 758 State = 0x550, 759 DataWhiteningInitialValue = 0x554, 760 BitCounterCompare = 0x560, 761 DeviceAddressBaseSegment0 = 0x600, 762 DeviceAddressBaseSegment1 = 0x604, 763 DeviceAddressBaseSegment2 = 0x608, 764 DeviceAddressBaseSegment3 = 0x60C, 765 DeviceAddressBaseSegment4 = 0x610, 766 DeviceAddressBaseSegment5 = 0x614, 767 DeviceAddressBaseSegment6 = 0x618, 768 DeviceAddressBaseSegment7 = 0x61C, 769 DeviceAddressPrefix0 = 0x620, 770 DeviceAddressPrefix1 = 0x624, 771 DeviceAddressPrefix2 = 0x628, 772 DeviceAddressPrefix3 = 0x62C, 773 DeviceAddressPrefix4 = 0x630, 774 DeviceAddressPrefix5 = 0x634, 775 DeviceAddressPrefix6 = 0x638, 776 DeviceAddressPrefix7 = 0x63C, 777 DeviceAddressMatchConfiguration = 0x640, 778 SearchPatternConfiguration = 0x644, 779 PatternMask = 0x648, 780 ModeConfiguration0 = 0x650, 781 StartOfFrameDelimiter = 0x660, 782 EnergyDetectLoopCount = 0x664, 783 EnergyDetectLevel = 0x668, 784 CCAControl = 0x66C, 785 PowerControl = 0xFFC 786 } 787 } 788 } 789