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 "radio_spinel_metrics.h" 41 #include "spinel.h" 42 #include "spinel_interface.hpp" 43 #include "core/radio/max_power_table.hpp" 44 #include "ncp/ncp_config.h" 45 46 namespace ot { 47 namespace Spinel { 48 49 /** 50 * The class for providing a OpenThread radio interface by talking with a radio-only 51 * co-processor(RCP). The InterfaceType template parameter should provide the following 52 * methods: 53 * 54 * class InterfaceType { 55 * 56 * // This constructor initializes the object. 57 * 58 * // @param[in] aCallback Callback on frame received 59 * // @param[in] aCallbackContext Callback context 60 * // @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. 61 * 62 * InterfaceType(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, 63 * void * aCallbackContext, 64 * Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); 65 * 66 * 67 * // This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. 68 * 69 * // This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for 70 * // up to `kMaxWaitTime` interval. 71 * 72 * // @param[in] aFrame A pointer to buffer containing the spinel frame to send. 73 * // @param[in] aLength The length (number of bytes) in the frame. 74 * 75 * // @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame. 76 * // @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame. 77 * // @retval OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`. 78 * 79 * otError SendFrame(const uint8_t *aFrame, uint16_t aLength); 80 * 81 * 82 * // This method waits for receiving part or all of spinel frame within specified interval. 83 * 84 * // @param[in] aTimeout The timeout value in microseconds. 85 * 86 * // @retval OT_ERROR_NONE Part or all of spinel frame is received. 87 * // @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. 88 * 89 * otError WaitForFrame(uint64_t& aTimeoutUs); 90 * 91 * 92 * // This method performs radio driver processing. 93 * 94 * // @param[in] aContext The context containing fd_sets. 95 * // The type is specified by the user in template parameters. 96 * 97 * void Process(const ProcessContextType &aContext); 98 * 99 * 100 * // This method deinitializes the interface to the RCP. 101 * 102 * void Deinit(void); 103 * }; 104 */ 105 template <typename InterfaceType, typename ProcessContextType> class RadioSpinel 106 { 107 public: 108 /** 109 * This constructor initializes the spinel based OpenThread transceiver. 110 * 111 */ 112 RadioSpinel(void); 113 114 /** 115 * Initialize this radio transceiver. 116 * 117 * @param[in] aResetRadio TRUE to reset on init, FALSE to not reset on init. 118 * @param[in] aRestoreDatasetFromNcp TRUE to restore dataset to host from non-volatile memory 119 * (only used when attempts to upgrade from NCP to RCP mode), 120 * FALSE otherwise. 121 * @param[in] aSkipRcpCompatibilityCheck TRUE to skip RCP compatibility check, FALSE to perform the check. 122 * 123 */ 124 void Init(bool aResetRadio, bool aRestoreDataSetFromNcp, bool aSkipRcpCompatibilityCheck); 125 126 /** 127 * Deinitialize this radio transceiver. 128 * 129 */ 130 void Deinit(void); 131 132 /** 133 * This method gets the status of promiscuous mode. 134 * 135 * @retval true Promiscuous mode is enabled. 136 * @retval false Promiscuous mode is disabled. 137 * 138 */ IsPromiscuous(void) const139 bool IsPromiscuous(void) const { return mIsPromiscuous; } 140 141 /** 142 * This method sets the status of promiscuous mode. 143 * 144 * @param[in] aEnable Whether to enable or disable promiscuous mode. 145 * 146 * @retval OT_ERROR_NONE Succeeded. 147 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 148 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 149 * 150 */ 151 otError SetPromiscuous(bool aEnable); 152 153 /** 154 * This method sets the Short Address for address filtering. 155 * 156 * @param[in] aShortAddress The IEEE 802.15.4 Short Address. 157 * 158 * @retval OT_ERROR_NONE Succeeded. 159 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 160 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 161 * 162 */ 163 otError SetShortAddress(uint16_t aAddress); 164 165 /** 166 * This method gets the factory-assigned IEEE EUI-64 for this transceiver. 167 * 168 * @param[in] aInstance The OpenThread instance structure. 169 * @param[out] aIeeeEui64 A pointer to the factory-assigned IEEE EUI-64. 170 * 171 * @retval OT_ERROR_NONE Succeeded. 172 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 173 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 174 * 175 */ 176 otError GetIeeeEui64(uint8_t *aIeeeEui64); 177 178 /** 179 * This method sets the Extended Address for address filtering. 180 * 181 * @param[in] aExtAddress A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order. 182 * 183 * @retval OT_ERROR_NONE Succeeded. 184 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 185 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 186 * 187 */ 188 otError SetExtendedAddress(const otExtAddress &aAddress); 189 190 /** 191 * This method sets the PAN ID for address filtering. 192 * 193 * @param[in] aPanId The IEEE 802.15.4 PAN ID. 194 * 195 * @retval OT_ERROR_NONE Succeeded. 196 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 197 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 198 * 199 */ 200 otError SetPanId(uint16_t aPanId); 201 202 /** 203 * This method gets the radio's transmit power in dBm. 204 * 205 * @param[out] aPower The transmit power in dBm. 206 * 207 * @retval OT_ERROR_NONE Succeeded. 208 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 209 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 210 * 211 */ 212 otError GetTransmitPower(int8_t &aPower); 213 214 /** 215 * This method sets the radio's transmit power in dBm. 216 * 217 * @param[in] aPower The transmit power in dBm. 218 * 219 * @retval OT_ERROR_NONE Succeeded. 220 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 221 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 222 * 223 */ 224 otError SetTransmitPower(int8_t aPower); 225 226 /** 227 * This method gets the radio's CCA ED threshold in dBm. 228 * 229 * @param[out] aThreshold The CCA ED threshold in dBm. 230 * 231 * @retval OT_ERROR_NONE Succeeded. 232 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 233 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 234 * 235 */ 236 otError GetCcaEnergyDetectThreshold(int8_t &aThreshold); 237 238 /** 239 * This method sets the radio's CCA ED threshold in dBm. 240 * 241 * @param[in] aThreshold The CCA ED threshold in dBm. 242 * 243 * @retval OT_ERROR_NONE Succeeded. 244 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 245 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 246 * 247 */ 248 otError SetCcaEnergyDetectThreshold(int8_t aThreshold); 249 250 /** 251 * This method gets the FEM's Rx LNA gain in dBm. 252 * 253 * @param[out] aGain The FEM's Rx LNA gain in dBm. 254 * 255 * @retval OT_ERROR_NONE Succeeded. 256 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 257 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 258 * 259 */ 260 otError GetFemLnaGain(int8_t &aGain); 261 262 /** 263 * This method sets the FEM's Rx LNA gain in dBm. 264 * 265 * @param[in] aGain The FEM's Rx LNA gain in dBm. 266 * 267 * @retval OT_ERROR_NONE Succeeded. 268 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 269 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 270 * 271 */ 272 otError SetFemLnaGain(int8_t aGain); 273 274 /** 275 * This method returns the radio sw version string. 276 * 277 * @returns A pointer to the radio version string. 278 * 279 */ GetVersion(void) const280 const char *GetVersion(void) const { return mVersion; } 281 282 /** 283 * This method returns the radio capabilities. 284 * 285 * @returns The radio capability bit vector. 286 * 287 */ GetRadioCaps(void) const288 otRadioCaps GetRadioCaps(void) const { return mRadioCaps; } 289 290 /** 291 * This method gets the most recent RSSI measurement. 292 * 293 * @returns The RSSI in dBm when it is valid. 127 when RSSI is invalid. 294 */ 295 int8_t GetRssi(void); 296 297 /** 298 * This method returns the radio receive sensitivity value. 299 * 300 * @returns The radio receive sensitivity value in dBm. 301 * 302 * @retval OT_ERROR_NONE Succeeded. 303 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 304 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 305 * 306 */ GetReceiveSensitivity(void) const307 int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; } 308 309 /** 310 * This method gets current state of the radio. 311 * 312 * @return Current state of the radio. 313 * 314 */ 315 otRadioState GetState(void) const; 316 317 /** 318 * This method gets the current receiving channel. 319 * 320 * @returns Current receiving channel. 321 * 322 */ GetChannel(void) const323 uint8_t GetChannel(void) const { return mChannel; } 324 325 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 326 /** 327 * Enable the radio coex. 328 * 329 * @param[in] aInstance The OpenThread instance structure. 330 * @param[in] aEnabled TRUE to enable the radio coex, FALSE otherwise. 331 * 332 * @retval OT_ERROR_NONE Successfully enabled. 333 * @retval OT_ERROR_FAILED The radio coex could not be enabled. 334 * 335 */ 336 otError SetCoexEnabled(bool aEnabled); 337 338 /** 339 * Check whether radio coex is enabled or not. 340 * 341 * @param[in] aInstance The OpenThread instance structure. 342 * 343 * @returns TRUE if the radio coex is enabled, FALSE otherwise. 344 * 345 */ 346 bool IsCoexEnabled(void); 347 348 /** 349 * This method retrieves the radio coexistence metrics. 350 * 351 * @param[out] aCoexMetrics A reference to the coexistence metrics structure. 352 * 353 * @retval OT_ERROR_NONE Successfully retrieved the coex metrics. 354 * @retval OT_ERROR_INVALID_ARGS @p aCoexMetrics was nullptr. 355 * 356 */ 357 otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics); 358 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 359 360 /** 361 * This method returns a reference to the transmit buffer. 362 * 363 * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission. 364 * 365 * @returns A reference to the transmit buffer. 366 * 367 */ GetTransmitFrame(void)368 otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; } 369 370 /** 371 * This method enables or disables source address match feature. 372 * 373 * @param[in] aEnable Enable/disable source address match feature. 374 * 375 * @retval OT_ERROR_NONE Succeeded. 376 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 377 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 378 * 379 */ 380 otError EnableSrcMatch(bool aEnable); 381 382 /** 383 * This method adds a short address to the source address match table. 384 * 385 * @param[in] aInstance The OpenThread instance structure. 386 * @param[in] aShortAddress The short address to be added. 387 * 388 * @retval OT_ERROR_NONE Successfully added short address to the source match table. 389 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 390 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 391 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 392 */ 393 otError AddSrcMatchShortEntry(uint16_t aShortAddress); 394 395 /** 396 * This method removes a short address from the source address match table. 397 * 398 * @param[in] aInstance The OpenThread instance structure. 399 * @param[in] aShortAddress The short address to be removed. 400 * 401 * @retval OT_ERROR_NONE Successfully removed short address from the source match table. 402 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 403 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 404 * @retval OT_ERROR_NO_ADDRESS The short address is not in source address match table. 405 */ 406 otError ClearSrcMatchShortEntry(uint16_t aShortAddress); 407 408 /** 409 * Clear all short addresses from the source address match table. 410 * 411 * @param[in] aInstance The OpenThread instance structure. 412 * 413 * @retval OT_ERROR_NONE Succeeded. 414 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 415 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 416 * 417 */ 418 otError ClearSrcMatchShortEntries(void); 419 420 /** 421 * Add an extended address to the source address match table. 422 * 423 * @param[in] aInstance The OpenThread instance structure. 424 * @param[in] aExtAddress The extended address to be added stored in little-endian byte order. 425 * 426 * @retval OT_ERROR_NONE Successfully added extended address to the source match table. 427 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 428 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 429 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 430 */ 431 otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress); 432 433 /** 434 * Remove an extended address from the source address match table. 435 * 436 * @param[in] aInstance The OpenThread instance structure. 437 * @param[in] aExtAddress The extended address to be removed stored in little-endian byte order. 438 * 439 * @retval OT_ERROR_NONE Successfully removed the extended address from the source match table. 440 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 441 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 442 * @retval OT_ERROR_NO_ADDRESS The extended address is not in source address match table. 443 */ 444 otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress); 445 446 /** 447 * Clear all the extended/long addresses from source address match table. 448 * 449 * @param[in] aInstance The OpenThread instance structure. 450 * 451 * @retval OT_ERROR_NONE Succeeded. 452 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 453 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 454 * 455 */ 456 otError ClearSrcMatchExtEntries(void); 457 458 /** 459 * This method begins the energy scan sequence on the radio. 460 * 461 * @param[in] aScanChannel The channel to perform the energy scan on. 462 * @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned. 463 * 464 * @retval OT_ERROR_NONE Succeeded. 465 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 466 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 467 * 468 */ 469 otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration); 470 471 /** 472 * This method switches the radio state from Receive to Transmit. 473 * 474 * @param[in] aFrame A reference to the transmitted frame. 475 * 476 * @retval OT_ERROR_NONE Successfully transitioned to Transmit. 477 * @retval OT_ERROR_BUSY Failed due to another transmission is on going. 478 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 479 * @retval OT_ERROR_INVALID_STATE The radio was not in the Receive state. 480 */ 481 otError Transmit(otRadioFrame &aFrame); 482 483 /** 484 * This method switches the radio state from Sleep to Receive. 485 * 486 * @param[in] aChannel The channel to use for receiving. 487 * 488 * @retval OT_ERROR_NONE Successfully transitioned to Receive. 489 * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting. 490 * 491 */ 492 otError Receive(uint8_t aChannel); 493 494 /** 495 * This method switches the radio state from Receive to Sleep. 496 * 497 * @retval OT_ERROR_NONE Successfully transitioned to Sleep. 498 * @retval OT_ERROR_BUSY The radio was transmitting 499 * @retval OT_ERROR_INVALID_STATE The radio was disabled 500 * 501 */ 502 otError Sleep(void); 503 504 /** 505 * Enable the radio. 506 * 507 * @param[in] aInstance A pointer to the OpenThread instance. 508 * 509 * @retval OT_ERROR_NONE Successfully enabled. 510 * @retval OT_ERROR_FAILED The radio could not be enabled. 511 * 512 */ 513 otError Enable(otInstance *aInstance); 514 515 /** 516 * Disable the radio. 517 * 518 * @retval OT_ERROR_NONE Successfully transitioned to Disabled. 519 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 520 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 521 * 522 */ 523 otError Disable(void); 524 525 /** 526 * This method checks whether radio is enabled or not. 527 * 528 * @returns TRUE if the radio is enabled, FALSE otherwise. 529 * 530 */ IsEnabled(void) const531 bool IsEnabled(void) const { return mState != kStateDisabled; } 532 533 /** 534 * This method indicates whether there is a pending transmission. 535 * 536 * @retval TRUE There is a pending transmission. 537 * @retval FALSE There is no pending transmission. 538 * 539 */ IsTransmitting(void) const540 bool IsTransmitting(void) const { return mState == kStateTransmitting; } 541 542 /** 543 * This method indicates whether a transmit has just finished. 544 * 545 * @retval TRUE The transmission is done. 546 * @retval FALSE The transmission is not done. 547 * 548 */ IsTransmitDone(void) const549 bool IsTransmitDone(void) const { return mState == kStateTransmitDone; } 550 551 /** 552 * This method returns the timeout timepoint for the pending transmission. 553 * 554 * @returns The timeout timepoint for the pending transmission. 555 * 556 */ GetTxRadioEndUs(void) const557 uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; } 558 559 /** 560 * This method processes any pending the I/O data. 561 * 562 * @param[in] aContext The process context. 563 * 564 */ 565 void Process(const ProcessContextType &aContext); 566 567 /** 568 * This method returns the underlying spinel interface. 569 * 570 * @returns The underlying spinel interface. 571 * 572 */ GetSpinelInterface(void)573 InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; } 574 575 #if OPENTHREAD_CONFIG_DIAG_ENABLE 576 /** 577 * This method enables/disables the factory diagnostics mode. 578 * 579 * @param[in] aMode TRUE to enable diagnostics mode, FALSE otherwise. 580 * 581 */ SetDiagEnabled(bool aMode)582 void SetDiagEnabled(bool aMode) { mDiagMode = aMode; } 583 584 /** 585 * This method indicates whether or not factory diagnostics mode is enabled. 586 * 587 * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise. 588 * 589 */ IsDiagEnabled(void) const590 bool IsDiagEnabled(void) const { return mDiagMode; } 591 592 /** 593 * This method processes platform diagnostics commands. 594 * 595 * @param[in] aString A null-terminated input string. 596 * @param[out] aOutput The diagnostics execution result. 597 * @param[in] aOutputMaxLen The output buffer size. 598 * 599 * @retval OT_ERROR_NONE Succeeded. 600 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 601 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 602 * 603 */ 604 otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); 605 #endif 606 607 /** 608 * This method returns the radio channel mask. 609 * 610 * @param[in] aPreferred TRUE to get preferred channel mask, FALSE to get supported channel mask. 611 * 612 * @returns The radio channel mask according to @aPreferred: 613 * The radio supported channel mask that the device is allowed to be on. 614 * The radio preferred channel mask that the device prefers to form on. 615 * 616 */ 617 uint32_t GetRadioChannelMask(bool aPreferred); 618 619 /** 620 * This method processes a received Spinel frame. 621 * 622 * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`. 623 * 624 */ 625 void HandleReceivedFrame(void); 626 627 /** 628 * This method sets MAC key and key index to RCP. 629 * 630 * @param[in] aKeyIdMode The key ID mode. 631 * @param[in] aKeyId The key index. 632 * @param[in] aPrevKey Pointer to previous MAC key. 633 * @param[in] aCurrKey Pointer to current MAC key. 634 * @param[in] aNextKey Pointer to next MAC key. 635 * 636 * @retval OT_ERROR_NONE Succeeded. 637 * @retval OT_ERROR_INVALID_ARGS One of the keys passed is invalid.. 638 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 639 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 640 * 641 */ 642 otError SetMacKey(uint8_t aKeyIdMode, 643 uint8_t aKeyId, 644 const otMacKeyMaterial *aPrevKey, 645 const otMacKeyMaterial *aCurrKey, 646 const otMacKeyMaterial *aNextKey); 647 648 /** 649 * This method sets the current MAC Frame Counter value. 650 * 651 * @param[in] aMacFrameCounter The MAC Frame Counter value. 652 * @param[in] aSetIfLarger If `true`, set only if the new value is larger than the current value. 653 * If `false`, set the new value independent of the current value. 654 * 655 */ 656 otError SetMacFrameCounter(uint32_t aMacFrameCounter, bool aSetIfLarger); 657 658 /** 659 * This method sets the radio region code. 660 * 661 * @param[in] aRegionCode The radio region code. 662 * 663 * @retval OT_ERROR_NONE Successfully set region code. 664 * @retval OT_ERROR_FAILED Other platform specific errors. 665 * 666 */ 667 otError SetRadioRegion(uint16_t aRegionCode); 668 669 /** 670 * This method gets the radio region code. 671 * 672 * @param[out] aRegionCode The radio region code. 673 * 674 * @retval OT_ERROR_INVALID_ARGS @p aRegionCode is nullptr. 675 * @retval OT_ERROR_NONE Successfully got region code. 676 * @retval OT_ERROR_FAILED Other platform specific errors. 677 * 678 */ 679 otError GetRadioRegion(uint16_t *aRegionCode); 680 681 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 682 /** 683 * Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator. 684 * 685 * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that 686 * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop 687 * to collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that 688 * Probing Initiator. 689 * 690 * @param[in] aLinkMetrics This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2 691 * metrics can be specified. The probing would be disabled if @p aLinkMetrics is 692 * bitwise 0. 693 * @param[in] aShortAddress The short address of the Probing Initiator. 694 * @param[in] aExtAddress The extended source address of the Probing Initiator. @p aExtAddress MUST NOT be 695 * nullptr. 696 * 697 * @retval OT_ERROR_NONE Successfully configured the Enhanced-ACK Based Probing. 698 * @retval OT_ERROR_INVALID_ARGS @p aExtAddress is nullptr. 699 * @retval OT_ERROR_NOT_FOUND The Initiator indicated by @p aShortAddress is not found when trying to clear. 700 * @retval OT_ERROR_NO_BUFS No more Initiator can be supported. 701 */ 702 otError ConfigureEnhAckProbing(otLinkMetrics aLinkMetrics, 703 const otShortAddress aShortAddress, 704 const otExtAddress &aExtAddress); 705 #endif 706 707 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 708 /** 709 * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations. 710 * 711 * @note Platforms may optimize this value based on operational conditions (i.e.: temperature). 712 * 713 * @retval The current CSL rx/tx scheduling drift, in units of ± ppm. 714 * 715 */ 716 uint8_t GetCslAccuracy(void); 717 #endif 718 719 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 720 /** 721 * Get the current uncertainty, in units of 10 us, of the clock used for scheduling CSL operations. 722 * 723 * @retval The current CSL Clock Uncertainty in units of 10 us. 724 * 725 */ 726 uint8_t GetCslUncertainty(void); 727 #endif 728 729 /** 730 * This method checks whether the spinel interface is radio-only. 731 * 732 * @param[out] aSupportsRcpApiVersion A reference to a boolean variable to update whether the list of 733 * spinel capabilities includes `SPINEL_CAP_RCP_API_VERSION`. 734 * @param[out] aSupportsRcpMinHostApiVersion A reference to a boolean variable to update whether the list of 735 * spinel capabilities includes `SPINEL_CAP_RCP_MIN_HOST_API_VERSION`. 736 * 737 * @retval TRUE The radio chip is in radio-only mode. 738 * @retval FALSE Otherwise. 739 * 740 */ 741 bool IsRcp(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion); 742 743 /** 744 * This method checks whether there is pending frame in the buffer. 745 * 746 * @returns Whether there is pending frame in the buffer. 747 * 748 */ HasPendingFrame(void) const749 bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); } 750 751 /** 752 * This method gets dataset from NCP radio and saves it. 753 * 754 * @retval OT_ERROR_NONE Successfully restore dataset. 755 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 756 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the radio. 757 * @retval OT_ERROR_NOT_FOUND Failed due to spinel property not supported in radio. 758 * @retval OT_ERROR_FAILED Failed due to other reasons. 759 */ 760 otError RestoreDatasetFromNcp(void); 761 762 /** 763 * This method returns the next timepoint to recalculate RCP time offset. 764 * 765 * @returns The timepoint to start the recalculation of RCP time offset. 766 * 767 */ GetNextRadioTimeRecalcStart(void) const768 uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; } 769 770 /** 771 * This method gets the current estimated time on RCP. 772 * 773 * @returns The current estimated RCP time in microseconds. 774 * 775 */ 776 uint64_t GetNow(void); 777 778 /** 779 * This method returns the bus speed between the host and the radio. 780 * 781 * @returns bus speed in bits/second. 782 * 783 */ 784 uint32_t GetBusSpeed(void) const; 785 786 /** 787 * This method sets the max transmit power. 788 * 789 * @param[in] aChannel The radio channel. 790 * @param[in] aPower The max transmit power in dBm. 791 * 792 * @retval OT_ERROR_NONE Successfully set the max transmit power. 793 * @retval OT_ERROR_INVALID_ARGS Channel is not in valid range. 794 * 795 */ 796 otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aPower); 797 798 /** 799 * This method tries to retrieve a spinel property from OpenThread transceiver. 800 * 801 * @param[in] aKey Spinel property key. 802 * @param[in] aFormat Spinel formatter to unpack property value. 803 * @param[out] ... Variable arguments list. 804 * 805 * @retval OT_ERROR_NONE Successfully got the property. 806 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 807 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 808 * 809 */ 810 otError Get(spinel_prop_key_t aKey, const char *aFormat, ...); 811 812 /** 813 * This method tries to retrieve a spinel property from OpenThread transceiver with parameter appended. 814 * 815 * @param[in] aKey Spinel property key. 816 * @param[in] aParam Parameter appended to spinel command. 817 * @param[in] aParamSize Size of parameter appended to spinel command 818 * @param[in] aFormat Spinel formatter to unpack property value. 819 * @param[out] ... Variable arguments list. 820 * 821 * @retval OT_ERROR_NONE Successfully got the property. 822 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 823 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 824 * 825 */ 826 otError GetWithParam(spinel_prop_key_t aKey, 827 const uint8_t *aParam, 828 spinel_size_t aParamSize, 829 const char *aFormat, 830 ...); 831 832 /** 833 * This method tries to update a spinel property of OpenThread transceiver. 834 * 835 * @param[in] aKey Spinel property key. 836 * @param[in] aFormat Spinel formatter to pack property value. 837 * @param[in] ... Variable arguments list. 838 * 839 * @retval OT_ERROR_NONE Successfully set the property. 840 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 841 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 842 * 843 */ 844 otError Set(spinel_prop_key_t aKey, const char *aFormat, ...); 845 846 /** 847 * This method tries to insert a item into a spinel list property of OpenThread transceiver. 848 * 849 * @param[in] aKey Spinel property key. 850 * @param[in] aFormat Spinel formatter to pack the item. 851 * @param[in] ... Variable arguments list. 852 * 853 * @retval OT_ERROR_NONE Successfully insert item into the property. 854 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 855 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 856 * 857 */ 858 otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...); 859 860 /** 861 * This method tries to remove a item from a spinel list property of OpenThread transceiver. 862 * 863 * @param[in] aKey Spinel property key. 864 * @param[in] aFormat Spinel formatter to pack the item. 865 * @param[in] ... Variable arguments list. 866 * 867 * @retval OT_ERROR_NONE Successfully removed item from the property. 868 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 869 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 870 * 871 */ 872 otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...); 873 874 /** 875 * This method tries to reset the co-processor. 876 * 877 * @prarm[in] aResetType The reset type, SPINEL_RESET_PLATFORM or SPINEL_RESET_STACK. 878 * 879 * @retval OT_ERROR_NONE Successfully removed item from the property. 880 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 881 * 882 */ 883 otError SendReset(uint8_t aResetType); 884 885 /** 886 * This method returns the radio Spinel metrics. 887 * 888 * @returns The radio Spinel metrics. 889 * 890 */ GetRadioSpinelMetrics(void) const891 const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; } 892 893 #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 894 /** 895 * Add a calibrated power of the specified channel to the power calibration table. 896 * 897 * @param[in] aChannel The radio channel. 898 * @param[in] aActualPower The actual power in 0.01dBm. 899 * @param[in] aRawPowerSetting A pointer to the raw power setting byte array. 900 * @param[in] aRawPowerSettingLength The length of the @p aRawPowerSetting. 901 * 902 * @retval OT_ERROR_NONE Successfully added the calibrated power to the power calibration table. 903 * @retval OT_ERROR_NO_BUFS No available entry in the power calibration table. 904 * @retval OT_ERROR_INVALID_ARGS The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid. 905 * @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented. 906 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 907 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 908 * 909 */ 910 otError AddCalibratedPower(uint8_t aChannel, 911 int16_t aActualPower, 912 const uint8_t *aRawPowerSetting, 913 uint16_t aRawPowerSettingLength); 914 915 /** 916 * Clear all calibrated powers from the power calibration table. 917 * 918 * @retval OT_ERROR_NONE Successfully cleared all calibrated powers from the power calibration table. 919 * @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented. 920 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 921 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 922 * 923 */ 924 otError ClearCalibratedPowers(void); 925 926 /** 927 * Set the target power for the given channel. 928 * 929 * @param[in] aChannel The radio channel. 930 * @param[in] aTargetPower The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel. 931 * 932 * @retval OT_ERROR_NONE Successfully set the target power. 933 * @retval OT_ERROR_INVALID_ARGS The @p aChannel or @p aTargetPower is invalid.. 934 * @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented. 935 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 936 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 937 * 938 */ 939 otError SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower); 940 #endif 941 942 private: 943 enum 944 { 945 kMaxSpinelFrame = SPINEL_FRAME_MAX_SIZE, 946 kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds. 947 kVersionStringSize = 128, ///< Max size of version string. 948 kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value. 949 kChannelMaskBufferSize = 32, ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value. 950 }; 951 952 enum State 953 { 954 kStateDisabled, ///< Radio is disabled. 955 kStateSleep, ///< Radio is sleep. 956 kStateReceive, ///< Radio is in receive mode. 957 kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio. 958 kStateTransmitDone, ///< Radio indicated frame transmission is done. 959 }; 960 961 typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); 962 963 static void HandleReceivedFrame(void *aContext); 964 965 void ResetRcp(bool aResetRadio); 966 otError CheckSpinelVersion(void); 967 otError CheckRadioCapabilities(void); 968 otError CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsMinHostRcpApiVersion); 969 970 /** 971 * This method triggers a state transfer of the state machine. 972 * 973 */ 974 void ProcessRadioStateMachine(void); 975 976 /** 977 * This method processes the frame queue. 978 * 979 */ 980 void ProcessFrameQueue(void); 981 982 spinel_tid_t GetNextTid(void); FreeTid(spinel_tid_t tid)983 void FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); } 984 985 otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs); 986 otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...); 987 otError RequestWithPropertyFormat(const char *aPropertyFormat, 988 uint32_t aCommand, 989 spinel_prop_key_t aKey, 990 const char *aFormat, 991 ...); 992 otError RequestWithPropertyFormatV(const char *aPropertyFormat, 993 uint32_t aCommand, 994 spinel_prop_key_t aKey, 995 const char *aFormat, 996 va_list aArgs); 997 otError RequestWithExpectedCommandV(uint32_t aExpectedCommand, 998 uint32_t aCommand, 999 spinel_prop_key_t aKey, 1000 const char *aFormat, 1001 va_list aArgs); 1002 otError WaitResponse(bool aHandleRcpTimeout = true); 1003 otError SendCommand(uint32_t aCommand, 1004 spinel_prop_key_t aKey, 1005 spinel_tid_t aTid, 1006 const char *aFormat, 1007 va_list aArgs); 1008 otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked); 1009 otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength); 1010 1011 /** 1012 * This method returns if the property changed event is safe to be handled now. 1013 * 1014 * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and 1015 * `WaitResponse()`. 1016 * 1017 * @param[in] aKey The identifier of the property. 1018 * 1019 * @returns Whether this property is safe to be handled now. 1020 * 1021 */ IsSafeToHandleNow(spinel_prop_key_t aKey) const1022 bool IsSafeToHandleNow(spinel_prop_key_t aKey) const 1023 { 1024 return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT); 1025 } 1026 1027 void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer); 1028 void HandleNotification(const uint8_t *aBuffer, uint16_t aLength); 1029 void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1030 1031 void HandleResponse(const uint8_t *aBuffer, uint16_t aLength); 1032 void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1033 void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1034 1035 void RadioReceive(void); 1036 1037 void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 1038 1039 void CalcRcpTimeOffset(void); 1040 1041 void HandleRcpUnexpectedReset(spinel_status_t aStatus); 1042 void HandleRcpTimeout(void); 1043 void RecoverFromRcpFailure(void); 1044 1045 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1046 void RestoreProperties(void); 1047 #endif UpdateParseErrorCount(otError aError)1048 void UpdateParseErrorCount(otError aError) 1049 { 1050 mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0; 1051 } 1052 1053 uint32_t Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...); 1054 void LogSpinelFrame(const uint8_t *aFrame, uint16_t aLength, bool aTx); 1055 1056 otInstance *mInstance; 1057 1058 SpinelInterface::RxFrameBuffer mRxFrameBuffer; 1059 1060 InterfaceType mSpinelInterface; 1061 1062 uint16_t mCmdTidsInUse; ///< Used transaction ids. 1063 spinel_tid_t mCmdNextTid; ///< Next available transaction id. 1064 spinel_tid_t mTxRadioTid; ///< The transaction id used to send a radio frame. 1065 spinel_tid_t mWaitingTid; ///< The transaction id of current transaction. 1066 spinel_prop_key_t mWaitingKey; ///< The property key of current transaction. 1067 const char *mPropertyFormat; ///< The spinel property format of current transaction. 1068 va_list mPropertyArgs; ///< The arguments pack or unpack spinel property of current transaction. 1069 uint32_t mExpectedCommand; ///< Expected response command of current transaction. 1070 otError mError; ///< The result of current transaction. 1071 1072 uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1073 uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1074 uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1075 otRadioFrame mRxRadioFrame; 1076 otRadioFrame mTxRadioFrame; 1077 otRadioFrame mAckRadioFrame; 1078 otRadioFrame *mTransmitFrame; ///< Points to the frame to send 1079 1080 otExtAddress mExtendedAddress; 1081 uint16_t mShortAddress; 1082 uint16_t mPanId; 1083 otRadioCaps mRadioCaps; 1084 uint8_t mChannel; 1085 int8_t mRxSensitivity; 1086 otError mTxError; 1087 char mVersion[kVersionStringSize]; 1088 otExtAddress mIeeeEui64; 1089 1090 State mState; 1091 bool mIsPromiscuous : 1; ///< Promiscuous mode. 1092 bool mIsReady : 1; ///< NCP ready. 1093 bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format. 1094 bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP. 1095 1096 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1097 1098 bool mResetRadioOnStartup : 1; ///< Whether should send reset command when init. 1099 int16_t mRcpFailureCount; ///< Count of consecutive RCP failures. 1100 1101 // Properties set by core. 1102 uint8_t mKeyIdMode; 1103 uint8_t mKeyId; 1104 otMacKey mPrevKey; 1105 otMacKey mCurrKey; 1106 otMacKey mNextKey; 1107 uint16_t mSrcMatchShortEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 1108 int16_t mSrcMatchShortEntryCount; 1109 otExtAddress mSrcMatchExtEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 1110 int16_t mSrcMatchExtEntryCount; 1111 uint8_t mScanChannel; 1112 uint16_t mScanDuration; 1113 int8_t mCcaEnergyDetectThreshold; 1114 int8_t mTransmitPower; 1115 int8_t mFemLnaGain; 1116 bool mCoexEnabled : 1; 1117 1118 bool mMacKeySet : 1; ///< Whether MAC key has been set. 1119 bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set. 1120 bool mTransmitPowerSet : 1; ///< Whether transmit power has been set. 1121 bool mCoexEnabledSet : 1; ///< Whether coex enabled has been set. 1122 bool mFemLnaGainSet : 1; ///< Whether FEM LNA gain has been set. 1123 bool mRcpFailed : 1; ///< RCP failure happened, should recover and retry operation. 1124 bool mEnergyScanning : 1; ///< If fails while scanning, restarts scanning. 1125 1126 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1127 1128 #if OPENTHREAD_CONFIG_DIAG_ENABLE 1129 bool mDiagMode; 1130 char *mDiagOutput; 1131 size_t mDiagOutputMaxLen; 1132 #endif 1133 1134 uint64_t mTxRadioEndUs; 1135 uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset. 1136 uint64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time. 1137 1138 MaxPowerTable mMaxPowerTable; 1139 1140 otRadioSpinelMetrics mRadioSpinelMetrics; 1141 }; 1142 1143 } // namespace Spinel 1144 } // namespace ot 1145 1146 #include "radio_spinel_impl.hpp" 1147 1148 #endif // RADIO_SPINEL_HPP_ 1149