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