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