1 /* 2 * Copyright (c) 2018, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for the spinel based radio transceiver. 32 */ 33 34 #ifndef RADIO_SPINEL_HPP_ 35 #define RADIO_SPINEL_HPP_ 36 37 #include <openthread/platform/radio.h> 38 39 #include "openthread-spinel-config.h" 40 #include "spinel.h" 41 #include "spinel_interface.hpp" 42 #include "core/radio/max_power_table.hpp" 43 #include "ncp/ncp_config.h" 44 45 namespace ot { 46 namespace Spinel { 47 48 /** 49 * The class for providing a OpenThread radio interface by talking with a radio-only 50 * co-processor(RCP). The InterfaceType template parameter should provide the following 51 * methods: 52 * 53 * class InterfaceType { 54 * 55 * // This constructor initializes the object. 56 * 57 * // @param[in] aCallback Callback on frame received 58 * // @param[in] aCallbackContext Callback context 59 * // @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. 60 * 61 * InterfaceType(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, 62 * void * aCallbackContext, 63 * Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); 64 * 65 * 66 * // This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. 67 * 68 * // This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for 69 * // up to `kMaxWaitTime` interval. 70 * 71 * // @param[in] aFrame A pointer to buffer containing the spinel frame to send. 72 * // @param[in] aLength The length (number of bytes) in the frame. 73 * 74 * // @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame. 75 * // @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame. 76 * // @retval OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`. 77 * 78 * otError SendFrame(const uint8_t *aFrame, uint16_t aLength); 79 * 80 * 81 * // This method waits for receiving part or all of spinel frame within specified interval. 82 * 83 * // @param[in] aTimeout The timeout value in microseconds. 84 * 85 * // @retval OT_ERROR_NONE Part or all of spinel frame is received. 86 * // @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. 87 * 88 * otError WaitForFrame(uint64_t& aTimeoutUs); 89 * 90 * 91 * // This method performs radio driver processing. 92 * 93 * // @param[in] aContext The context containing fd_sets. 94 * // The type is specified by the user in template parameters. 95 * 96 * void Process(const ProcessContextType &aContext); 97 * 98 * 99 * // This method deinitializes the interface to the RCP. 100 * 101 * void Deinit(void); 102 * }; 103 */ 104 template <typename InterfaceType, typename ProcessContextType> class RadioSpinel 105 { 106 public: 107 /** 108 * This constructor initializes the spinel based OpenThread transceiver. 109 * 110 */ 111 RadioSpinel(void); 112 113 /** 114 * Initialize this radio transceiver. 115 * 116 * @param[in] aResetRadio TRUE to reset on init, FALSE to not reset on init. 117 * @param[in] aRestoreDatasetFromNcp TRUE to restore dataset to host from non-volatile memory 118 * (only used when attempts to upgrade from NCP to RCP mode), 119 * FALSE otherwise. 120 * @param[in] aSkipRcpCompatibilityCheck TRUE to skip RCP compatibility check, FALSE to perform the check. 121 * 122 */ 123 void Init(bool aResetRadio, bool aRestoreDataSetFromNcp, bool aSkipRcpCompatibilityCheck); 124 125 /** 126 * Deinitialize this radio transceiver. 127 * 128 */ 129 void Deinit(void); 130 131 /** 132 * This method gets the status of promiscuous mode. 133 * 134 * @retval true Promiscuous mode is enabled. 135 * @retval false Promiscuous mode is disabled. 136 * 137 */ IsPromiscuous(void) const138 bool IsPromiscuous(void) const { return mIsPromiscuous; } 139 140 /** 141 * This method sets the status of promiscuous mode. 142 * 143 * @param[in] aEnable Whether to enable or disable promiscuous mode. 144 * 145 * @retval OT_ERROR_NONE Succeeded. 146 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 147 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 148 * 149 */ 150 otError SetPromiscuous(bool aEnable); 151 152 /** 153 * This method sets the Short Address for address filtering. 154 * 155 * @param[in] aShortAddress The IEEE 802.15.4 Short Address. 156 * 157 * @retval OT_ERROR_NONE Succeeded. 158 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 159 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 160 * 161 */ 162 otError SetShortAddress(uint16_t aAddress); 163 164 /** 165 * This method gets the factory-assigned IEEE EUI-64 for this transceiver. 166 * 167 * @param[in] aInstance The OpenThread instance structure. 168 * @param[out] aIeeeEui64 A pointer to the factory-assigned IEEE EUI-64. 169 * 170 * @retval OT_ERROR_NONE Succeeded. 171 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 172 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 173 * 174 */ 175 otError GetIeeeEui64(uint8_t *aIeeeEui64); 176 177 /** 178 * This method sets the Extended Address for address filtering. 179 * 180 * @param[in] aExtAddress A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order. 181 * 182 * @retval OT_ERROR_NONE Succeeded. 183 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 184 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 185 * 186 */ 187 otError SetExtendedAddress(const otExtAddress &aAddress); 188 189 /** 190 * This method sets the PAN ID for address filtering. 191 * 192 * @param[in] aPanId The IEEE 802.15.4 PAN ID. 193 * 194 * @retval OT_ERROR_NONE Succeeded. 195 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 196 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 197 * 198 */ 199 otError SetPanId(uint16_t aPanId); 200 201 /** 202 * This method gets the radio's transmit power in dBm. 203 * 204 * @param[out] aPower The transmit power in dBm. 205 * 206 * @retval OT_ERROR_NONE Succeeded. 207 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 208 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 209 * 210 */ 211 otError GetTransmitPower(int8_t &aPower); 212 213 /** 214 * This method sets the radio's transmit power in dBm. 215 * 216 * @param[in] aPower The transmit power in dBm. 217 * 218 * @retval OT_ERROR_NONE Succeeded. 219 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 220 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 221 * 222 */ 223 otError SetTransmitPower(int8_t aPower); 224 225 /** 226 * This method gets the radio's CCA ED threshold in dBm. 227 * 228 * @param[out] aThreshold The CCA ED threshold in dBm. 229 * 230 * @retval OT_ERROR_NONE Succeeded. 231 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 232 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 233 * 234 */ 235 otError GetCcaEnergyDetectThreshold(int8_t &aThreshold); 236 237 /** 238 * This method sets the radio's CCA ED threshold in dBm. 239 * 240 * @param[in] aThreshold The CCA ED threshold in dBm. 241 * 242 * @retval OT_ERROR_NONE Succeeded. 243 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 244 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 245 * 246 */ 247 otError SetCcaEnergyDetectThreshold(int8_t aThreshold); 248 249 /** 250 * This method gets the FEM's Rx LNA gain in dBm. 251 * 252 * @param[out] aGain The FEM's Rx LNA gain in dBm. 253 * 254 * @retval OT_ERROR_NONE Succeeded. 255 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 256 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 257 * 258 */ 259 otError GetFemLnaGain(int8_t &aGain); 260 261 /** 262 * This method sets the FEM's Rx LNA gain in dBm. 263 * 264 * @param[in] aGain The FEM's Rx LNA gain in dBm. 265 * 266 * @retval OT_ERROR_NONE Succeeded. 267 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 268 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 269 * 270 */ 271 otError SetFemLnaGain(int8_t aGain); 272 273 /** 274 * This method returns the radio sw version string. 275 * 276 * @returns A pointer to the radio version string. 277 * 278 */ GetVersion(void) const279 const char *GetVersion(void) const { return mVersion; } 280 281 /** 282 * This method returns the radio capabilities. 283 * 284 * @returns The radio capability bit vector. 285 * 286 */ GetRadioCaps(void) const287 otRadioCaps GetRadioCaps(void) const { return mRadioCaps; } 288 289 /** 290 * This method gets the most recent RSSI measurement. 291 * 292 * @returns The RSSI in dBm when it is valid. 127 when RSSI is invalid. 293 */ 294 int8_t GetRssi(void); 295 296 /** 297 * This method returns the radio receive sensitivity value. 298 * 299 * @returns The radio receive sensitivity value in dBm. 300 * 301 * @retval OT_ERROR_NONE Succeeded. 302 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 303 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 304 * 305 */ GetReceiveSensitivity(void) const306 int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; } 307 308 /** 309 * This method gets current state of the radio. 310 * 311 * @return Current state of the radio. 312 * 313 */ 314 otRadioState GetState(void) const; 315 316 /** 317 * This method gets the current receiving channel. 318 * 319 * @returns Current receiving channel. 320 * 321 */ GetChannel(void) const322 uint8_t GetChannel(void) const { return mChannel; } 323 324 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 325 /** 326 * Enable the radio coex. 327 * 328 * @param[in] aInstance The OpenThread instance structure. 329 * @param[in] aEnabled TRUE to enable the radio coex, FALSE otherwise. 330 * 331 * @retval OT_ERROR_NONE Successfully enabled. 332 * @retval OT_ERROR_FAILED The radio coex could not be enabled. 333 * 334 */ 335 otError SetCoexEnabled(bool aEnabled); 336 337 /** 338 * Check whether radio coex is enabled or not. 339 * 340 * @param[in] aInstance The OpenThread instance structure. 341 * 342 * @returns TRUE if the radio coex is enabled, FALSE otherwise. 343 * 344 */ 345 bool IsCoexEnabled(void); 346 347 /** 348 * This method retrieves the radio coexistence metrics. 349 * 350 * @param[out] aCoexMetrics A reference to the coexistence metrics structure. 351 * 352 * @retval OT_ERROR_NONE Successfully retrieved the coex metrics. 353 * @retval OT_ERROR_INVALID_ARGS @p aCoexMetrics was nullptr. 354 * 355 */ 356 otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics); 357 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 358 359 /** 360 * This method returns a reference to the transmit buffer. 361 * 362 * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission. 363 * 364 * @returns A reference to the transmit buffer. 365 * 366 */ GetTransmitFrame(void)367 otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; } 368 369 /** 370 * This method enables or disables source address match feature. 371 * 372 * @param[in] aEnable Enable/disable source address match feature. 373 * 374 * @retval OT_ERROR_NONE Succeeded. 375 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 376 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 377 * 378 */ 379 otError EnableSrcMatch(bool aEnable); 380 381 /** 382 * This method adds a short address to the source address match table. 383 * 384 * @param[in] aInstance The OpenThread instance structure. 385 * @param[in] aShortAddress The short address to be added. 386 * 387 * @retval OT_ERROR_NONE Successfully added short address to the source match table. 388 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 389 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 390 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 391 */ 392 otError AddSrcMatchShortEntry(uint16_t aShortAddress); 393 394 /** 395 * This method removes a short address from the source address match table. 396 * 397 * @param[in] aInstance The OpenThread instance structure. 398 * @param[in] aShortAddress The short address to be removed. 399 * 400 * @retval OT_ERROR_NONE Successfully removed short address from the source match table. 401 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 402 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 403 * @retval OT_ERROR_NO_ADDRESS The short address is not in source address match table. 404 */ 405 otError ClearSrcMatchShortEntry(uint16_t aShortAddress); 406 407 /** 408 * Clear all short addresses from the source address match table. 409 * 410 * @param[in] aInstance The OpenThread instance structure. 411 * 412 * @retval OT_ERROR_NONE Succeeded. 413 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 414 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 415 * 416 */ 417 otError ClearSrcMatchShortEntries(void); 418 419 /** 420 * Add an extended address to the source address match table. 421 * 422 * @param[in] aInstance The OpenThread instance structure. 423 * @param[in] aExtAddress The extended address to be added stored in little-endian byte order. 424 * 425 * @retval OT_ERROR_NONE Successfully added extended address to the source match table. 426 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 427 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 428 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 429 */ 430 otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress); 431 432 /** 433 * Remove an extended address from the source address match table. 434 * 435 * @param[in] aInstance The OpenThread instance structure. 436 * @param[in] aExtAddress The extended address to be removed stored in little-endian byte order. 437 * 438 * @retval OT_ERROR_NONE Successfully removed the extended address from the source match table. 439 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 440 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 441 * @retval OT_ERROR_NO_ADDRESS The extended address is not in source address match table. 442 */ 443 otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress); 444 445 /** 446 * Clear all the extended/long addresses from source address match table. 447 * 448 * @param[in] aInstance The OpenThread instance structure. 449 * 450 * @retval OT_ERROR_NONE Succeeded. 451 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 452 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 453 * 454 */ 455 otError ClearSrcMatchExtEntries(void); 456 457 /** 458 * This method begins the energy scan sequence on the radio. 459 * 460 * @param[in] aScanChannel The channel to perform the energy scan on. 461 * @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned. 462 * 463 * @retval OT_ERROR_NONE Succeeded. 464 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 465 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 466 * 467 */ 468 otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration); 469 470 /** 471 * This method switches the radio state from Receive to Transmit. 472 * 473 * @param[in] aFrame A reference to the transmitted frame. 474 * 475 * @retval OT_ERROR_NONE Successfully transitioned to Transmit. 476 * @retval OT_ERROR_BUSY Failed due to another transmission is on going. 477 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 478 * @retval OT_ERROR_INVALID_STATE The radio was not in the Receive state. 479 */ 480 otError Transmit(otRadioFrame &aFrame); 481 482 /** 483 * This method switches the radio state from Sleep to Receive. 484 * 485 * @param[in] aChannel The channel to use for receiving. 486 * 487 * @retval OT_ERROR_NONE Successfully transitioned to Receive. 488 * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting. 489 * 490 */ 491 otError Receive(uint8_t aChannel); 492 493 /** 494 * This method switches the radio state from Receive to Sleep. 495 * 496 * @retval OT_ERROR_NONE Successfully transitioned to Sleep. 497 * @retval OT_ERROR_BUSY The radio was transmitting 498 * @retval OT_ERROR_INVALID_STATE The radio was disabled 499 * 500 */ 501 otError Sleep(void); 502 503 /** 504 * Enable the radio. 505 * 506 * @param[in] aInstance A pointer to the OpenThread instance. 507 * 508 * @retval OT_ERROR_NONE Successfully enabled. 509 * @retval OT_ERROR_FAILED The radio could not be enabled. 510 * 511 */ 512 otError Enable(otInstance *aInstance); 513 514 /** 515 * Disable the radio. 516 * 517 * @retval OT_ERROR_NONE Successfully transitioned to Disabled. 518 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 519 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 520 * 521 */ 522 otError Disable(void); 523 524 /** 525 * This method checks whether radio is enabled or not. 526 * 527 * @returns TRUE if the radio is enabled, FALSE otherwise. 528 * 529 */ IsEnabled(void) const530 bool IsEnabled(void) const { return mState != kStateDisabled; } 531 532 /** 533 * This method indicates whether there is a pending transmission. 534 * 535 * @retval TRUE There is a pending transmission. 536 * @retval FALSE There is no pending transmission. 537 * 538 */ IsTransmitting(void) const539 bool IsTransmitting(void) const { return mState == kStateTransmitting; } 540 541 /** 542 * This method indicates whether a transmit has just finished. 543 * 544 * @retval TRUE The transmission is done. 545 * @retval FALSE The transmission is not done. 546 * 547 */ IsTransmitDone(void) const548 bool IsTransmitDone(void) const { return mState == kStateTransmitDone; } 549 550 /** 551 * This method returns the timeout timepoint for the pending transmission. 552 * 553 * @returns The timeout timepoint for the pending transmission. 554 * 555 */ GetTxRadioEndUs(void) const556 uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; } 557 558 /** 559 * This method processes any pending the I/O data. 560 * 561 * @param[in] aContext The process context. 562 * 563 */ 564 void Process(const ProcessContextType &aContext); 565 566 /** 567 * This method returns the underlying spinel interface. 568 * 569 * @returns The underlying spinel interface. 570 * 571 */ GetSpinelInterface(void)572 InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; } 573 574 #if OPENTHREAD_CONFIG_DIAG_ENABLE 575 /** 576 * This method enables/disables the factory diagnostics mode. 577 * 578 * @param[in] aMode TRUE to enable diagnostics mode, FALSE otherwise. 579 * 580 */ SetDiagEnabled(bool aMode)581 void SetDiagEnabled(bool aMode) { mDiagMode = aMode; } 582 583 /** 584 * This method indicates whether or not factory diagnostics mode is enabled. 585 * 586 * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise. 587 * 588 */ IsDiagEnabled(void) const589 bool IsDiagEnabled(void) const { return mDiagMode; } 590 591 /** 592 * This method processes platform diagnostics commands. 593 * 594 * @param[in] aString A null-terminated input string. 595 * @param[out] aOutput The diagnostics execution result. 596 * @param[in] aOutputMaxLen The output buffer size. 597 * 598 * @retval OT_ERROR_NONE Succeeded. 599 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 600 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 601 * 602 */ 603 otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); 604 #endif 605 606 /** 607 * This method returns the radio channel mask. 608 * 609 * @param[in] aPreferred TRUE to get preferred channel mask, FALSE to get supported channel mask. 610 * 611 * @returns The radio channel mask according to @aPreferred: 612 * The radio supported channel mask that the device is allowed to be on. 613 * The radio preferred channel mask that the device prefers to form on. 614 * 615 */ 616 uint32_t GetRadioChannelMask(bool aPreferred); 617 618 /** 619 * This method processes a received Spinel frame. 620 * 621 * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`. 622 * 623 */ 624 void HandleReceivedFrame(void); 625 626 /** 627 * This method sets MAC key and key index to RCP. 628 * 629 * @param[in] aKeyIdMode The key ID mode. 630 * @param[in] aKeyId The key index. 631 * @param[in] aPrevKey The previous MAC key. 632 * @param[in] aCurrKey The current MAC key. 633 * @param[in] aNextKey The next MAC key. 634 * 635 * @retval OT_ERROR_NONE Succeeded. 636 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 637 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 638 * 639 */ 640 otError SetMacKey(uint8_t aKeyIdMode, 641 uint8_t aKeyId, 642 const otMacKey &aPrevKey, 643 const otMacKey &aCurrKey, 644 const otMacKey &aNextKey); 645 646 /** 647 * This method sets the current MAC Frame Counter value. 648 * 649 * @param[in] aMacFrameCounter The MAC Frame Counter value. 650 * 651 */ 652 otError SetMacFrameCounter(uint32_t aMacFrameCounter); 653 654 /** 655 * This method sets the radio region code. 656 * 657 * @param[in] aRegionCode The radio region code. 658 * 659 * @retval OT_ERROR_NONE Successfully set region code. 660 * @retval OT_ERROR_FAILED Other platform specific errors. 661 * 662 */ 663 otError SetRadioRegion(uint16_t aRegionCode); 664 665 /** 666 * This method gets the radio region code. 667 * 668 * @param[out] aRegionCode The radio region code. 669 * 670 * @retval OT_ERROR_INVALID_ARGS @p aRegionCode is nullptr. 671 * @retval OT_ERROR_NONE Successfully got region code. 672 * @retval OT_ERROR_FAILED Other platform specific errors. 673 * 674 */ 675 otError GetRadioRegion(uint16_t *aRegionCode); 676 677 /** 678 * This method checks whether the spinel interface is radio-only. 679 * 680 * @param[out] aSupportsRcpApiVersion A reference to a boolean variable to update whether the list of spinel 681 * capabilities include `SPINEL_CAP_RCP_API_VERSION`. 682 * 683 * @retval TRUE The radio chip is in radio-only mode. 684 * @retval FALSE Otherwise. 685 * 686 */ 687 bool IsRcp(bool &aSupportsRcpApiVersion); 688 689 /** 690 * This method checks whether there is pending frame in the buffer. 691 * 692 * @returns Whether there is pending frame in the buffer. 693 * 694 */ HasPendingFrame(void) const695 bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); } 696 697 /** 698 * This method gets dataset from NCP radio and saves it. 699 * 700 * @retval OT_ERROR_NONE Successfully restore dataset. 701 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 702 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the radio. 703 * @retval OT_ERROR_NOT_FOUND Failed due to spinel property not supported in radio. 704 * @retval OT_ERROR_FAILED Failed due to other reasons. 705 */ 706 otError RestoreDatasetFromNcp(void); 707 708 /** 709 * This method returns the next timepoint to recalculate RCP time offset. 710 * 711 * @returns The timepoint to start the recalculation of RCP time offset. 712 * 713 */ GetNextRadioTimeRecalcStart(void) const714 uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; } 715 716 /** 717 * This method gets the current estimated time on RCP. 718 * 719 * @returns The current estimated RCP time in microseconds. 720 * 721 */ 722 uint64_t GetNow(void); 723 724 /** 725 * This method returns the bus speed between the host and the radio. 726 * 727 * @returns bus speed in bits/second. 728 * 729 */ 730 uint32_t GetBusSpeed(void) const; 731 732 /** 733 * This method sets the max transmit power. 734 * 735 * @param[in] aChannel The radio channel. 736 * @param[in] aPower The max transmit power in dBm. 737 * 738 * @retval OT_ERROR_NONE Successfully set the max transmit power. 739 * @retval OT_ERROR_INVALID_ARGS Channel is not in valid range. 740 * 741 */ 742 otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aPower); 743 744 private: 745 enum 746 { 747 kMaxSpinelFrame = SpinelInterface::kMaxFrameSize, 748 kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds. 749 kVersionStringSize = 128, ///< Max size of version string. 750 kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value. 751 kChannelMaskBufferSize = 32, ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value. 752 }; 753 754 enum State 755 { 756 kStateDisabled, ///< Radio is disabled. 757 kStateSleep, ///< Radio is sleep. 758 kStateReceive, ///< Radio is in receive mode. 759 kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio. 760 kStateTransmitDone, ///< Radio indicated frame transmission is done. 761 }; 762 763 typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); 764 765 static void HandleReceivedFrame(void *aContext); 766 767 otError CheckSpinelVersion(void); 768 otError CheckRadioCapabilities(void); 769 otError CheckRcpApiVersion(bool aSupportsRcpApiVersion); 770 771 /** 772 * This method triggers a state transfer of the state machine. 773 * 774 */ 775 void ProcessRadioStateMachine(void); 776 777 /** 778 * This method processes the frame queue. 779 * 780 */ 781 void ProcessFrameQueue(void); 782 783 /** 784 * This method tries to retrieve a spinel property from OpenThread transceiver. 785 * 786 * @param[in] aKey Spinel property key. 787 * @param[in] aFormat Spinel formatter to unpack property value. 788 * @param[out] ... Variable arguments list. 789 * 790 * @retval OT_ERROR_NONE Successfully got the property. 791 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 792 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 793 * 794 */ 795 otError Get(spinel_prop_key_t aKey, const char *aFormat, ...); 796 797 /** 798 * This method tries to retrieve a spinel property from OpenThread transceiver with parameter appended. 799 * 800 * @param[in] aKey Spinel property key. 801 * @param[in] aParam Parameter appended to spinel command. 802 * @param[in] aParamSize Size of parameter appended to spinel command 803 * @param[in] aFormat Spinel formatter to unpack property value. 804 * @param[out] ... Variable arguments list. 805 * 806 * @retval OT_ERROR_NONE Successfully got the property. 807 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 808 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 809 * 810 */ 811 otError GetWithParam(spinel_prop_key_t aKey, 812 const uint8_t * aParam, 813 spinel_size_t aParamSize, 814 const char * aFormat, 815 ...); 816 817 /** 818 * This method tries to update a spinel property of OpenThread transceiver. 819 * 820 * @param[in] aKey Spinel property key. 821 * @param[in] aFormat Spinel formatter to pack property value. 822 * @param[in] ... Variable arguments list. 823 * 824 * @retval OT_ERROR_NONE Successfully set the property. 825 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 826 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 827 * 828 */ 829 otError Set(spinel_prop_key_t aKey, const char *aFormat, ...); 830 831 /** 832 * This method tries to insert a item into a spinel list property of OpenThread transceiver. 833 * 834 * @param[in] aKey Spinel property key. 835 * @param[in] aFormat Spinel formatter to pack the item. 836 * @param[in] ... Variable arguments list. 837 * 838 * @retval OT_ERROR_NONE Successfully insert item into the property. 839 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 840 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 841 * 842 */ 843 otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...); 844 845 /** 846 * This method tries to remove a item from a spinel list property of OpenThread transceiver. 847 * 848 * @param[in] aKey Spinel property key. 849 * @param[in] aFormat Spinel formatter to pack the item. 850 * @param[in] ... Variable arguments list. 851 * 852 * @retval OT_ERROR_NONE Successfully removed item from the property. 853 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 854 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 855 * 856 */ 857 otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...); 858 859 spinel_tid_t GetNextTid(void); FreeTid(spinel_tid_t tid)860 void FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); } 861 862 otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs); 863 otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...); 864 otError RequestWithPropertyFormat(const char * aPropertyFormat, 865 uint32_t aCommand, 866 spinel_prop_key_t aKey, 867 const char * aFormat, 868 ...); 869 otError RequestWithPropertyFormatV(const char * aPropertyFormat, 870 uint32_t aCommand, 871 spinel_prop_key_t aKey, 872 const char * aFormat, 873 va_list aArgs); 874 otError RequestWithExpectedCommandV(uint32_t aExpectedCommand, 875 uint32_t aCommand, 876 spinel_prop_key_t aKey, 877 const char * aFormat, 878 va_list aArgs); 879 otError WaitResponse(void); 880 otError SendReset(void); 881 otError SendCommand(uint32_t command, 882 spinel_prop_key_t key, 883 spinel_tid_t tid, 884 const char * pack_format, 885 va_list args); 886 otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked); 887 otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength); 888 889 /** 890 * This method returns if the property changed event is safe to be handled now. 891 * 892 * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and 893 * `WaitResponse()`. 894 * 895 * @param[in] aKey The identifier of the property. 896 * 897 * @returns Whether this property is safe to be handled now. 898 * 899 */ IsSafeToHandleNow(spinel_prop_key_t aKey) const900 bool IsSafeToHandleNow(spinel_prop_key_t aKey) const 901 { 902 return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT); 903 } 904 905 void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer); 906 void HandleNotification(const uint8_t *aBuffer, uint16_t aLength); 907 void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 908 909 void HandleResponse(const uint8_t *aBuffer, uint16_t aLength); 910 void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 911 void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 912 913 void RadioReceive(void); 914 915 void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 916 917 void CalcRcpTimeOffset(void); 918 919 void HandleRcpUnexpectedReset(spinel_status_t aStatus); 920 void HandleRcpTimeout(void); 921 void RecoverFromRcpFailure(void); 922 923 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 924 void RestoreProperties(void); 925 #endif 926 927 otInstance *mInstance; 928 929 SpinelInterface::RxFrameBuffer mRxFrameBuffer; 930 931 InterfaceType mSpinelInterface; 932 933 uint16_t mCmdTidsInUse; ///< Used transaction ids. 934 spinel_tid_t mCmdNextTid; ///< Next available transaction id. 935 spinel_tid_t mTxRadioTid; ///< The transaction id used to send a radio frame. 936 spinel_tid_t mWaitingTid; ///< The transaction id of current transaction. 937 spinel_prop_key_t mWaitingKey; ///< The property key of current transaction. 938 const char * mPropertyFormat; ///< The spinel property format of current transaction. 939 va_list mPropertyArgs; ///< The arguments pack or unpack spinel property of current transaction. 940 uint32_t mExpectedCommand; ///< Expected response command of current transaction. 941 otError mError; ///< The result of current transaction. 942 943 uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 944 uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 945 uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE]; 946 otRadioFrame mRxRadioFrame; 947 otRadioFrame mTxRadioFrame; 948 otRadioFrame mAckRadioFrame; 949 otRadioFrame *mTransmitFrame; ///< Points to the frame to send 950 951 otExtAddress mExtendedAddress; 952 uint16_t mShortAddress; 953 uint16_t mPanId; 954 otRadioCaps mRadioCaps; 955 uint8_t mChannel; 956 int8_t mRxSensitivity; 957 otError mTxError; 958 char mVersion[kVersionStringSize]; 959 otExtAddress mIeeeEui64; 960 961 State mState; 962 bool mIsPromiscuous : 1; ///< Promiscuous mode. 963 bool mIsReady : 1; ///< NCP ready. 964 bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format. 965 bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP. 966 967 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 968 969 bool mResetRadioOnStartup : 1; ///< Whether should send reset command when init. 970 int16_t mRcpFailureCount; ///< Count of consecutive RCP failures. 971 972 // Properties set by core. 973 uint8_t mKeyIdMode; 974 uint8_t mKeyId; 975 otMacKey mPrevKey; 976 otMacKey mCurrKey; 977 otMacKey mNextKey; 978 uint16_t mSrcMatchShortEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 979 int16_t mSrcMatchShortEntryCount; 980 otExtAddress mSrcMatchExtEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 981 int16_t mSrcMatchExtEntryCount; 982 uint8_t mScanChannel; 983 uint16_t mScanDuration; 984 int8_t mCcaEnergyDetectThreshold; 985 int8_t mTransmitPower; 986 int8_t mFemLnaGain; 987 bool mCoexEnabled : 1; 988 989 bool mMacKeySet : 1; ///< Whether MAC key has been set. 990 bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set. 991 bool mTransmitPowerSet : 1; ///< Whether transmit power has been set. 992 bool mCoexEnabledSet : 1; ///< Whether coex enabled has been set. 993 bool mFemLnaGainSet : 1; ///< Whether FEM LNA gain has been set. 994 bool mRcpFailed : 1; ///< RCP failure happened, should recover and retry operation. 995 bool mEnergyScanning : 1; ///< If fails while scanning, restarts scanning. 996 997 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 998 999 #if OPENTHREAD_CONFIG_DIAG_ENABLE 1000 bool mDiagMode; 1001 char * mDiagOutput; 1002 size_t mDiagOutputMaxLen; 1003 #endif 1004 1005 uint64_t mTxRadioEndUs; 1006 uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset. 1007 int64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time. 1008 1009 MaxPowerTable mMaxPowerTable; 1010 }; 1011 1012 } // namespace Spinel 1013 } // namespace ot 1014 1015 #include "radio_spinel_impl.hpp" 1016 1017 #endif // RADIO_SPINEL_HPP_ 1018