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