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 "core/radio/max_power_table.hpp" 41 #include "lib/spinel/radio_spinel_metrics.h" 42 #include "lib/spinel/spinel.h" 43 #include "lib/spinel/spinel_interface.hpp" 44 #include "ncp/ncp_config.h" 45 46 namespace ot { 47 namespace Spinel { 48 49 /** 50 * Maximum number of Spinel Interface IDs. 51 * 52 */ 53 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE 54 static constexpr uint8_t kSpinelHeaderMaxNumIid = 4; 55 #else 56 static constexpr uint8_t kSpinelHeaderMaxNumIid = 1; 57 #endif 58 59 struct RadioSpinelCallbacks 60 { 61 /** 62 * This callback notifies user of `RadioSpinel` of a received frame. 63 * 64 * @param[in] aInstance The OpenThread instance structure. 65 * @param[in] aFrame A pointer to the received frame or nullptr if the receive operation failed. 66 * @param[in] aError kErrorNone when successfully received a frame, 67 * kErrorAbort when reception was aborted and a frame was not received, 68 * kErrorNoBufs when a frame could not be received due to lack of rx buffer space. 69 * 70 */ 71 void (*mReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError); 72 73 /** 74 * The callback notifies user of `RadioSpinel` that the transmit operation has completed, providing, if 75 * applicable, the received ACK frame. 76 * 77 * @param[in] aInstance The OpenThread instance structure. 78 * @param[in] aFrame The transmitted frame. 79 * @param[in] aAckFrame A pointer to the ACK frame, nullptr if no ACK was received. 80 * @param[in] aError kErrorNone when the frame was transmitted, 81 * kErrorNoAck when the frame was transmitted but no ACK was received, 82 * kErrorChannelAccessFailure tx failed due to activity on the channel, 83 * kErrorAbort when transmission was aborted for other reasons. 84 * 85 */ 86 void (*mTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, Error aError); 87 88 /** 89 * This callback notifies user of `RadioSpinel` that energy scan is complete. 90 * 91 * @param[in] aInstance The OpenThread instance structure. 92 * @param[in] aMaxRssi Maximum RSSI seen on the channel, or `SubMac::kInvalidRssiValue` if failed. 93 * 94 */ 95 void (*mEnergyScanDone)(otInstance *aInstance, int8_t aMaxRssi); 96 97 /** 98 * This callback notifies user of `RadioSpinel` that the transmission has started. 99 * 100 * @param[in] aInstance A pointer to the OpenThread instance structure. 101 * @param[in] aFrame A pointer to the frame that is being transmitted. 102 * 103 */ 104 void (*mTxStarted)(otInstance *aInstance, otRadioFrame *aFrame); 105 106 /** 107 * This callback notifies user of `RadioSpinel` that the radio interface switchover has completed. 108 * 109 * @param[in] aInstance A pointer to the OpenThread instance structure. 110 * @param[in] aSuccess A value indicating if the switchover was successful or not. 111 * 112 */ 113 void (*mSwitchoverDone)(otInstance *aInstance, bool aSuccess); 114 115 #if OPENTHREAD_CONFIG_DIAG_ENABLE 116 /** 117 * This callback notifies diagnostics module using `RadioSpinel` of a received frame. 118 * 119 * This callback is used when diagnostics is enabled. 120 * 121 * @param[in] aInstance The OpenThread instance structure. 122 * @param[in] aFrame A pointer to the received frame or NULL if the receive operation failed. 123 * @param[in] aError OT_ERROR_NONE when successfully received a frame, 124 * OT_ERROR_ABORT when reception was aborted and a frame was not received, 125 * OT_ERROR_NO_BUFS when a frame could not be received due to lack of rx buffer space. 126 * 127 */ 128 void (*mDiagReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError); 129 130 /** 131 * This callback notifies diagnostics module using `RadioSpinel` that the transmission has completed. 132 * 133 * This callback is used when diagnostics is enabled. 134 * 135 * @param[in] aInstance The OpenThread instance structure. 136 * @param[in] aFrame A pointer to the frame that was transmitted. 137 * @param[in] aError OT_ERROR_NONE when the frame was transmitted, 138 * OT_ERROR_CHANNEL_ACCESS_FAILURE tx could not take place due to activity on the 139 * channel, OT_ERROR_ABORT when transmission was aborted for other reasons. 140 * 141 */ 142 void (*mDiagTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError); 143 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE 144 }; 145 146 /** 147 * The class for providing a OpenThread radio interface by talking with a radio-only 148 * co-processor(RCP). 149 * 150 */ 151 class RadioSpinel 152 { 153 public: 154 /** 155 * Initializes the spinel based OpenThread transceiver. 156 * 157 */ 158 RadioSpinel(void); 159 160 /** 161 * Deinitializes the spinel based OpenThread transceiver. 162 * 163 */ ~RadioSpinel(void)164 ~RadioSpinel(void) { Deinit(); } 165 166 /** 167 * Initialize this radio transceiver. 168 * 169 * @param[in] aSpinelInterface A reference to the Spinel interface. 170 * @param[in] aResetRadio TRUE to reset on init, FALSE to not reset on init. 171 * @param[in] aSkipRcpCompatibilityCheck TRUE to skip RCP compatibility check, FALSE to perform the check. 172 * @param[in] aIidList A Pointer to the list of IIDs to receive spinel frame from. 173 * First entry must be the IID of the Host Application. 174 * @param[in] aIidListLength The Length of the @p aIidList. 175 * 176 */ 177 void Init(SpinelInterface &aSpinelInterface, 178 bool aResetRadio, 179 bool aSkipRcpCompatibilityCheck, 180 const spinel_iid_t *aIidList, 181 uint8_t aIidListLength); 182 183 /** 184 * This method sets the notification callbacks. 185 * 186 * @param[in] aCallbacks A pointer to structure with notification callbacks. 187 * 188 */ 189 void SetCallbacks(const struct RadioSpinelCallbacks &aCallbacks); 190 191 /** 192 * Deinitialize this radio transceiver. 193 * 194 */ 195 void Deinit(void); 196 197 /** 198 * Gets the status of promiscuous mode. 199 * 200 * @retval true Promiscuous mode is enabled. 201 * @retval false Promiscuous mode is disabled. 202 * 203 */ IsPromiscuous(void) const204 bool IsPromiscuous(void) const { return mIsPromiscuous; } 205 206 /** 207 * Sets the status of promiscuous mode. 208 * 209 * @param[in] aEnable Whether to enable or disable promiscuous mode. 210 * 211 * @retval OT_ERROR_NONE Succeeded. 212 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 213 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 214 * 215 */ 216 otError SetPromiscuous(bool aEnable); 217 218 /** 219 * Sets the status of RxOnWhenIdle mode. 220 * 221 * @param[in] aEnable Whether to enable or disable RxOnWhenIdle mode. 222 * 223 * @retval OT_ERROR_NONE Succeeded. 224 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 225 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 226 * 227 */ 228 otError SetRxOnWhenIdle(bool aEnable); 229 230 /** 231 * Sets the Short Address for address filtering. 232 * 233 * @param[in] aShortAddress The IEEE 802.15.4 Short Address. 234 * 235 * @retval OT_ERROR_NONE Succeeded. 236 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 237 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 238 * 239 */ 240 otError SetShortAddress(uint16_t aAddress); 241 242 /** 243 * Gets the factory-assigned IEEE EUI-64 for this transceiver. 244 * 245 * @param[in] aInstance The OpenThread instance structure. 246 * @param[out] aIeeeEui64 A pointer to the factory-assigned IEEE EUI-64. 247 * 248 * @retval OT_ERROR_NONE Succeeded. 249 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 250 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 251 * 252 */ 253 otError GetIeeeEui64(uint8_t *aIeeeEui64); 254 255 /** 256 * Sets the Extended Address for address filtering. 257 * 258 * @param[in] aExtAddress A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order. 259 * 260 * @retval OT_ERROR_NONE Succeeded. 261 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 262 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 263 * 264 */ 265 otError SetExtendedAddress(const otExtAddress &aExtAddress); 266 267 /** 268 * Sets the PAN ID for address filtering. 269 * 270 * @param[in] aPanId The IEEE 802.15.4 PAN ID. 271 * 272 * @retval OT_ERROR_NONE Succeeded. 273 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 274 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 275 * 276 */ 277 otError SetPanId(uint16_t aPanId); 278 279 /** 280 * Gets the radio's transmit power in dBm. 281 * 282 * @param[out] aPower The transmit power in dBm. 283 * 284 * @retval OT_ERROR_NONE Succeeded. 285 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 286 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 287 * 288 */ 289 otError GetTransmitPower(int8_t &aPower); 290 291 /** 292 * Sets the radio's transmit power in dBm. 293 * 294 * @param[in] aPower The transmit power in dBm. 295 * 296 * @retval OT_ERROR_NONE Succeeded. 297 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 298 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 299 * 300 */ 301 otError SetTransmitPower(int8_t aPower); 302 303 /** 304 * Gets the radio's CCA ED threshold in dBm. 305 * 306 * @param[out] aThreshold The CCA ED threshold in dBm. 307 * 308 * @retval OT_ERROR_NONE Succeeded. 309 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 310 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 311 * 312 */ 313 otError GetCcaEnergyDetectThreshold(int8_t &aThreshold); 314 315 /** 316 * Sets the radio's CCA ED threshold in dBm. 317 * 318 * @param[in] aThreshold The CCA ED threshold in dBm. 319 * 320 * @retval OT_ERROR_NONE Succeeded. 321 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 322 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 323 * 324 */ 325 otError SetCcaEnergyDetectThreshold(int8_t aThreshold); 326 327 /** 328 * Gets the FEM's Rx LNA gain in dBm. 329 * 330 * @param[out] aGain The FEM's Rx LNA gain in dBm. 331 * 332 * @retval OT_ERROR_NONE Succeeded. 333 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 334 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 335 * 336 */ 337 otError GetFemLnaGain(int8_t &aGain); 338 339 /** 340 * Sets the FEM's Rx LNA gain in dBm. 341 * 342 * @param[in] aGain The FEM's Rx LNA gain in dBm. 343 * 344 * @retval OT_ERROR_NONE Succeeded. 345 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 346 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 347 * 348 */ 349 otError SetFemLnaGain(int8_t aGain); 350 351 /** 352 * Returns the radio sw version string. 353 * 354 * @returns A pointer to the radio version string. 355 * 356 */ GetVersion(void) const357 const char *GetVersion(void) const { return sVersion; } 358 359 /** 360 * Returns the radio capabilities. 361 * 362 * @returns The radio capability bit vector. 363 * 364 */ GetRadioCaps(void) const365 otRadioCaps GetRadioCaps(void) const { return sRadioCaps; } 366 367 /** 368 * Gets the most recent RSSI measurement. 369 * 370 * @returns The RSSI in dBm when it is valid. 127 when RSSI is invalid. 371 */ 372 int8_t GetRssi(void); 373 374 /** 375 * Returns the radio receive sensitivity value. 376 * 377 * @returns The radio receive sensitivity value in dBm. 378 * 379 * @retval OT_ERROR_NONE Succeeded. 380 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 381 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 382 * 383 */ GetReceiveSensitivity(void) const384 int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; } 385 386 /** 387 * Gets current state of the radio. 388 * 389 * @return Current state of the radio. 390 * 391 */ 392 otRadioState GetState(void) const; 393 394 /** 395 * Gets the current receiving channel. 396 * 397 * @returns Current receiving channel. 398 * 399 */ GetChannel(void) const400 uint8_t GetChannel(void) const { return mChannel; } 401 402 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 403 /** 404 * Enable the radio coex. 405 * 406 * @param[in] aInstance The OpenThread instance structure. 407 * @param[in] aEnabled TRUE to enable the radio coex, FALSE otherwise. 408 * 409 * @retval OT_ERROR_NONE Successfully enabled. 410 * @retval OT_ERROR_FAILED The radio coex could not be enabled. 411 * 412 */ 413 otError SetCoexEnabled(bool aEnabled); 414 415 /** 416 * Check whether radio coex is enabled or not. 417 * 418 * @param[in] aInstance The OpenThread instance structure. 419 * 420 * @returns TRUE if the radio coex is enabled, FALSE otherwise. 421 * 422 */ 423 bool IsCoexEnabled(void); 424 425 /** 426 * Retrieves the radio coexistence metrics. 427 * 428 * @param[out] aCoexMetrics A reference to the coexistence metrics structure. 429 * 430 * @retval OT_ERROR_NONE Successfully retrieved the coex metrics. 431 * @retval OT_ERROR_INVALID_ARGS @p aCoexMetrics was nullptr. 432 * 433 */ 434 otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics); 435 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 436 437 /** 438 * Get currently active interface. 439 * 440 * @param[out] aIid IID of the interface that owns the radio. 441 * 442 * @retval OT_ERROR_NONE Successfully got the property. 443 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 444 * @retval OT_ERROR_NOT_IMPLEMENTED Failed due to lack of the support in radio 445 * @retval OT_ERROR_INVALID_COMMAND Platform supports all interfaces simultaneously. 446 * (i.e. no active/inactive interface concept in the platform level) 447 * 448 */ 449 otError GetMultipanActiveInterface(spinel_iid_t *aIid); 450 451 /** 452 * Sets specified radio interface active 453 * 454 * This function allows selecting currently active radio interface on platforms that do not support parallel 455 * communication on multiple interfaces. I.e. if more than one interface is in receive state calling 456 * SetMultipanActiveInterface guarantees that specified interface will not be losing frames. This function 457 * returns if the request was received properly. After interface switching is complete SwitchoverDone callback is 458 * Invoked. Switching interfaces may take longer if aCompletePending is set true. 459 * 460 * @param[in] aIid IID of the interface to set active. 461 * @param[in] aCompletePending Set true if pending radio operation should complete first(Soft switch) or false if 462 * ongoing operations should be interrupted (Force switch). 463 * 464 * @retval OT_ERROR_NONE Successfully requested interface switch. 465 * @retval OT_ERROR_BUSY Failed due to another operation on going. 466 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 467 * @retval OT_ERROR_NOT_IMPLEMENTED Failed due to lack of support in radio for the given interface id or 468 * @retval OT_ERROR_INVALID_COMMAND Platform supports all interfaces simultaneously 469 * (i.e. no active/inactive interface concept in the platform level) 470 * @retval OT_ERROR_ALREADY Given interface is already active. 471 * 472 */ 473 otError SetMultipanActiveInterface(spinel_iid_t aIid, bool aCompletePending); 474 475 /** 476 * Returns a reference to the transmit buffer. 477 * 478 * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission. 479 * 480 * @returns A reference to the transmit buffer. 481 * 482 */ GetTransmitFrame(void)483 otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; } 484 485 /** 486 * Enables or disables source address match feature. 487 * 488 * @param[in] aEnable Enable/disable source address match feature. 489 * 490 * @retval OT_ERROR_NONE Succeeded. 491 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 492 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 493 * 494 */ 495 otError EnableSrcMatch(bool aEnable); 496 497 /** 498 * Adds a short address to the source address match table. 499 * 500 * @param[in] aInstance The OpenThread instance structure. 501 * @param[in] aShortAddress The short address to be added. 502 * 503 * @retval OT_ERROR_NONE Successfully added short address to the source match table. 504 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 505 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 506 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 507 */ 508 otError AddSrcMatchShortEntry(uint16_t aShortAddress); 509 510 /** 511 * Removes a short address from the source address match table. 512 * 513 * @param[in] aInstance The OpenThread instance structure. 514 * @param[in] aShortAddress The short address to be removed. 515 * 516 * @retval OT_ERROR_NONE Successfully removed short address from the source match table. 517 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 518 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 519 * @retval OT_ERROR_NO_ADDRESS The short address is not in source address match table. 520 */ 521 otError ClearSrcMatchShortEntry(uint16_t aShortAddress); 522 523 /** 524 * Clear all short addresses from the source address match table. 525 * 526 * @param[in] aInstance The OpenThread instance structure. 527 * 528 * @retval OT_ERROR_NONE Succeeded. 529 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 530 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 531 * 532 */ 533 otError ClearSrcMatchShortEntries(void); 534 535 /** 536 * Add an extended address to the source address match table. 537 * 538 * @param[in] aInstance The OpenThread instance structure. 539 * @param[in] aExtAddress The extended address to be added stored in little-endian byte order. 540 * 541 * @retval OT_ERROR_NONE Successfully added extended address to the source match table. 542 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 543 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 544 * @retval OT_ERROR_NO_BUFS No available entry in the source match table. 545 */ 546 otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress); 547 548 /** 549 * Remove an extended address from the source address match table. 550 * 551 * @param[in] aInstance The OpenThread instance structure. 552 * @param[in] aExtAddress The extended address to be removed stored in little-endian byte order. 553 * 554 * @retval OT_ERROR_NONE Successfully removed the extended address from the source match table. 555 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 556 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 557 * @retval OT_ERROR_NO_ADDRESS The extended address is not in source address match table. 558 */ 559 otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress); 560 561 /** 562 * Clear all the extended/long addresses from source address match table. 563 * 564 * @param[in] aInstance The OpenThread instance structure. 565 * 566 * @retval OT_ERROR_NONE Succeeded. 567 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 568 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 569 * 570 */ 571 otError ClearSrcMatchExtEntries(void); 572 573 /** 574 * Begins the energy scan sequence on the radio. 575 * 576 * @param[in] aScanChannel The channel to perform the energy scan on. 577 * @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned. 578 * 579 * @retval OT_ERROR_NONE Succeeded. 580 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 581 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 582 * 583 */ 584 otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration); 585 586 /** 587 * Switches the radio state from Receive to Transmit. 588 * 589 * @param[in] aFrame A reference to the transmitted frame. 590 * 591 * @retval OT_ERROR_NONE Successfully transitioned to Transmit. 592 * @retval OT_ERROR_BUSY Failed due to another transmission is on going. 593 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 594 * @retval OT_ERROR_INVALID_STATE The radio was not in the Receive state. 595 */ 596 otError Transmit(otRadioFrame &aFrame); 597 598 /** 599 * Switches the radio state from Sleep to Receive. 600 * 601 * @param[in] aChannel The channel to use for receiving. 602 * 603 * @retval OT_ERROR_NONE Successfully transitioned to Receive. 604 * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting. 605 * 606 */ 607 otError Receive(uint8_t aChannel); 608 609 /** 610 * Switches the radio state from Receive to Sleep. 611 * 612 * @retval OT_ERROR_NONE Successfully transitioned to Sleep. 613 * @retval OT_ERROR_BUSY The radio was transmitting 614 * @retval OT_ERROR_INVALID_STATE The radio was disabled 615 * 616 */ 617 otError Sleep(void); 618 619 /** 620 * Enable the radio. 621 * 622 * @param[in] aInstance A pointer to the OpenThread instance. 623 * 624 * @retval OT_ERROR_NONE Successfully enabled. 625 * @retval OT_ERROR_FAILED The radio could not be enabled. 626 * 627 */ 628 otError Enable(otInstance *aInstance); 629 630 /** 631 * Disable the radio. 632 * 633 * @retval OT_ERROR_NONE Successfully transitioned to Disabled. 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 Disable(void); 639 640 /** 641 * Checks whether radio is enabled or not. 642 * 643 * @returns TRUE if the radio is enabled, FALSE otherwise. 644 * 645 */ IsEnabled(void) const646 bool IsEnabled(void) const { return mState != kStateDisabled; } 647 648 /** 649 * Indicates whether there is a pending transmission. 650 * 651 * @retval TRUE There is a pending transmission. 652 * @retval FALSE There is no pending transmission. 653 * 654 */ IsTransmitting(void) const655 bool IsTransmitting(void) const { return mState == kStateTransmitting; } 656 657 /** 658 * Indicates whether a transmit has just finished. 659 * 660 * @retval TRUE The transmission is done. 661 * @retval FALSE The transmission is not done. 662 * 663 */ IsTransmitDone(void) const664 bool IsTransmitDone(void) const { return mState == kStateTransmitDone; } 665 666 /** 667 * Returns the timeout timepoint for the pending transmission. 668 * 669 * @returns The timeout timepoint for the pending transmission. 670 * 671 */ GetTxRadioEndUs(void) const672 uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; } 673 674 /** 675 * Processes any pending the I/O data. 676 * 677 * @param[in] aContext The process context. 678 * 679 */ 680 void Process(const void *aContext); 681 682 #if OPENTHREAD_CONFIG_DIAG_ENABLE 683 /** 684 * Enables/disables the factory diagnostics mode. 685 * 686 * @param[in] aMode TRUE to enable diagnostics mode, FALSE otherwise. 687 * 688 */ SetDiagEnabled(bool aMode)689 void SetDiagEnabled(bool aMode) { mDiagMode = aMode; } 690 691 /** 692 * Indicates whether or not factory diagnostics mode is enabled. 693 * 694 * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise. 695 * 696 */ IsDiagEnabled(void) const697 bool IsDiagEnabled(void) const { return mDiagMode; } 698 699 /** 700 * Processes platform diagnostics commands. 701 * 702 * @param[in] aString A null-terminated input string. 703 * @param[out] aOutput The diagnostics execution result. 704 * @param[in] aOutputMaxLen The output buffer size. 705 * 706 * @retval OT_ERROR_NONE Succeeded. 707 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 708 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 709 * 710 */ 711 otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); 712 #endif 713 714 /** 715 * Returns the radio channel mask. 716 * 717 * @param[in] aPreferred TRUE to get preferred channel mask, FALSE to get supported channel mask. 718 * 719 * @returns The radio channel mask according to @aPreferred: 720 * The radio supported channel mask that the device is allowed to be on. 721 * The radio preferred channel mask that the device prefers to form on. 722 * 723 */ 724 uint32_t GetRadioChannelMask(bool aPreferred); 725 726 /** 727 * Processes a received Spinel frame. 728 * 729 * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`. 730 * 731 */ 732 void HandleReceivedFrame(void); 733 734 /** 735 * Sets MAC key and key index to RCP. 736 * 737 * @param[in] aKeyIdMode The key ID mode. 738 * @param[in] aKeyId The key index. 739 * @param[in] aPrevKey Pointer to previous MAC key. 740 * @param[in] aCurrKey Pointer to current MAC key. 741 * @param[in] aNextKey Pointer to next MAC key. 742 * 743 * @retval OT_ERROR_NONE Succeeded. 744 * @retval OT_ERROR_INVALID_ARGS One of the keys passed is invalid.. 745 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 746 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 747 * 748 */ 749 otError SetMacKey(uint8_t aKeyIdMode, 750 uint8_t aKeyId, 751 const otMacKeyMaterial *aPrevKey, 752 const otMacKeyMaterial *aCurrKey, 753 const otMacKeyMaterial *aNextKey); 754 755 /** 756 * Sets the current MAC Frame Counter value. 757 * 758 * @param[in] aMacFrameCounter The MAC Frame Counter value. 759 * @param[in] aSetIfLarger If `true`, set only if the new value is larger than the current value. 760 * If `false`, set the new value independent of the current value. 761 * 762 */ 763 otError SetMacFrameCounter(uint32_t aMacFrameCounter, bool aSetIfLarger); 764 765 /** 766 * Sets the radio region code. 767 * 768 * @param[in] aRegionCode The radio region code. 769 * 770 * @retval OT_ERROR_NONE Successfully set region code. 771 * @retval OT_ERROR_FAILED Other platform specific errors. 772 * 773 */ 774 otError SetRadioRegion(uint16_t aRegionCode); 775 776 /** 777 * Gets the radio region code. 778 * 779 * @param[out] aRegionCode The radio region code. 780 * 781 * @retval OT_ERROR_INVALID_ARGS @p aRegionCode is nullptr. 782 * @retval OT_ERROR_NONE Successfully got region code. 783 * @retval OT_ERROR_FAILED Other platform specific errors. 784 * 785 */ 786 otError GetRadioRegion(uint16_t *aRegionCode); 787 788 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 789 /** 790 * Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator. 791 * 792 * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that 793 * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop 794 * to collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that 795 * Probing Initiator. 796 * 797 * @param[in] aLinkMetrics This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2 798 * metrics can be specified. The probing would be disabled if @p aLinkMetrics is 799 * bitwise 0. 800 * @param[in] aShortAddress The short address of the Probing Initiator. 801 * @param[in] aExtAddress The extended source address of the Probing Initiator. @p aExtAddress MUST NOT be 802 * nullptr. 803 * 804 * @retval OT_ERROR_NONE Successfully configured the Enhanced-ACK Based Probing. 805 * @retval OT_ERROR_INVALID_ARGS @p aExtAddress is nullptr. 806 * @retval OT_ERROR_NOT_FOUND The Initiator indicated by @p aShortAddress is not found when trying to clear. 807 * @retval OT_ERROR_NO_BUFS No more Initiator can be supported. 808 */ 809 otError ConfigureEnhAckProbing(otLinkMetrics aLinkMetrics, 810 const otShortAddress &aShortAddress, 811 const otExtAddress &aExtAddress); 812 #endif 813 814 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 815 /** 816 * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations. 817 * 818 * @note Platforms may optimize this value based on operational conditions (i.e.: temperature). 819 * 820 * @retval The current CSL rx/tx scheduling drift, in units of ± ppm. 821 * 822 */ 823 uint8_t GetCslAccuracy(void); 824 #endif 825 826 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 827 /** 828 * Get the current uncertainty, in units of 10 us, of the clock used for scheduling CSL operations. 829 * 830 * @retval The current CSL Clock Uncertainty in units of 10 us. 831 * 832 */ 833 uint8_t GetCslUncertainty(void); 834 #endif 835 836 /** 837 * Checks whether the spinel interface is radio-only. 838 * 839 * @param[out] aSupportsRcpApiVersion A reference to a boolean variable to update whether the list of 840 * spinel capabilities includes `SPINEL_CAP_RCP_API_VERSION`. 841 * @param[out] aSupportsRcpMinHostApiVersion A reference to a boolean variable to update whether the list of 842 * spinel capabilities includes `SPINEL_CAP_RCP_MIN_HOST_API_VERSION`. 843 * 844 * @retval TRUE The radio chip is in radio-only mode. 845 * @retval FALSE Otherwise. 846 * 847 */ 848 bool IsRcp(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion); 849 850 /** 851 * Checks whether there is pending frame in the buffer. 852 * 853 * @returns Whether there is pending frame in the buffer. 854 * 855 */ HasPendingFrame(void) const856 bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); } 857 858 /** 859 * Returns the next timepoint to recalculate RCP time offset. 860 * 861 * @returns The timepoint to start the recalculation of RCP time offset. 862 * 863 */ GetNextRadioTimeRecalcStart(void) const864 uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; } 865 866 /** 867 * Gets the current estimated time on RCP. 868 * 869 * @returns The current estimated RCP time in microseconds. 870 * 871 */ 872 uint64_t GetNow(void); 873 874 /** 875 * Returns the bus speed between the host and the radio. 876 * 877 * @returns bus speed in bits/second. 878 * 879 */ 880 uint32_t GetBusSpeed(void) const; 881 882 /** 883 * Sets the max transmit power. 884 * 885 * @param[in] aChannel The radio channel. 886 * @param[in] aMaxPower The max transmit power in dBm. 887 * 888 * @retval OT_ERROR_NONE Successfully set the max transmit power. 889 * @retval OT_ERROR_INVALID_ARGS Channel is not in valid range. 890 * 891 */ 892 otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aMaxPower); 893 894 /** 895 * Tries to retrieve a spinel property from OpenThread transceiver. 896 * 897 * @param[in] aKey Spinel property key. 898 * @param[in] aFormat Spinel formatter to unpack property value. 899 * @param[out] ... Variable arguments list. 900 * 901 * @retval OT_ERROR_NONE Successfully got the property. 902 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 903 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 904 * 905 */ 906 otError Get(spinel_prop_key_t aKey, const char *aFormat, ...); 907 908 /** 909 * Tries to retrieve a spinel property from OpenThread transceiver with parameter appended. 910 * 911 * @param[in] aKey Spinel property key. 912 * @param[in] aParam Parameter appended to spinel command. 913 * @param[in] aParamSize Size of parameter appended to spinel command 914 * @param[in] aFormat Spinel formatter to unpack property value. 915 * @param[out] ... Variable arguments list. 916 * 917 * @retval OT_ERROR_NONE Successfully got the property. 918 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 919 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 920 * 921 */ 922 otError GetWithParam(spinel_prop_key_t aKey, 923 const uint8_t *aParam, 924 spinel_size_t aParamSize, 925 const char *aFormat, 926 ...); 927 928 /** 929 * Tries to update a spinel property of OpenThread transceiver. 930 * 931 * @param[in] aKey Spinel property key. 932 * @param[in] aFormat Spinel formatter to pack property value. 933 * @param[in] ... Variable arguments list. 934 * 935 * @retval OT_ERROR_NONE Successfully set the property. 936 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 937 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 938 * 939 */ 940 otError Set(spinel_prop_key_t aKey, const char *aFormat, ...); 941 942 /** 943 * Tries to insert a item into a spinel list property of OpenThread transceiver. 944 * 945 * @param[in] aKey Spinel property key. 946 * @param[in] aFormat Spinel formatter to pack the item. 947 * @param[in] ... Variable arguments list. 948 * 949 * @retval OT_ERROR_NONE Successfully insert item into the property. 950 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 951 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 952 * 953 */ 954 otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...); 955 956 /** 957 * Tries to remove a item from a spinel list property of OpenThread transceiver. 958 * 959 * @param[in] aKey Spinel property key. 960 * @param[in] aFormat Spinel formatter to pack the item. 961 * @param[in] ... Variable arguments list. 962 * 963 * @retval OT_ERROR_NONE Successfully removed item from the property. 964 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 965 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 966 * 967 */ 968 otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...); 969 970 /** 971 * Tries to reset the co-processor. 972 * 973 * @prarm[in] aResetType The reset type, SPINEL_RESET_PLATFORM, SPINEL_RESET_STACK, or SPINEL_RESET_BOOTLOADER. 974 * 975 * @retval OT_ERROR_NONE Successfully removed item from the property. 976 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 977 * @retval OT_ERROR_NOT_CAPABLE Requested reset type is not supported by the co-processor 978 * 979 */ 980 otError SendReset(uint8_t aResetType); 981 982 /** 983 * Returns the radio Spinel metrics. 984 * 985 * @returns The radio Spinel metrics. 986 * 987 */ GetRadioSpinelMetrics(void) const988 const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; } 989 990 #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 991 /** 992 * Add a calibrated power of the specified channel to the power calibration table. 993 * 994 * @param[in] aChannel The radio channel. 995 * @param[in] aActualPower The actual power in 0.01dBm. 996 * @param[in] aRawPowerSetting A pointer to the raw power setting byte array. 997 * @param[in] aRawPowerSettingLength The length of the @p aRawPowerSetting. 998 * 999 * @retval OT_ERROR_NONE Successfully added the calibrated power to the power calibration table. 1000 * @retval OT_ERROR_NO_BUFS No available entry in the power calibration table. 1001 * @retval OT_ERROR_INVALID_ARGS The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid. 1002 * @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented. 1003 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 1004 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 1005 * 1006 */ 1007 otError AddCalibratedPower(uint8_t aChannel, 1008 int16_t aActualPower, 1009 const uint8_t *aRawPowerSetting, 1010 uint16_t aRawPowerSettingLength); 1011 1012 /** 1013 * Clear all calibrated powers from the power calibration table. 1014 * 1015 * @retval OT_ERROR_NONE Successfully cleared all calibrated powers from the power calibration table. 1016 * @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented. 1017 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 1018 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 1019 * 1020 */ 1021 otError ClearCalibratedPowers(void); 1022 1023 /** 1024 * Set the target power for the given channel. 1025 * 1026 * @param[in] aChannel The radio channel. 1027 * @param[in] aTargetPower The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel. 1028 * 1029 * @retval OT_ERROR_NONE Successfully set the target power. 1030 * @retval OT_ERROR_INVALID_ARGS The @p aChannel or @p aTargetPower is invalid.. 1031 * @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented. 1032 * @retval OT_ERROR_BUSY Failed due to another operation is on going. 1033 * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. 1034 * 1035 */ 1036 otError SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower); 1037 #endif 1038 1039 /** 1040 * Convert the Spinel status code to OpenThread error code. 1041 * 1042 * @param[in] aStatus The Spinel status code. 1043 * 1044 * @retval OT_ERROR_NONE The operation has completed successfully. 1045 * @retval OT_ERROR_DROP The packet was dropped. 1046 * @retval OT_ERROR_NO_BUFS The operation has been prevented due to memory pressure. 1047 * @retval OT_ERROR_BUSY The device is currently performing a mutuallyexclusive operation. 1048 * @retval OT_ERROR_PARSE An error has occurred while parsing the command. 1049 * @retval OT_ERROR_INVALID_ARGS An argument to the given operation is invalid. 1050 * @retval OT_ERROR_NOT_IMPLEMENTED The given operation has not been implemented. 1051 * @retval OT_ERROR_INVALID_STATE The given operation is invalid for the current state of the device. 1052 * @retval OT_ERROR_NO_ACK The packet was not acknowledged. 1053 * @retval OT_ERROR_NOT_FOUND The given property is not recognized. 1054 * @retval OT_ERROR_FAILED The given operation has failed for some undefined reason. 1055 * @retval OT_ERROR_CHANNEL_ACCESS_FAILURE The packet was not sent due to a CCA failure. 1056 * @retval OT_ERROR_ALREADY The operation is already in progress or the property was already set 1057 * to the given value. 1058 */ 1059 static otError SpinelStatusToOtError(spinel_status_t aStatus); 1060 1061 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1062 /** 1063 * Restore the properties of Radio Co-processor (RCP). 1064 * 1065 */ 1066 void RestoreProperties(void); 1067 #endif 1068 #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 1069 /** 1070 * Defines a vendor "set property handler" hook to process vendor spinel properties. 1071 * 1072 * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the 1073 * given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it 1074 * should first decode the value from the input spinel frame and then perform the corresponding set operation. The 1075 * handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The 1076 * `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the 1077 * input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call 1078 * the `VendorGetPropertyHandler()` for the same property key to prepare the response. 1079 * 1080 * @param[in] aPropKey The spinel property key. 1081 * 1082 * @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing 1083 * of the input or the "set" operation. 1084 * 1085 */ 1086 otError VendorHandleValueIs(spinel_prop_key_t aPropKey); 1087 #endif 1088 1089 private: 1090 enum 1091 { 1092 kMaxSpinelFrame = SPINEL_FRAME_MAX_SIZE, 1093 kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds. 1094 kVersionStringSize = 128, ///< Max size of version string. 1095 kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value. 1096 kChannelMaskBufferSize = 32, ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value. 1097 }; 1098 1099 enum State 1100 { 1101 kStateDisabled, ///< Radio is disabled. 1102 kStateSleep, ///< Radio is sleep. 1103 kStateReceive, ///< Radio is in receive mode. 1104 kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio. 1105 kStateTransmitDone, ///< Radio indicated frame transmission is done. 1106 }; 1107 1108 static constexpr uint32_t kUsPerMs = 1000; ///< Microseconds per millisecond. 1109 static constexpr uint32_t kMsPerSec = 1000; ///< Milliseconds per second. 1110 static constexpr uint32_t kUsPerSec = kUsPerMs * kMsPerSec; ///< Microseconds per second. 1111 static constexpr uint64_t kTxWaitUs = 1112 OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS * 1113 kUsPerSec; ///< Maximum time of waiting for `TransmitDone` event, in microseconds. 1114 1115 typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); 1116 1117 static void HandleReceivedFrame(void *aContext); 1118 1119 void ResetRcp(bool aResetRadio); 1120 otError CheckSpinelVersion(void); 1121 otError CheckRadioCapabilities(void); 1122 otError CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsRcpMinHostApiVersion); 1123 1124 /** 1125 * Triggers a state transfer of the state machine. 1126 * 1127 */ 1128 void ProcessRadioStateMachine(void); 1129 1130 /** 1131 * Processes the frame queue. 1132 * 1133 */ 1134 void ProcessFrameQueue(void); 1135 1136 spinel_tid_t GetNextTid(void); FreeTid(spinel_tid_t tid)1137 void FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); } 1138 1139 otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs); 1140 otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...); 1141 otError RequestWithPropertyFormat(const char *aPropertyFormat, 1142 uint32_t aCommand, 1143 spinel_prop_key_t aKey, 1144 const char *aFormat, 1145 ...); 1146 otError RequestWithPropertyFormatV(const char *aPropertyFormat, 1147 uint32_t aCommand, 1148 spinel_prop_key_t aKey, 1149 const char *aFormat, 1150 va_list aArgs); 1151 otError RequestWithExpectedCommandV(uint32_t aExpectedCommand, 1152 uint32_t aCommand, 1153 spinel_prop_key_t aKey, 1154 const char *aFormat, 1155 va_list aArgs); 1156 otError WaitResponse(bool aHandleRcpTimeout = true); 1157 otError SendCommand(uint32_t aCommand, 1158 spinel_prop_key_t aKey, 1159 spinel_tid_t aTid, 1160 const char *aFormat, 1161 va_list aArgs); 1162 otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked); 1163 1164 /** 1165 * Returns if the property changed event is safe to be handled now. 1166 * 1167 * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and 1168 * `WaitResponse()`. 1169 * 1170 * @param[in] aKey The identifier of the property. 1171 * 1172 * @returns Whether this property is safe to be handled now. 1173 * 1174 */ IsSafeToHandleNow(spinel_prop_key_t aKey) const1175 bool IsSafeToHandleNow(spinel_prop_key_t aKey) const 1176 { 1177 return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT); 1178 } 1179 1180 /** 1181 * Checks whether given interface ID is part of list of IIDs to be allowed. 1182 * 1183 * @param[in] aIid Spinel Interface ID. 1184 * 1185 * @retval TRUE Given IID present in allow list. 1186 * @retval FALSE Otherwise. 1187 * 1188 */ 1189 inline bool IsFrameForUs(spinel_iid_t aIid); 1190 1191 void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer); 1192 void HandleNotification(const uint8_t *aFrame, uint16_t aLength); 1193 void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1194 1195 void HandleResponse(const uint8_t *aBuffer, uint16_t aLength); 1196 void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1197 void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); 1198 1199 void RadioReceive(void); 1200 1201 void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 1202 1203 void CalcRcpTimeOffset(void); 1204 1205 void HandleRcpUnexpectedReset(spinel_status_t aStatus); 1206 void HandleRcpTimeout(void); 1207 void RecoverFromRcpFailure(void); 1208 UpdateParseErrorCount(otError aError)1209 void UpdateParseErrorCount(otError aError) 1210 { 1211 mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0; 1212 } 1213 1214 otError SetMacKey(uint8_t aKeyIdMode, 1215 uint8_t aKeyId, 1216 const otMacKey &aPrevKey, 1217 const otMacKey &aCurrKey, 1218 const otMacKey &NextKey); 1219 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1220 static otError ReadMacKey(const otMacKeyMaterial &aKeyMaterial, otMacKey &aKey); 1221 #endif 1222 1223 static void LogIfFail(const char *aText, otError aError); 1224 1225 static void LogCrit(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(1, 2); 1226 static void LogWarn(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(1, 2); 1227 static void LogNote(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(1, 2); 1228 static void LogInfo(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(1, 2); 1229 static void LogDebg(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(1, 2); 1230 1231 uint32_t Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...); 1232 void LogSpinelFrame(const uint8_t *aFrame, uint16_t aLength, bool aTx); 1233 1234 otInstance *mInstance; 1235 1236 SpinelInterface::RxFrameBuffer mRxFrameBuffer; 1237 SpinelInterface *mSpinelInterface; 1238 1239 RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer. 1240 1241 uint16_t mCmdTidsInUse; ///< Used transaction ids. 1242 spinel_tid_t mCmdNextTid; ///< Next available transaction id. 1243 spinel_tid_t mTxRadioTid; ///< The transaction id used to send a radio frame. 1244 spinel_tid_t mWaitingTid; ///< The transaction id of current transaction. 1245 spinel_prop_key_t mWaitingKey; ///< The property key of current transaction. 1246 const char *mPropertyFormat; ///< The spinel property format of current transaction. 1247 va_list mPropertyArgs; ///< The arguments pack or unpack spinel property of current transaction. 1248 uint32_t mExpectedCommand; ///< Expected response command of current transaction. 1249 otError mError; ///< The result of current transaction. 1250 spinel_iid_t mIid; ///< The spinel interface id used by this process. 1251 spinel_iid_t mIidList[kSpinelHeaderMaxNumIid]; ///< Array of interface ids to accept the incoming spinel frames. 1252 1253 uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1254 uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1255 uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE]; 1256 otRadioFrame mRxRadioFrame; 1257 otRadioFrame mTxRadioFrame; 1258 otRadioFrame mAckRadioFrame; 1259 otRadioFrame *mTransmitFrame; ///< Points to the frame to send 1260 1261 otExtAddress mExtendedAddress; 1262 uint16_t mShortAddress; 1263 uint16_t mPanId; 1264 uint8_t mChannel; 1265 int8_t mRxSensitivity; 1266 otError mTxError; 1267 static char sVersion[kVersionStringSize]; 1268 static otExtAddress sIeeeEui64; 1269 static otRadioCaps sRadioCaps; 1270 1271 State mState; 1272 bool mIsPromiscuous : 1; ///< Promiscuous mode. 1273 bool mRxOnWhenIdle : 1; ///< RxOnWhenIdle mode. 1274 bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP. 1275 1276 static bool sIsReady; ///< NCP ready. 1277 static bool sSupportsLogStream; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format. 1278 static bool sSupportsResetToBootloader; ///< RCP supports resetting into bootloader mode. 1279 1280 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1281 1282 enum 1283 { 1284 kRcpFailureNone, 1285 kRcpFailureTimeout, 1286 kRcpFailureUnexpectedReset, 1287 }; 1288 1289 bool mResetRadioOnStartup : 1; ///< Whether should send reset command when init. 1290 int16_t mRcpFailureCount; ///< Count of consecutive RCP failures. 1291 uint8_t mRcpFailure : 2; ///< RCP failure reason, should recover and retry operation. 1292 1293 // Properties set by core. 1294 uint8_t mKeyIdMode; 1295 uint8_t mKeyId; 1296 otMacKey mPrevKey; 1297 otMacKey mCurrKey; 1298 otMacKey mNextKey; 1299 uint16_t mSrcMatchShortEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 1300 int16_t mSrcMatchShortEntryCount; 1301 otExtAddress mSrcMatchExtEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN]; 1302 int16_t mSrcMatchExtEntryCount; 1303 uint8_t mScanChannel; 1304 uint16_t mScanDuration; 1305 int8_t mCcaEnergyDetectThreshold; 1306 int8_t mTransmitPower; 1307 int8_t mFemLnaGain; 1308 uint32_t mMacFrameCounter; 1309 bool mCoexEnabled : 1; 1310 1311 bool mMacKeySet : 1; ///< Whether MAC key has been set. 1312 bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set. 1313 bool mTransmitPowerSet : 1; ///< Whether transmit power has been set. 1314 bool mCoexEnabledSet : 1; ///< Whether coex enabled has been set. 1315 bool mFemLnaGainSet : 1; ///< Whether FEM LNA gain has been set. 1316 bool mEnergyScanning : 1; ///< If fails while scanning, restarts scanning. 1317 bool mMacFrameCounterSet : 1; ///< Whether the MAC frame counter has been set. 1318 1319 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 1320 1321 #if OPENTHREAD_CONFIG_DIAG_ENABLE 1322 bool mDiagMode; 1323 char *mDiagOutput; 1324 size_t mDiagOutputMaxLen; 1325 #endif 1326 1327 uint64_t mTxRadioEndUs; 1328 uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset. 1329 uint64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time. 1330 1331 MaxPowerTable mMaxPowerTable; 1332 1333 otRadioSpinelMetrics mRadioSpinelMetrics; 1334 }; 1335 1336 } // namespace Spinel 1337 } // namespace ot 1338 1339 #endif // RADIO_SPINEL_HPP_ 1340