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