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