938 lines
34 KiB
C
938 lines
34 KiB
C
/*
|
|
* Copyright (c) 2017 - 2022, Nordic Semiconductor ASA
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* This file implements requests to the driver triggered by the MAC layer through SWI.
|
|
*
|
|
*/
|
|
|
|
#include "nrf_802154_request.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "nrf_802154_config.h"
|
|
#include "nrf_802154_core.h"
|
|
#include "nrf_802154_critical_section.h"
|
|
#include "nrf_802154_debug.h"
|
|
#include "nrf_802154_queue.h"
|
|
#include "nrf_802154_rx_buffer.h"
|
|
#include "nrf_802154_swi.h"
|
|
#include "nrf_802154_utils.h"
|
|
#include "mac_features/nrf_802154_csma_ca.h"
|
|
#include "hal/nrf_radio.h"
|
|
#include "hal/nrf_egu.h"
|
|
#include "mac_features/nrf_802154_delayed_trx.h"
|
|
#include "platform/nrf_802154_irq.h"
|
|
|
|
#include <nrf.h>
|
|
|
|
/** Size of requests queue.
|
|
*
|
|
* Two is minimal queue size. It is not expected in current implementation to queue a few requests.
|
|
*/
|
|
#define REQ_QUEUE_SIZE 2
|
|
|
|
#define REQ_INT NRF_EGU_INT_TRIGGERED2 ///< Label of request interrupt.
|
|
#define REQ_TASK NRF_EGU_TASK_TRIGGER2 ///< Label of request task.
|
|
#define REQ_EVENT NRF_EGU_EVENT_TRIGGERED2 ///< Label of request event.
|
|
|
|
/// Type of requests in request queue.
|
|
typedef enum
|
|
{
|
|
REQ_TYPE_SLEEP,
|
|
REQ_TYPE_RECEIVE,
|
|
REQ_TYPE_TRANSMIT,
|
|
REQ_TYPE_ENERGY_DETECTION,
|
|
REQ_TYPE_CCA,
|
|
REQ_TYPE_CONTINUOUS_CARRIER,
|
|
REQ_TYPE_MODULATED_CARRIER,
|
|
REQ_TYPE_BUFFER_FREE,
|
|
REQ_TYPE_CHANNEL_UPDATE,
|
|
REQ_TYPE_CCA_CFG_UPDATE,
|
|
REQ_TYPE_RSSI_MEASURE,
|
|
REQ_TYPE_RSSI_GET,
|
|
REQ_TYPE_ANTENNA_UPDATE,
|
|
REQ_TYPE_TRANSMIT_AT,
|
|
REQ_TYPE_TRANSMIT_AT_CANCEL,
|
|
REQ_TYPE_RECEIVE_AT,
|
|
REQ_TYPE_RECEIVE_AT_CANCEL,
|
|
REQ_TYPE_CSMA_CA_START,
|
|
} nrf_802154_req_type_t;
|
|
|
|
/// Request data in request queue.
|
|
typedef struct
|
|
{
|
|
nrf_802154_req_type_t type; ///< Type of the request.
|
|
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
bool * p_result; ///< Sleep request result.
|
|
} sleep; ///< Sleep request details.
|
|
|
|
struct
|
|
{
|
|
nrf_802154_notification_func_t notif_func; ///< Error notified in case of success.
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
req_originator_t req_orig; ///< Request originator.
|
|
bool notif_abort; ///< If function termination should be notified.
|
|
uint32_t id; ///< Identifier of a reception window.
|
|
bool * p_result; ///< Receive request result.
|
|
} receive; ///< Receive request details.
|
|
|
|
struct
|
|
{
|
|
nrf_802154_notification_func_t notif_func; ///< Error notified in case of success.
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
req_originator_t req_orig; ///< Request originator.
|
|
uint8_t * p_data; ///< Pointer to a buffer containing PHR and PSDU of the frame to transmit.
|
|
nrf_802154_transmit_params_t * p_params; ///< Pointer to transmission parameters.
|
|
bool * p_result; ///< Transmit request result.
|
|
} transmit; ///< Transmit request details.
|
|
|
|
struct
|
|
{
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
bool * p_result; ///< Energy detection request result.
|
|
uint32_t time_us; ///< Requested time of energy detection procedure.
|
|
} energy_detection; ///< Energy detection request details.
|
|
|
|
struct
|
|
{
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
bool * p_result; ///< CCA request result.
|
|
} cca; ///< CCA request details.
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
struct
|
|
{
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
bool * p_result; ///< Continuous carrier request result.
|
|
} continuous_carrier; ///< Continuous carrier request details.
|
|
|
|
struct
|
|
{
|
|
nrf_802154_term_t term_lvl; ///< Request priority.
|
|
const uint8_t * p_data; ///< Pointer to a buffer to modulate the carrier wave with.
|
|
bool * p_result; ///< Modulated carrier request result.
|
|
} modulated_carrier; ///< Modulated carrier request details.
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
struct
|
|
{
|
|
uint8_t * p_data; ///< Pointer to receive buffer to free.
|
|
bool * p_result; ///< Buffer free request result.
|
|
} buffer_free; ///< Buffer free request details.
|
|
|
|
struct
|
|
{
|
|
req_originator_t req_orig; ///< Request originator.
|
|
bool * p_result; ///< Channel update request result.
|
|
} channel_update; ///< Channel update request details.
|
|
|
|
struct
|
|
{
|
|
bool * p_result; ///< CCA config update request result.
|
|
} cca_cfg_update; ///< CCA config update request details.
|
|
|
|
struct
|
|
{
|
|
bool * p_result; ///< RSSI measurement request result.
|
|
} rssi_measure; ///< RSSI measurement request details.
|
|
|
|
struct
|
|
{
|
|
int8_t * p_rssi; ///< RSSI measurement result.
|
|
bool * p_result; ///< RSSI measurement status.
|
|
} rssi_get; ///< Details of the getter that retrieves the RSSI measurement result.
|
|
|
|
struct
|
|
{
|
|
bool * p_result; ///< Antenna update request result.
|
|
} antenna_update; ///< Antenna update request details.
|
|
|
|
#if NRF_802154_DELAYED_TRX_ENABLED
|
|
struct
|
|
{
|
|
uint8_t * p_data;
|
|
uint64_t tx_time;
|
|
const nrf_802154_transmit_at_metadata_t * p_metadata;
|
|
bool * p_result;
|
|
} transmit_at;
|
|
|
|
struct
|
|
{
|
|
bool * p_result;
|
|
} transmit_at_cancel;
|
|
|
|
struct
|
|
{
|
|
uint64_t rx_time;
|
|
uint32_t timeout;
|
|
uint8_t channel;
|
|
uint32_t id;
|
|
bool * p_result;
|
|
} receive_at;
|
|
|
|
struct
|
|
{
|
|
uint32_t id;
|
|
bool * p_result;
|
|
} receive_at_cancel;
|
|
|
|
#endif // NRF_802154_DELAYED_TRX_ENABLED
|
|
|
|
struct
|
|
{
|
|
uint8_t * p_data;
|
|
const nrf_802154_transmit_csma_ca_metadata_t * p_metadata;
|
|
bool * p_result;
|
|
} csma_ca_start; ///< Antenna update request details.
|
|
|
|
} data; ///< Request data depending on its type.
|
|
} nrf_802154_req_data_t;
|
|
|
|
/**@brief Instance of a requests queue */
|
|
static nrf_802154_queue_t m_requests_queue;
|
|
|
|
/**@brief Memory holding requests queue items */
|
|
static nrf_802154_req_data_t m_requests_queue_memory[REQ_QUEUE_SIZE];
|
|
|
|
/**@brief State of the MCU critical section */
|
|
static volatile nrf_802154_mcu_critical_state_t m_mcu_cs;
|
|
|
|
/**
|
|
* Enter request block.
|
|
*
|
|
* This is a helper function used in all request functions to atomically
|
|
* find an empty slot in request queue and allow atomic slot update.
|
|
*
|
|
* @return Pointer to an empty slot in the request queue.
|
|
*/
|
|
static nrf_802154_req_data_t * req_enter(void)
|
|
{
|
|
nrf_802154_mcu_critical_enter(m_mcu_cs);
|
|
|
|
assert(!nrf_802154_queue_is_full(&m_requests_queue));
|
|
|
|
return (nrf_802154_req_data_t *)nrf_802154_queue_push_begin(&m_requests_queue);
|
|
}
|
|
|
|
/**
|
|
* Exit request block.
|
|
*
|
|
* This is a helper function used in all request functions to end atomic slot update
|
|
* and trigger SWI to process the request from the slot.
|
|
*/
|
|
static void req_exit(void)
|
|
{
|
|
nrf_802154_queue_push_commit(&m_requests_queue);
|
|
|
|
nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, REQ_TASK);
|
|
|
|
nrf_802154_mcu_critical_exit(m_mcu_cs);
|
|
}
|
|
|
|
/** Assert if SWI interrupt is disabled. */
|
|
static inline void assert_interrupt_status(void)
|
|
{
|
|
assert(nrf_802154_irq_is_enabled(NRF_802154_EGU_IRQN));
|
|
}
|
|
|
|
#define REQUEST_FUNCTION(func_core, func_swi, ...) \
|
|
bool result = false; \
|
|
\
|
|
if (active_vector_priority_is_high()) \
|
|
{ \
|
|
result = func_core(__VA_ARGS__); \
|
|
} \
|
|
else \
|
|
{ \
|
|
assert_interrupt_status(); \
|
|
func_swi(__VA_ARGS__, &result); \
|
|
} \
|
|
\
|
|
return result;
|
|
|
|
#define REQUEST_FUNCTION_NO_ARGS(func_core, func_swi) \
|
|
bool result = false; \
|
|
\
|
|
if (active_vector_priority_is_high()) \
|
|
{ \
|
|
result = func_core(); \
|
|
} \
|
|
else \
|
|
{ \
|
|
assert_interrupt_status(); \
|
|
func_swi(&result); \
|
|
} \
|
|
\
|
|
return result;
|
|
|
|
/** Check if active vector priority is high enough to call requests directly.
|
|
*
|
|
* @retval true Active vector priority is greater or equal to SWI priority.
|
|
* @retval false Active vector priority is lower than SWI priority.
|
|
*/
|
|
static bool active_vector_priority_is_high(void)
|
|
{
|
|
|
|
return nrf_802154_critical_section_active_vector_priority_get() <=
|
|
nrf_802154_irq_priority_get(NRF_802154_EGU_IRQN);
|
|
}
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_SLEEP state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[out] p_result Result of entering the sleep state.
|
|
*/
|
|
static void swi_sleep(nrf_802154_term_t term_lvl, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_SLEEP;
|
|
p_slot->data.sleep.term_lvl = term_lvl;
|
|
p_slot->data.sleep.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_RX state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[in] req_orig Module that originates this request.
|
|
* @param[in] notify_function Function called to notify the status of the procedure. May be NULL.
|
|
* @param[in] notify_abort If abort notification should be triggered automatically.
|
|
* @param[in] id Identifier of the reception window.
|
|
* @param[out] p_result Result of entering the receive state.
|
|
*/
|
|
static void swi_receive(nrf_802154_term_t term_lvl,
|
|
req_originator_t req_orig,
|
|
nrf_802154_notification_func_t notify_function,
|
|
bool notify_abort,
|
|
uint32_t id,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_RECEIVE;
|
|
p_slot->data.receive.term_lvl = term_lvl;
|
|
p_slot->data.receive.req_orig = req_orig;
|
|
p_slot->data.receive.notif_func = notify_function;
|
|
p_slot->data.receive.notif_abort = notify_abort;
|
|
p_slot->data.receive.id = id;
|
|
p_slot->data.receive.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @biref Requests entering the @ref RADIO_STATE_TX state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[in] req_orig Module that originates this request.
|
|
* @param[in] p_data Pointer to a buffer that contains PHR and PSDU of the frame to be
|
|
* transmitted.
|
|
* @param[in] p_params Pointer to transmission parameters.
|
|
* @param[in] notify_function Function called to notify the status of this procedure instead of
|
|
* the default notification. If NULL, the default notification
|
|
* is used.
|
|
* @param[out] p_result Result of entering the transmit state.
|
|
*/
|
|
static void swi_transmit(nrf_802154_term_t term_lvl,
|
|
req_originator_t req_orig,
|
|
uint8_t * p_data,
|
|
nrf_802154_transmit_params_t * p_params,
|
|
nrf_802154_notification_func_t notify_function,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_TRANSMIT;
|
|
p_slot->data.transmit.term_lvl = term_lvl;
|
|
p_slot->data.transmit.req_orig = req_orig;
|
|
p_slot->data.transmit.p_data = p_data;
|
|
p_slot->data.transmit.p_params = p_params;
|
|
p_slot->data.transmit.notif_func = notify_function;
|
|
p_slot->data.transmit.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_ED state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[in] time_us Requested duration of the energy detection procedure.
|
|
* @param[out] p_result Result of entering the energy detection state.
|
|
*/
|
|
static void swi_energy_detection(nrf_802154_term_t term_lvl,
|
|
uint32_t time_us,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_ENERGY_DETECTION;
|
|
p_slot->data.energy_detection.term_lvl = term_lvl;
|
|
p_slot->data.energy_detection.time_us = time_us;
|
|
p_slot->data.energy_detection.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_CCA state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[out] p_result Result of entering the CCA state.
|
|
*/
|
|
static void swi_cca(nrf_802154_term_t term_lvl, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_CCA;
|
|
p_slot->data.cca.term_lvl = term_lvl;
|
|
p_slot->data.cca.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_CONTINUOUS_CARRIER state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[out] p_result Result of entering the continuous carrier state.
|
|
*/
|
|
static void swi_continuous_carrier(nrf_802154_term_t term_lvl, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_CONTINUOUS_CARRIER;
|
|
p_slot->data.continuous_carrier.term_lvl = term_lvl;
|
|
p_slot->data.continuous_carrier.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Requests entering the @ref RADIO_STATE_MODULATED_CARRIER state from the SWI priority.
|
|
*
|
|
* @param[in] term_lvl Termination level of this request. Selects procedures to abort.
|
|
* @param[in] p_data Pointer to the data buffer to modulate the carrier wave with.
|
|
* @param[out] p_result Result of entering the modulated carrier state.
|
|
*/
|
|
static void swi_modulated_carrier(nrf_802154_term_t term_lvl,
|
|
const uint8_t * p_data,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_MODULATED_CARRIER;
|
|
p_slot->data.modulated_carrier.term_lvl = term_lvl;
|
|
p_slot->data.modulated_carrier.p_data = p_data;
|
|
p_slot->data.modulated_carrier.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
/**
|
|
* @brief Notifies the core module that the given buffer is not used anymore and can be freed.
|
|
*
|
|
* @param[in] p_data Pointer to the buffer to be freed.
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_buffer_free should be written by the swi handler.
|
|
*/
|
|
static void swi_buffer_free(uint8_t * p_data, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_BUFFER_FREE;
|
|
p_slot->data.buffer_free.p_data = p_data;
|
|
p_slot->data.buffer_free.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Notifies the core module that the next higher layer has requested an antenna change.
|
|
*
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_antenna_update should be written by the swi handler.
|
|
*/
|
|
static void swi_antenna_update(bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_ANTENNA_UPDATE;
|
|
p_slot->data.antenna_update.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Notifies the core module that the next higher layer has requested a channel change.
|
|
*
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_channel_update should be written by the swi handler.
|
|
*/
|
|
static void swi_channel_update(req_originator_t req_orig, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_CHANNEL_UPDATE;
|
|
p_slot->data.channel_update.p_result = p_result;
|
|
p_slot->data.channel_update.req_orig = req_orig;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Notifies the core module that the next higher layer has requested a CCA configuration
|
|
* change.
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_cca_cfg_update should be written by the swi handler.
|
|
*/
|
|
static void swi_cca_cfg_update(bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_CCA_CFG_UPDATE;
|
|
p_slot->data.cca_cfg_update.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Notifies the core module that the next higher layer requested the RSSI measurement.
|
|
*
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_rssi_measure should be written by the swi handler.
|
|
*/
|
|
static void swi_rssi_measure(bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_RSSI_MEASURE;
|
|
p_slot->data.rssi_measure.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the last RSSI measurement result from the core module.
|
|
*
|
|
* @param[out] p_rssi Pointer where RSSI measurement value will be stored.
|
|
* @param[out] p_result Pointer where the result to be returned by
|
|
* nrf_802154_request_rssi_measurement_get should be written by the swi handler.
|
|
*/
|
|
static void swi_rssi_measurement_get(int8_t * p_rssi, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_RSSI_GET;
|
|
p_slot->data.rssi_get.p_rssi = p_rssi;
|
|
p_slot->data.rssi_get.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
#if NRF_802154_DELAYED_TRX_ENABLED
|
|
static void swi_transmit_at(uint8_t * p_data,
|
|
uint64_t tx_time,
|
|
const nrf_802154_transmit_at_metadata_t * p_metadata,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_TRANSMIT_AT;
|
|
p_slot->data.transmit_at.p_data = p_data;
|
|
p_slot->data.transmit_at.tx_time = tx_time;
|
|
p_slot->data.transmit_at.p_metadata = p_metadata;
|
|
p_slot->data.transmit_at.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
static void swi_transmit_at_cancel(bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_TRANSMIT_AT_CANCEL;
|
|
p_slot->data.transmit_at_cancel.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
static void swi_receive_at(uint64_t rx_time,
|
|
uint32_t timeout,
|
|
uint8_t channel,
|
|
uint32_t id,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_RECEIVE_AT;
|
|
p_slot->data.receive_at.rx_time = rx_time;
|
|
p_slot->data.receive_at.timeout = timeout;
|
|
p_slot->data.receive_at.channel = channel;
|
|
p_slot->data.receive_at.id = id;
|
|
p_slot->data.receive_at.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
static void swi_receive_at_cancel(uint32_t id, bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_RECEIVE_AT_CANCEL;
|
|
p_slot->data.receive_at_cancel.id = id;
|
|
p_slot->data.receive_at_cancel.p_result = p_result;
|
|
|
|
req_exit();
|
|
}
|
|
|
|
#endif // NRF_802154_DELAYED_TRX_ENABLED
|
|
|
|
static void swi_csma_ca_start(uint8_t * p_data,
|
|
const nrf_802154_transmit_csma_ca_metadata_t * p_metadata,
|
|
bool * p_result)
|
|
{
|
|
nrf_802154_req_data_t * p_slot = req_enter();
|
|
|
|
p_slot->type = REQ_TYPE_CSMA_CA_START;
|
|
p_slot->data.csma_ca_start.p_data = p_data;
|
|
p_slot->data.csma_ca_start.p_metadata = p_metadata;
|
|
p_slot->data.csma_ca_start.p_result = p_result;
|
|
req_exit();
|
|
}
|
|
|
|
void nrf_802154_request_init(void)
|
|
{
|
|
nrf_802154_queue_init(&m_requests_queue,
|
|
m_requests_queue_memory,
|
|
sizeof(m_requests_queue_memory),
|
|
sizeof(m_requests_queue_memory[0]));
|
|
|
|
nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, REQ_INT);
|
|
|
|
nrf_802154_swi_init();
|
|
}
|
|
|
|
bool nrf_802154_request_sleep(nrf_802154_term_t term_lvl)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_sleep, swi_sleep, term_lvl)
|
|
}
|
|
|
|
bool nrf_802154_request_receive(nrf_802154_term_t term_lvl,
|
|
req_originator_t req_orig,
|
|
nrf_802154_notification_func_t notify_function,
|
|
bool notify_abort,
|
|
uint32_t id)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_receive,
|
|
swi_receive,
|
|
term_lvl,
|
|
req_orig,
|
|
notify_function,
|
|
notify_abort,
|
|
id)
|
|
}
|
|
|
|
bool nrf_802154_request_transmit(nrf_802154_term_t term_lvl,
|
|
req_originator_t req_orig,
|
|
uint8_t * p_data,
|
|
nrf_802154_transmit_params_t * p_params,
|
|
nrf_802154_notification_func_t notify_function)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_transmit,
|
|
swi_transmit,
|
|
term_lvl,
|
|
req_orig,
|
|
p_data,
|
|
p_params,
|
|
notify_function)
|
|
}
|
|
|
|
bool nrf_802154_request_energy_detection(nrf_802154_term_t term_lvl,
|
|
uint32_t time_us)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_energy_detection,
|
|
swi_energy_detection,
|
|
term_lvl,
|
|
time_us)
|
|
}
|
|
|
|
bool nrf_802154_request_cca(nrf_802154_term_t term_lvl)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_cca, swi_cca, term_lvl)
|
|
}
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
bool nrf_802154_request_continuous_carrier(nrf_802154_term_t term_lvl)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_continuous_carrier,
|
|
swi_continuous_carrier,
|
|
term_lvl)
|
|
}
|
|
|
|
bool nrf_802154_request_modulated_carrier(nrf_802154_term_t term_lvl,
|
|
const uint8_t * p_data)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_modulated_carrier,
|
|
swi_modulated_carrier,
|
|
term_lvl,
|
|
p_data)
|
|
}
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
bool nrf_802154_request_buffer_free(uint8_t * p_data)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_notify_buffer_free, swi_buffer_free, p_data)
|
|
}
|
|
|
|
bool nrf_802154_request_antenna_update(void)
|
|
{
|
|
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_antenna_update, swi_antenna_update)
|
|
}
|
|
|
|
bool nrf_802154_request_channel_update(req_originator_t req_orig)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_channel_update, swi_channel_update, req_orig)
|
|
}
|
|
|
|
bool nrf_802154_request_cca_cfg_update(void)
|
|
{
|
|
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_cca_cfg_update, swi_cca_cfg_update)
|
|
}
|
|
|
|
bool nrf_802154_request_rssi_measure(void)
|
|
{
|
|
REQUEST_FUNCTION_NO_ARGS(nrf_802154_core_rssi_measure, swi_rssi_measure)
|
|
}
|
|
|
|
bool nrf_802154_request_rssi_measurement_get(int8_t * p_rssi)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_core_last_rssi_measurement_get,
|
|
swi_rssi_measurement_get,
|
|
p_rssi)
|
|
}
|
|
|
|
#if NRF_802154_DELAYED_TRX_ENABLED
|
|
bool nrf_802154_request_transmit_raw_at(uint8_t * p_data,
|
|
uint64_t tx_time,
|
|
const nrf_802154_transmit_at_metadata_t * p_metadata)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_delayed_trx_transmit, swi_transmit_at, p_data, tx_time, p_metadata);
|
|
}
|
|
|
|
bool nrf_802154_request_transmit_at_cancel(void)
|
|
{
|
|
REQUEST_FUNCTION_NO_ARGS(nrf_802154_delayed_trx_transmit_cancel, swi_transmit_at_cancel);
|
|
}
|
|
|
|
bool nrf_802154_request_receive_at(uint64_t rx_time,
|
|
uint32_t timeout,
|
|
uint8_t channel,
|
|
uint32_t id)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_delayed_trx_receive, swi_receive_at, rx_time, timeout, channel, id);
|
|
}
|
|
|
|
bool nrf_802154_request_receive_at_cancel(uint32_t id)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_delayed_trx_receive_cancel, swi_receive_at_cancel, id);
|
|
}
|
|
|
|
bool nrf_802154_request_csma_ca_start(uint8_t * p_data,
|
|
const nrf_802154_transmit_csma_ca_metadata_t * p_metadata)
|
|
{
|
|
REQUEST_FUNCTION(nrf_802154_csma_ca_start,
|
|
swi_csma_ca_start,
|
|
p_data,
|
|
p_metadata);
|
|
}
|
|
|
|
#endif // NRF_802154_DELAYED_TRX_ENABLED
|
|
|
|
/**@brief Handles REQ_EVENT on NRF_802154_EGU_INSTANCE */
|
|
static void irq_handler_req_event(void)
|
|
{
|
|
while (!nrf_802154_queue_is_empty(&m_requests_queue))
|
|
{
|
|
nrf_802154_req_data_t * p_slot =
|
|
(nrf_802154_req_data_t *)nrf_802154_queue_pop_begin(&m_requests_queue);
|
|
|
|
switch (p_slot->type)
|
|
{
|
|
case REQ_TYPE_SLEEP:
|
|
*(p_slot->data.sleep.p_result) =
|
|
nrf_802154_core_sleep(p_slot->data.sleep.term_lvl);
|
|
break;
|
|
|
|
case REQ_TYPE_RECEIVE:
|
|
*(p_slot->data.receive.p_result) =
|
|
nrf_802154_core_receive(p_slot->data.receive.term_lvl,
|
|
p_slot->data.receive.req_orig,
|
|
p_slot->data.receive.notif_func,
|
|
p_slot->data.receive.notif_abort,
|
|
p_slot->data.receive.id);
|
|
break;
|
|
|
|
case REQ_TYPE_TRANSMIT:
|
|
*(p_slot->data.transmit.p_result) =
|
|
nrf_802154_core_transmit(p_slot->data.transmit.term_lvl,
|
|
p_slot->data.transmit.req_orig,
|
|
p_slot->data.transmit.p_data,
|
|
p_slot->data.transmit.p_params,
|
|
p_slot->data.transmit.notif_func);
|
|
break;
|
|
|
|
case REQ_TYPE_ENERGY_DETECTION:
|
|
*(p_slot->data.energy_detection.p_result) =
|
|
nrf_802154_core_energy_detection(
|
|
p_slot->data.energy_detection.term_lvl,
|
|
p_slot->data.energy_detection.time_us);
|
|
break;
|
|
|
|
case REQ_TYPE_CCA:
|
|
*(p_slot->data.cca.p_result) = nrf_802154_core_cca(p_slot->data.cca.term_lvl);
|
|
break;
|
|
|
|
#if NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
case REQ_TYPE_CONTINUOUS_CARRIER:
|
|
*(p_slot->data.continuous_carrier.p_result) =
|
|
nrf_802154_core_continuous_carrier(
|
|
p_slot->data.continuous_carrier.term_lvl);
|
|
break;
|
|
|
|
case REQ_TYPE_MODULATED_CARRIER:
|
|
*(p_slot->data.modulated_carrier.p_result) =
|
|
nrf_802154_core_modulated_carrier(p_slot->data.modulated_carrier.term_lvl,
|
|
p_slot->data.modulated_carrier.p_data);
|
|
break;
|
|
|
|
#endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
|
|
|
|
case REQ_TYPE_BUFFER_FREE:
|
|
*(p_slot->data.buffer_free.p_result) =
|
|
nrf_802154_core_notify_buffer_free(p_slot->data.buffer_free.p_data);
|
|
break;
|
|
|
|
case REQ_TYPE_CHANNEL_UPDATE:
|
|
*(p_slot->data.channel_update.p_result) =
|
|
nrf_802154_core_channel_update(p_slot->data.channel_update.req_orig);
|
|
break;
|
|
|
|
case REQ_TYPE_CCA_CFG_UPDATE:
|
|
*(p_slot->data.cca_cfg_update.p_result) = nrf_802154_core_cca_cfg_update();
|
|
break;
|
|
|
|
case REQ_TYPE_RSSI_MEASURE:
|
|
*(p_slot->data.rssi_measure.p_result) = nrf_802154_core_rssi_measure();
|
|
break;
|
|
|
|
case REQ_TYPE_RSSI_GET:
|
|
*(p_slot->data.rssi_get.p_result) =
|
|
nrf_802154_core_last_rssi_measurement_get(p_slot->data.rssi_get.p_rssi);
|
|
break;
|
|
|
|
case REQ_TYPE_ANTENNA_UPDATE:
|
|
*(p_slot->data.antenna_update.p_result) = nrf_802154_core_antenna_update();
|
|
break;
|
|
|
|
#if NRF_802154_DELAYED_TRX_ENABLED
|
|
case REQ_TYPE_TRANSMIT_AT:
|
|
*(p_slot->data.transmit_at.p_result) =
|
|
nrf_802154_delayed_trx_transmit(p_slot->data.transmit_at.p_data,
|
|
p_slot->data.transmit_at.tx_time,
|
|
p_slot->data.transmit_at.p_metadata);
|
|
break;
|
|
|
|
case REQ_TYPE_TRANSMIT_AT_CANCEL:
|
|
*(p_slot->data.transmit_at_cancel.p_result) =
|
|
nrf_802154_delayed_trx_transmit_cancel();
|
|
break;
|
|
|
|
case REQ_TYPE_RECEIVE_AT:
|
|
*(p_slot->data.receive_at.p_result) =
|
|
nrf_802154_delayed_trx_receive(p_slot->data.receive_at.rx_time,
|
|
p_slot->data.receive_at.timeout,
|
|
p_slot->data.receive_at.channel,
|
|
p_slot->data.receive_at.id);
|
|
break;
|
|
|
|
case REQ_TYPE_RECEIVE_AT_CANCEL:
|
|
*(p_slot->data.receive_at_cancel.p_result) =
|
|
nrf_802154_delayed_trx_receive_cancel(p_slot->data.receive_at_cancel.id);
|
|
break;
|
|
|
|
case REQ_TYPE_CSMA_CA_START:
|
|
*(p_slot->data.receive_at_cancel.p_result) =
|
|
nrf_802154_csma_ca_start(p_slot->data.csma_ca_start.p_data,
|
|
p_slot->data.csma_ca_start.p_metadata);
|
|
break;
|
|
#endif // NRF_802154_DELAYED_TRX_ENABLED
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
nrf_802154_queue_pop_commit(&m_requests_queue);
|
|
}
|
|
}
|
|
|
|
void nrf_802154_request_swi_irq_handler(void)
|
|
{
|
|
if (nrf_egu_event_check(NRF_802154_EGU_INSTANCE, REQ_EVENT))
|
|
{
|
|
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, REQ_EVENT);
|
|
|
|
irq_handler_req_event();
|
|
}
|
|
}
|