472 lines
19 KiB
C++
472 lines
19 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "sdkconfig.h"
|
|
#include "esp_check.h"
|
|
#include "esp_log.h"
|
|
#include "platform/exit_code.h"
|
|
#include "radio_spinel.hpp"
|
|
#include "esp_radio_spinel.h"
|
|
#include "esp_radio_spinel_platform.h"
|
|
#include "esp_radio_spinel_adapter.hpp"
|
|
#include "esp_radio_spinel_uart_interface.hpp"
|
|
#include "spinel_driver.hpp"
|
|
#include "openthread/link.h"
|
|
|
|
#define SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE BIT(0)
|
|
#define SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR BIT(1)
|
|
static esp_ieee802154_pending_mode_t s_spinel_vendor_property_pendingmode[ot::Spinel::kSpinelHeaderMaxNumIid] = {ESP_IEEE802154_AUTO_PENDING_DISABLE};
|
|
static bool s_spinel_vendor_property_coordinator[ot::Spinel::kSpinelHeaderMaxNumIid] = {false};
|
|
static uint64_t s_spinel_vendor_property_mask[ot::Spinel::kSpinelHeaderMaxNumIid] = {0};
|
|
|
|
using ot::Spinel::RadioSpinel;
|
|
using ot::Spinel::RadioSpinelCallbacks;
|
|
using esp::radio_spinel::SpinelInterfaceAdapter;
|
|
using esp::radio_spinel::UartSpinelInterface;
|
|
using ot::Spinel::SpinelDriver;
|
|
|
|
static SpinelInterfaceAdapter<UartSpinelInterface> s_spinel_interface[ot::Spinel::kSpinelHeaderMaxNumIid];
|
|
static RadioSpinel s_radio[ot::Spinel::kSpinelHeaderMaxNumIid];
|
|
static esp_radio_spinel_callbacks_t s_esp_radio_spinel_callbacks[ot::Spinel::kSpinelHeaderMaxNumIid];
|
|
static SpinelDriver s_spinel_driver[ot::Spinel::kSpinelHeaderMaxNumIid];
|
|
otRadioFrame s_transmit_frame;
|
|
|
|
static otRadioCaps s_radio_caps = (OT_RADIO_CAPS_ENERGY_SCAN |
|
|
OT_RADIO_CAPS_TRANSMIT_SEC |
|
|
OT_RADIO_CAPS_RECEIVE_TIMING |
|
|
OT_RADIO_CAPS_TRANSMIT_TIMING |
|
|
OT_RADIO_CAPS_ACK_TIMEOUT |
|
|
OT_RADIO_CAPS_SLEEP_TO_TX);
|
|
|
|
static esp_radio_spinel_compatibility_error_callback s_radio_spinel_compatibility_error_callback = NULL;
|
|
static esp_radio_spinel_coprocessor_reset_failure_callback s_radio_spinel_coprocessor_reset_failure_callback = NULL;
|
|
|
|
static esp_radio_spinel_idx_t get_index_from_instance(otInstance *instance)
|
|
{
|
|
// TZ-563: Implement the function to get the esp radio spinel idx from otInstance for multipan rcp
|
|
return ESP_RADIO_SPINEL_ZIGBEE;
|
|
}
|
|
|
|
static otInstance* get_instance_from_index(esp_radio_spinel_idx_t idx)
|
|
{
|
|
// TZ-563: Implement the function to get otInstance pointer from esp radio spinel idx
|
|
return nullptr;
|
|
}
|
|
|
|
static void esp_radio_spinel_restore_vendor_properities(void *context)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance((otInstance*)context);
|
|
if (s_spinel_vendor_property_mask[idx] & SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE) {
|
|
if (esp_radio_spinel_set_pending_mode(s_spinel_vendor_property_pendingmode[idx], idx) != ESP_OK) {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to restore pendingmode: %d", idx);
|
|
}
|
|
}
|
|
|
|
if (s_spinel_vendor_property_mask[idx] & SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR) {
|
|
if (esp_radio_spinel_set_pan_coord(s_spinel_vendor_property_coordinator[idx], idx) != ESP_OK) {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to restore coordinator: %d", idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void radio_spinel_compatibility_error_callback(void *context)
|
|
{
|
|
OT_UNUSED_VARIABLE(context);
|
|
assert(s_radio_spinel_compatibility_error_callback);
|
|
s_radio_spinel_compatibility_error_callback();
|
|
}
|
|
|
|
static void radio_spinel_coprocessor_reset_failure_callback(void *context)
|
|
{
|
|
OT_UNUSED_VARIABLE(context);
|
|
assert(s_radio_spinel_coprocessor_reset_failure_callback);
|
|
s_radio_spinel_coprocessor_reset_failure_callback();
|
|
}
|
|
|
|
void esp_radio_spinel_set_compatibility_error_callback(esp_radio_spinel_compatibility_error_callback callback)
|
|
{
|
|
s_radio_spinel_compatibility_error_callback = callback;
|
|
}
|
|
|
|
void esp_radio_spinel_set_coprocessor_reset_failure_callback(esp_radio_spinel_coprocessor_reset_failure_callback callback)
|
|
{
|
|
s_radio_spinel_coprocessor_reset_failure_callback = callback;
|
|
}
|
|
|
|
void ReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].receive_done);
|
|
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
|
esp_ieee802154_frame_info_t frame_info;
|
|
if (frame) {
|
|
frame[0] = aFrame->mLength;
|
|
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
|
frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi;
|
|
frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp;
|
|
frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending;
|
|
s_esp_radio_spinel_callbacks[idx].receive_done(frame, &frame_info);
|
|
free(frame);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
|
}
|
|
}
|
|
|
|
void TransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].transmit_done && s_esp_radio_spinel_callbacks[idx].transmit_failed);
|
|
if (aError == OT_ERROR_NONE) {
|
|
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
|
uint8_t *ack = nullptr;
|
|
if (frame) {
|
|
esp_ieee802154_frame_info_t ack_info;
|
|
frame[0] = aFrame->mLength;
|
|
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
|
if (aAckFrame) {
|
|
ack = (uint8_t *)malloc(aAckFrame->mLength + 1);
|
|
if (ack) {
|
|
ack[0] = aAckFrame->mLength;
|
|
memcpy((void *)(ack + 1), aAckFrame->mPsdu, ack[0]);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for ack");
|
|
}
|
|
}
|
|
s_esp_radio_spinel_callbacks[idx].transmit_done(frame, ack, &ack_info);
|
|
free(frame);
|
|
free(ack);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
|
}
|
|
} else {
|
|
switch (aError) {
|
|
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
|
|
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
|
break;
|
|
case OT_ERROR_NO_ACK:
|
|
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK);
|
|
break;
|
|
default:
|
|
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_ABORT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnergyScanDone(otInstance *aInstance, int8_t aMaxRssi)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].energy_scan_done);
|
|
s_esp_radio_spinel_callbacks[idx].energy_scan_done(aMaxRssi);
|
|
}
|
|
|
|
void TxStarted(otInstance *aInstance, otRadioFrame *aFrame)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].transmit_started);
|
|
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
|
if (frame) {
|
|
frame[0] = aFrame->mLength;
|
|
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
|
s_esp_radio_spinel_callbacks[idx].transmit_started(frame);
|
|
free(frame);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
|
}
|
|
}
|
|
|
|
void SwitchoverDone(otInstance *aInstance, bool aSuccess)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].switchover_done);
|
|
s_esp_radio_spinel_callbacks[idx].switchover_done(aSuccess);
|
|
}
|
|
|
|
#if CONFIG_OPENTHREAD_DIAG
|
|
void DiagReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].diag_receive_done);
|
|
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
|
esp_ieee802154_frame_info_t frame_info;
|
|
if (frame) {
|
|
frame[0] = aFrame->mLength;
|
|
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
|
frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi;
|
|
frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp;
|
|
frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending;
|
|
s_esp_radio_spinel_callbacks[idx].diag_receive_done(frame, &frame_info);
|
|
free(frame);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
|
}
|
|
}
|
|
|
|
void DiagTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
assert(s_esp_radio_spinel_callbacks[idx].diag_transmit_done && s_esp_radio_spinel_callbacks[idx].diag_transmit_failed);
|
|
if (aError == OT_ERROR_NONE) {
|
|
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
|
if (frame) {
|
|
esp_ieee802154_frame_info_t ack_info;
|
|
frame[0] = aFrame->mLength;
|
|
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
|
s_esp_radio_spinel_callbacks[idx].diag_transmit_done(frame, &ack_info);
|
|
free(frame);
|
|
} else {
|
|
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
|
}
|
|
} else {
|
|
switch (aError) {
|
|
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
|
|
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
|
break;
|
|
case OT_ERROR_NO_ACK:
|
|
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK);
|
|
break;
|
|
default:
|
|
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif // CONFIG_OPENTHREAD_DIAG
|
|
|
|
|
|
void esp_radio_spinel_set_callbacks(const esp_radio_spinel_callbacks_t aCallbacks, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_esp_radio_spinel_callbacks[idx] = aCallbacks;
|
|
RadioSpinelCallbacks Callbacks;
|
|
memset(&Callbacks, 0, sizeof(Callbacks));
|
|
Callbacks.mReceiveDone = ReceiveDone;
|
|
Callbacks.mTransmitDone = TransmitDone;
|
|
Callbacks.mEnergyScanDone = EnergyScanDone;
|
|
Callbacks.mTxStarted = TxStarted;
|
|
Callbacks.mSwitchoverDone = SwitchoverDone;
|
|
#if CONFIG_OPENTHREAD_DIAG
|
|
Callbacks.mDiagReceiveDone = DiagReceiveDone;
|
|
Callbacks.mDiagTransmitDone = DiagTransmitDone;
|
|
#endif // CONFIG_OPENTHREAD_DIAG
|
|
|
|
s_radio[idx].SetCallbacks(Callbacks);
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_uart_interface_enable(const esp_radio_spinel_uart_config_t *radio_uart_config,
|
|
esp_radio_spinel_uart_init_handler aUartInitHandler,
|
|
esp_radio_spinel_uart_deinit_handler aUartDeinitHandler,
|
|
esp_radio_spinel_idx_t idx)
|
|
{
|
|
ESP_RETURN_ON_FALSE(aUartInitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartInitHandler can not be set to NULL");
|
|
ESP_RETURN_ON_FALSE(aUartDeinitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartDeinitHandler can not be set to NULL");
|
|
s_spinel_interface[idx].GetSpinelInterface().RegisterUartInitHandler(aUartInitHandler);
|
|
s_spinel_interface[idx].GetSpinelInterface().RegisterUartDeinitHandler(aUartDeinitHandler);
|
|
ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Enable(*radio_uart_config) == OT_ERROR_NONE, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Spinel UART interface failed to enable");
|
|
ESP_LOGI(ESP_SPINEL_LOG_TAG, "Spinel UART interface has been successfully enabled");
|
|
return ESP_OK;
|
|
}
|
|
|
|
void esp_radio_spinel_init(esp_radio_spinel_idx_t idx)
|
|
{
|
|
spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
|
|
otInstance *instance = get_instance_from_index(idx);
|
|
|
|
// Multipan is not currently supported
|
|
iidList[0] = 0;
|
|
s_spinel_driver[idx].SetCoprocessorResetFailureCallback(radio_spinel_coprocessor_reset_failure_callback, instance);
|
|
s_spinel_driver[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), true, iidList, ot::Spinel::kSpinelHeaderMaxNumIid);
|
|
s_radio[idx].SetCompatibilityErrorCallback(radio_spinel_compatibility_error_callback, instance);
|
|
s_radio[idx].Init(/*skip_rcp_compatibility_check=*/false, /*reset_radio=*/true, &s_spinel_driver[idx], s_radio_caps, false);
|
|
s_radio[idx].SetVendorRestorePropertiesCallback(esp_radio_spinel_restore_vendor_properities, instance);
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx)
|
|
{
|
|
otInstance *instance = get_instance_from_index(idx);
|
|
return (s_radio[idx].Enable(instance) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].GetIeeeEui64(eui64) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_panid(uint16_t panid, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].SetPanId(panid) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_short_address(uint16_t short_address, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].SetShortAddress(short_address) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_spinel_idx_t idx)
|
|
{
|
|
otExtAddress aExtAddress;
|
|
memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE);
|
|
return (s_radio[idx].SetExtendedAddress(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].Receive(channel) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_energy_scan(uint8_t scan_channel, uint16_t scan_duration, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].EnergyScan(scan_channel, scan_duration) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_transmit(uint8_t *frame, uint8_t channel, bool cca, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_transmit_frame.mLength = frame[0];
|
|
s_transmit_frame.mPsdu = frame + 1;
|
|
s_transmit_frame.mInfo.mTxInfo.mCsmaCaEnabled = cca;
|
|
s_transmit_frame.mInfo.mTxInfo.mMaxCsmaBackoffs = CONFIG_OPENTHREAD_SPINEL_MAC_MAX_CSMA_BACKOFFS_DIRECT;
|
|
s_transmit_frame.mChannel = channel;
|
|
s_transmit_frame.mInfo.mTxInfo.mRxChannelAfterTxDone = channel;
|
|
return (s_radio[idx].Transmit(s_transmit_frame) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_clear_short_entries(esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].ClearSrcMatchShortEntries() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_add_short_entry(uint16_t short_address, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].AddSrcMatchShortEntry(short_address) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_clear_extended_entries(esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].ClearSrcMatchExtEntries() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_add_extended_entry(uint8_t *ext_address, esp_radio_spinel_idx_t idx)
|
|
{
|
|
otExtAddress aExtAddress;
|
|
memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE);
|
|
return (s_radio[idx].AddSrcMatchExtEntry(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].SetPromiscuous(enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
/*------------------------------------------------Vendor Property Set-------------------------------------------------------*/
|
|
esp_err_t esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_vendor_property_pendingmode[idx] = pending_mode;
|
|
s_spinel_vendor_property_mask[idx] |= SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE;
|
|
return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE, SPINEL_DATATYPE_INT32_S, static_cast<int32_t>(pending_mode)) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_vendor_property_coordinator[idx] = enable;
|
|
s_spinel_vendor_property_mask[idx] |= SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR;
|
|
return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR, SPINEL_DATATYPE_BOOL_S, enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
|
|
void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_interface[idx].GetSpinelInterface().UpdateFdSet(static_cast<void *>(mainloop_context));
|
|
}
|
|
|
|
void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_driver[idx].Process((void *)mainloop_context);
|
|
s_radio[idx].Process(static_cast<void *>(mainloop_context));
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_sleep(esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].Sleep() == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_tx_power(int8_t power, esp_radio_spinel_idx_t idx)
|
|
{
|
|
return (s_radio[idx].SetTransmitPower(power) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_get_tx_power(int8_t *power, esp_radio_spinel_idx_t idx)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
int8_t aPower;
|
|
error = s_radio[idx].GetTransmitPower(aPower);
|
|
*power = aPower;
|
|
return (error == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
|
}
|
|
|
|
void esp_radio_spinel_register_rcp_failure_handler(esp_radio_spinel_rcp_failure_handler handler, esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_interface[idx].GetSpinelInterface().RegisterRcpFailureHandler(handler);
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_rcp_deinit(esp_radio_spinel_idx_t idx)
|
|
{
|
|
if (s_radio[idx].IsEnabled()) {
|
|
ESP_RETURN_ON_FALSE(s_radio[idx].Sleep() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Radio fails to sleep");
|
|
ESP_RETURN_ON_FALSE(s_radio[idx].Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to disable radio");
|
|
}
|
|
ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to deinitialize UART");
|
|
return ESP_OK;
|
|
}
|
|
|
|
|
|
esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_spinel_idx_t idx)
|
|
{
|
|
const char *rcp_version = s_radio[idx].GetVersion();
|
|
ESP_RETURN_ON_FALSE(rcp_version != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Fail to get rcp version");
|
|
strcpy(running_rcp_version, rcp_version);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t esp_radio_spinel_set_rcp_ready(esp_radio_spinel_idx_t idx)
|
|
{
|
|
s_spinel_driver[idx].SetCoprocessorReady();
|
|
return ESP_OK;
|
|
}
|
|
|
|
// TZ-1261
|
|
uint32_t otLinkGetFrameCounter(otInstance *aInstance)
|
|
{
|
|
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
|
return esp_radio_spinel_extern_get_frame_counter(idx);
|
|
}
|
|
|
|
__attribute__((weak)) uint32_t esp_radio_spinel_extern_get_frame_counter(esp_radio_spinel_idx_t idx)
|
|
{
|
|
ESP_LOGW(ESP_SPINEL_LOG_TAG, "None function to get frame counter");
|
|
return 0;
|
|
}
|
|
|
|
namespace ot {
|
|
namespace Spinel {
|
|
|
|
otError RadioSpinel::VendorHandleValueIs(spinel_prop_key_t aPropKey)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
|
|
switch (aPropKey)
|
|
{
|
|
default:
|
|
ESP_LOGW(ESP_SPINEL_LOG_TAG, "Not Implemented!");
|
|
error = OT_ERROR_NOT_FOUND;
|
|
break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
} // namespace Spinel
|
|
} // namespace ot
|