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