mbed-os/features/nanostack/nanostack-interface/targets/TARGET_NXP/TARGET_KW41Z/NanostackRfPhyKw41z.cpp

1125 lines
31 KiB
C++

/*
* Copyright (c) 2016-2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_power_mgmt.h"
#include "common_functions.h"
#include "platform/arm_hal_interrupt.h"
#include "platform/arm_hal_phy.h"
#include "NanostackRfPhyKw41z.h"
#include "fsl_xcvr.h"
#define RF_THREAD_STACK_SIZE 1024
static void rf_thread_loop();
Thread rf_thread(osPriorityRealtime, RF_THREAD_STACK_SIZE);
#define PHY_MTU_SIZE 127
#define CRC_LENGTH 0
#define PHY_HEADER_LENGTH 0
#define BM_ZLL_IRQSTS_TMRxMSK (ZLL_IRQSTS_TMR1MSK_MASK | \
ZLL_IRQSTS_TMR2MSK_MASK | \
ZLL_IRQSTS_TMR3MSK_MASK | \
ZLL_IRQSTS_TMR4MSK_MASK)
#define RF_CCA_THRESHOLD 75 /* -75 dBm */
#define gPhyDefaultTxPowerLevel_d (22)
#define gPhyMaxTxPowerLevel_d (32)
#define gCcaED_c (0)
#define gCcaCCA_MODE1_c (1)
#define gPhyTimeMask_c (0x00FFFFFF)
#define KW41Z_SHR_PHY_TIME 12
#define KW41Z_PER_BYTE_TIME 2
#define KW41Z_ACK_WAIT_TIME 54
static int8_t rf_radio_driver_id = -1;
static uint8_t need_ack = 0;
/* PHY states */
typedef enum xcvrState_tag {
gIdle_c,
gRX_c,
gTX_c,
gCCA_c,
gTR_c,
gCCCA_c,
} xcvrState_t;
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol);
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr);
static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr);
static void rf_mac_hw_init(void);
static void rf_mac_ed_state_enable(void);
static void rf_mac_set_pending(uint8_t status);
static void rf_mac_set_shortAddress(uint8_t *valueAddress);
static void rf_mac_set_panId(uint8_t *valueAddress);
static void rf_mac_set_mac64(const uint8_t *valueAddress);
static uint8_t rf_convert_energy_level(uint8_t energyLevel);
static void rf_abort(void);
static void rf_ack_wait_timer_start(uint16_t time);
static void rf_get_timestamp(uint32_t *pRetClk);
static uint32_t rf_get_timeout(void);
static void rf_set_timeout(uint32_t timeout);
static void rf_promiscuous(uint8_t state);
static void handle_IRQ_events(void);
static uint8_t PhyPlmeSetCurrentChannelRequest(uint8_t channel, uint8_t pan);
static void rf_receive(void);
static void rf_handle_rx_end(void);
static uint8_t MAC64_addr_default[8] = {1, 2, 3, 4, 5, 6, 7, 8};
static uint8_t MAC64_addr[8];
static xcvrState_t mPhySeqState;
static uint8_t rf_mac_handle;
static volatile uint8_t rf_ed_value = 0;
static volatile bool rf_ack_pending_state = false;
static volatile bool sleep_blocked = false;
static NanostackRfPhyKw41z *rf = NULL;
#define MAC_PACKET_SIZE 127 //MAX MAC payload is 127 bytes
static uint8_t PHYPAYLOAD[MAC_PACKET_SIZE];
const phy_rf_channel_configuration_s phy_2_4ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
const phy_device_channel_page_s phy_channel_pages[] = {
{CHANNEL_PAGE_0, &phy_2_4ghz},
{CHANNEL_PAGE_0, NULL}
};
static phy_device_driver_s device_driver = {
PHY_LINK_15_4_2_4GHZ_TYPE,
PHY_LAYER_PAYLOAD_DATA_FLOW,
MAC64_addr,
PHY_MTU_SIZE,
(char *)"NXP kw41z",
CRC_LENGTH,
PHY_HEADER_LENGTH,
&rf_interface_state_control,
&rf_start_cca,
&rf_address_write,
&rf_extension,
phy_channel_pages,
NULL,
NULL,
NULL,
NULL
};
static void rf_thread_loop()
{
for (;;) {
ThisThread::flags_wait_all(1);
platform_enter_critical();
handle_IRQ_events();
platform_exit_critical();
NVIC_ClearPendingIRQ(Radio_1_IRQn);
NVIC_EnableIRQ(Radio_1_IRQn);
}
}
static int8_t rf_device_register(void)
{
if (rf_radio_driver_id < 0) {
rf_mac_hw_init();
/**
* Read factory stored Mac address to RAM
*/
common_write_32_bit(ZLL->MACLONGADDRS0_MSB, MAC64_addr);
common_write_32_bit(ZLL->MACLONGADDRS0_LSB, MAC64_addr + 4);
rf_radio_driver_id = arm_net_phy_register(&device_driver);
}
return rf_radio_driver_id;
}
static void rf_device_unregister(void)
{
arm_net_phy_unregister(rf_radio_driver_id);
if (sleep_blocked) {
sleep_manager_unlock_deep_sleep();
sleep_blocked = false;
}
}
/*
* \brief Function enables/disables Rx promiscuous mode.
*
* \param state of XCVR promiscuous mode
*
* \return none
*/
static void rf_promiscuous(uint8_t state)
{
if (state) {
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_PROMISCUOUS_MASK;
/* FRM_VER[11:8] = b1111. Any FrameVersion accepted */
ZLL->RX_FRAME_FILTER |= (ZLL_RX_FRAME_FILTER_FRM_VER_FILTER_MASK |
ZLL_RX_FRAME_FILTER_ACK_FT_MASK |
ZLL_RX_FRAME_FILTER_NS_FT_MASK);
} else {
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_PROMISCUOUS_MASK;
/* FRM_VER[11:8] = b0011. Accept FrameVersion 0 and 1 packets, reject all others */
/* Beacon, Data and MAC command frame types accepted */
ZLL->RX_FRAME_FILTER &= ~(ZLL_RX_FRAME_FILTER_FRM_VER_FILTER_MASK |
ZLL_RX_FRAME_FILTER_ACK_FT_MASK |
ZLL_RX_FRAME_FILTER_NS_FT_MASK |
ZLL_RX_FRAME_FILTER_ACTIVE_PROMISCUOUS_MASK);
ZLL->RX_FRAME_FILTER |= ZLL_RX_FRAME_FILTER_FRM_VER_FILTER(3);
}
}
static void rf_mac_set_pending(uint8_t status)
{
uint32_t reg = ZLL->SAM_TABLE;
/* Disable the Source Address Matching feature and set FP manually */
reg |= ZLL_SAM_TABLE_ACK_FRM_PND_CTRL_MASK;
if (status) {
reg |= ZLL_SAM_TABLE_ACK_FRM_PND_MASK;
rf_ack_pending_state = true;
} else {
reg &= ~ZLL_SAM_TABLE_ACK_FRM_PND_MASK;
rf_ack_pending_state = false;
}
ZLL->SAM_TABLE = reg;
}
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
{
platform_enter_critical();
switch (new_state) {
/*Reset PHY driver and set to idle*/
case PHY_INTERFACE_RESET:
rf_abort();
if (sleep_blocked) {
sleep_manager_unlock_deep_sleep();
sleep_blocked = false;
}
break;
/*Disable PHY Interface driver*/
case PHY_INTERFACE_DOWN:
rf_abort();
if (sleep_blocked) {
sleep_manager_unlock_deep_sleep();
sleep_blocked = false;
}
break;
/*Enable PHY Interface driver*/
case PHY_INTERFACE_UP:
if (PhyPlmeSetCurrentChannelRequest(rf_channel, 0)) {
return 1;
}
if (!sleep_blocked) {
/* Disable enter to deep sleep when transfer active */
sleep_manager_lock_deep_sleep();
sleep_blocked = true;
}
rf_receive();
break;
/*Enable wireless interface ED scan mode*/
case PHY_INTERFACE_RX_ENERGY_STATE:
if (PhyPlmeSetCurrentChannelRequest(rf_channel, 0)) {
return 1;
}
if (!sleep_blocked) {
/* Disable enter to deep sleep when transfer active */
sleep_manager_lock_deep_sleep();
sleep_blocked = true;
}
rf_abort();
rf_mac_ed_state_enable();
break;
case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */
rf_promiscuous(1);
if (PhyPlmeSetCurrentChannelRequest(rf_channel, 0)) {
return 1;
}
if (!sleep_blocked) {
/* Disable enter to deep sleep when transfer active */
sleep_manager_lock_deep_sleep();
sleep_blocked = true;
}
rf_receive();
break;
}
platform_exit_critical();
return 0;
}
/*
* \brief Function forces the XCVR to Idle state.
*
* \param none
*
* \return none
*/
static void rf_abort(void)
{
/* Mask XCVR irq */
NVIC_DisableIRQ(Radio_1_IRQn);
mPhySeqState = gIdle_c;
/* Mask SEQ interrupt */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_SEQMSK_MASK;
/* Disable timer trigger (for scheduled XCVSEQ) */
if (ZLL->PHY_CTRL & ZLL_PHY_CTRL_TMRTRIGEN_MASK) {
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMRTRIGEN_MASK;
/* give the FSM enough time to start if it was triggered */
while ((XCVR_MISC->XCVR_CTRL & XCVR_CTRL_XCVR_STATUS_TSM_COUNT_MASK) == 0) {}
}
/* If XCVR is not idle, abort current SEQ */
if (ZLL->PHY_CTRL & ZLL_PHY_CTRL_XCVSEQ_MASK) {
/* Abort current SEQ */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_XCVSEQ_MASK;
/* Wait for Sequence Idle (if not already) */
while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {}
}
/* Stop timers */
ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR1CMP_EN_MASK |
ZLL_PHY_CTRL_TMR2CMP_EN_MASK |
ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
ZLL_PHY_CTRL_TC3TMOUT_MASK);
/* clear all IRQ bits to avoid unexpected interrupts */
ZLL->IRQSTS = ZLL->IRQSTS;
/* Unmask XCVR irq */
NVIC_EnableIRQ(Radio_1_IRQn);
}
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
{
uint32_t reg, tx_len;
uint32_t irqSts;
volatile uint8_t *pPB;
uint8_t i;
uint32_t tx_warmup_time;
platform_enter_critical();
if (mPhySeqState == gRX_c) {
rf_abort();
}
/* Check if transmitter is busy*/
if (mPhySeqState != gIdle_c) {
platform_exit_critical();
/*Return busy*/
return -1;
}
/*Store TX handle*/
rf_mac_handle = tx_handle;
/* Check if transmitted data needs to be acked */
need_ack = (*data_ptr & 0x20) == 0x20;
/* Load data into Packet Buffer */
pPB = (uint8_t *)ZLL->PKT_BUFFER_TX;
tx_len = data_length + 2;
*pPB++ = tx_len; /* including 2 bytes of FCS */
for (i = 0; i < data_length; i++) {
*pPB++ = *data_ptr++;
}
reg = ZLL->PHY_CTRL;
/* Perform CCA before TX */
reg |= ZLL_PHY_CTRL_CCABFRTX_MASK;
/* Set CCA mode 1 */
reg &= ~(ZLL_PHY_CTRL_CCATYPE_MASK);
reg |= ZLL_PHY_CTRL_CCATYPE(gCcaCCA_MODE1_c);
ZLL->PHY_CTRL = reg;
/* Perform TxRxAck sequence if required by phyTxMode */
if (need_ack) {
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_RXACKRQD_MASK;
mPhySeqState = gTR_c;
} else {
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_RXACKRQD_MASK;
mPhySeqState = gTX_c;
}
/* Ensure that no spurious interrupts are raised */
irqSts = ZLL->IRQSTS;
irqSts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
ZLL->IRQSTS = irqSts;
tx_warmup_time = (XCVR_TSM->END_OF_SEQ & XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_MASK) >>
XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_SHIFT;
/* Compute warmup times (scaled to 16us) */
if (tx_warmup_time & 0x0F) {
tx_warmup_time = 1 + (tx_warmup_time >> 4);
} else {
tx_warmup_time = tx_warmup_time >> 4;
}
if (need_ack) {
rf_ack_wait_timer_start(tx_warmup_time + KW41Z_SHR_PHY_TIME +
tx_len * KW41Z_PER_BYTE_TIME + 10 + KW41Z_ACK_WAIT_TIME);
}
/* Unmask SEQ interrupt */
ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_SEQMSK_MASK);
/* Start the TX / TRX */
reg = ZLL->PHY_CTRL;
reg &= ~(ZLL_PHY_CTRL_XCVSEQ_MASK);
reg |= mPhySeqState;
ZLL->PHY_CTRL = reg;
platform_exit_critical();
/*Return success*/
return 0;
}
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
{
int8_t ret_val = 0;
platform_enter_critical();
switch (address_type) {
case PHY_MAC_64BIT:
rf_mac_set_mac64(address_ptr);
break;
/*Set 16-bit address*/
case PHY_MAC_16BIT:
rf_mac_set_shortAddress(address_ptr);
break;
/*Set PAN Id*/
case PHY_MAC_PANID:
rf_mac_set_panId(address_ptr);
break;
default:
ret_val = -1;
}
platform_exit_critical();
return ret_val;
}
static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
{
int ret_value = 0;
platform_enter_critical();
switch (extension_type) {
case PHY_EXTENSION_CTRL_PENDING_BIT: /**< Control MAC pending bit for indirect data. */
rf_mac_set_pending(*data_ptr);
break;
/* Return frame Auto Ack frame pending status */
case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: {
*data_ptr = rf_ack_pending_state;
break;
}
case PHY_EXTENSION_SET_CHANNEL: /**< Net library channel set. */
break;
case PHY_EXTENSION_READ_CHANNEL_ENERGY: /**< RF interface ED scan energy read. */
*data_ptr = rf_ed_value;
break;
case PHY_EXTENSION_READ_LINK_STATUS: /**< Net library could read link status. */
case PHY_EXTENSION_CONVERT_SIGNAL_INFO: /**< Convert signal info. */
default:
ret_value = -1;
}
platform_exit_critical();
return ret_value;
}
/*
* \brief Function converts the energy level from dBm to a 0-255 value.
*
* \param energyLevel in dBm
*
* \return energy level (0-255)
*/
static uint8_t rf_convert_energy_level(uint8_t energyLevel)
{
int32_t temp = (int8_t)energyLevel;
if (temp <= -82) {
temp = 0x00;
} else if (temp >= -3) {
temp = 0xFF;
} else {
/* Convert energy level from dbm into a 0x00-0xFF value */
temp = (255 * temp + 20910) / 79;
}
return (uint8_t)temp;
}
/**
* SET MAC 16 address to Register
*/
static void rf_mac_set_shortAddress(uint8_t *valueAddress)
{
ZLL->MACSHORTADDRS0 &= ~ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK;
ZLL->MACSHORTADDRS0 |= ZLL_MACSHORTADDRS0_MACSHORTADDRS0(common_read_16_bit(valueAddress));
}
/**
* SET PAN-ID to Register
*/
static void rf_mac_set_panId(uint8_t *valueAddress)
{
ZLL->MACSHORTADDRS0 &= ~ZLL_MACSHORTADDRS0_MACPANID0_MASK;
ZLL->MACSHORTADDRS0 |= ZLL_MACSHORTADDRS0_MACPANID0(common_read_16_bit(valueAddress));
}
/**
* SET MAC64 address to register
*/
static void rf_mac_set_mac64(const uint8_t *valueAddress)
{
ZLL->MACLONGADDRS0_MSB = common_read_32_bit(valueAddress);
valueAddress += 4;
ZLL->MACLONGADDRS0_LSB = common_read_32_bit(valueAddress);
}
static void PhyPlmeSetPwrLevelRequest(uint8_t pwrStep)
{
/* Do not exceed the Tx power limit for the current channel */
if (pwrStep > gPhyMaxTxPowerLevel_d) {
pwrStep = gPhyMaxTxPowerLevel_d;
}
if (pwrStep > 2) {
pwrStep = (pwrStep << 1) - 2;
}
ZLL->PA_PWR = pwrStep;
}
static uint8_t PhyPlmeGetPwrLevelRequest(void)
{
uint8_t pwrStep = (uint8_t)ZLL->PA_PWR;
if (pwrStep > 2) {
pwrStep = (pwrStep + 2) >> 1;
}
return pwrStep;
}
static uint8_t PhyPlmeSetCurrentChannelRequest(uint8_t channel, uint8_t pan)
{
if ((channel < 11) || (channel > 26)) {
return 1;
}
if (!pan) {
ZLL->CHANNEL_NUM0 = channel;
} else {
ZLL->CHANNEL_NUM1 = channel;
}
/* Make sure the current Tx power doesn't exceed the Tx power limit for the new channel */
if (PhyPlmeGetPwrLevelRequest() > gPhyMaxTxPowerLevel_d) {
PhyPlmeSetPwrLevelRequest(gPhyMaxTxPowerLevel_d);
}
return 0;
}
/*
* Function is a RF interrupt vector.
*/
static void PHY_InterruptHandler(void)
{
/* Disable and clear transceiver(IRQ_B) interrupt */
NVIC_DisableIRQ(Radio_1_IRQn);
rf_thread.flags_set(1);
}
static void PhyIsrSeqCleanup(void)
{
uint32_t irqStatus;
/* Set the PHY sequencer back to IDLE */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_XCVSEQ_MASK;
/* Mask SEQ, RX, TX and CCA interrupts */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
ZLL_PHY_CTRL_SEQMSK_MASK;
while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {}
irqStatus = ZLL->IRQSTS;
/* Mask TMR3 interrupt */
irqStatus |= ZLL_IRQSTS_TMR3MSK_MASK;
/* Clear transceiver interrupts except TMRxIRQ */
irqStatus &= ~(ZLL_IRQSTS_TMR1IRQ_MASK |
ZLL_IRQSTS_TMR2IRQ_MASK |
ZLL_IRQSTS_TMR3IRQ_MASK |
ZLL_IRQSTS_TMR4IRQ_MASK);
ZLL->IRQSTS = irqStatus;
}
static void PhyIsrTimeoutCleanup(void)
{
uint32_t irqStatus;
/* Set the PHY sequencer back to IDLE and disable TMR3 comparator and timeout */
ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
ZLL_PHY_CTRL_TC3TMOUT_MASK |
ZLL_PHY_CTRL_XCVSEQ_MASK);
/* Mask SEQ, RX, TX and CCA interrupts */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
ZLL_PHY_CTRL_SEQMSK_MASK;
while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {}
irqStatus = ZLL->IRQSTS;
/* Mask TMR3 interrupt */
irqStatus |= ZLL_IRQSTS_TMR3MSK_MASK;
/* Clear transceiver interrupts except TMR1IRQ and TMR4IRQ. */
irqStatus &= ~(ZLL_IRQSTS_TMR1IRQ_MASK |
ZLL_IRQSTS_TMR4IRQ_MASK);
ZLL->IRQSTS = irqStatus;
/* The packet was transmitted successfully, but no ACK was received */
if (device_driver.phy_tx_done_cb) {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle, PHY_LINK_TX_SUCCESS, 1, 1);
}
}
/*
* \brief Function get the time-out for the current sequence.
*
* \return sequence time-out value
*/
static uint32_t rf_get_timeout(void)
{
return ZLL->T3CMP;
}
/*
* \brief Function set a time-out to an XCVR sequence.
*
* \param pEndTime sequence time-out value [symbols]
*
* \return none
*/
static void rf_set_timeout(uint32_t pEndTime)
{
uint32_t irqsts;
platform_enter_critical();
/* disable TMR3 compare */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
ZLL->T3CMP = pEndTime & ZLL_T3CMP_T3CMP_MASK;
/* acknowledge TMR3 IRQ */
irqsts = ZLL->IRQSTS & BM_ZLL_IRQSTS_TMRxMSK;
irqsts |= ZLL_IRQSTS_TMR3IRQ_MASK;
ZLL->IRQSTS = irqsts;
/* enable TMR3 compare */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
/* enable autosequence stop by TC3 match */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TC3TMOUT_MASK;
platform_exit_critical();
}
/**
* Call this only One time
*/
static void rf_mac_hw_init(void)
{
xcvrStatus_t xcvrStatus;
uint32_t phyReg;
/* The data rate argument only matters when GFSK/MSK protocol is selected */
xcvrStatus = XCVR_Init(ZIGBEE_MODE, DR_500KBPS);
if (xcvrStatus != gXcvrSuccess_c) {
return;
}
mPhySeqState = gIdle_c;
/* Enable 16 bit mode for TC2 - TC2 prime EN, disable all timers,
enable AUTOACK, mask all interrupts */
ZLL->PHY_CTRL = (gCcaCCA_MODE1_c << ZLL_PHY_CTRL_CCATYPE_SHIFT) |
ZLL_PHY_CTRL_TC2PRIME_EN_MASK |
ZLL_PHY_CTRL_TSM_MSK_MASK |
ZLL_PHY_CTRL_WAKE_MSK_MASK |
ZLL_PHY_CTRL_CRC_MSK_MASK |
ZLL_PHY_CTRL_PLL_UNLOCK_MSK_MASK |
ZLL_PHY_CTRL_FILTERFAIL_MSK_MASK |
ZLL_PHY_CTRL_RX_WMRK_MSK_MASK |
ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
ZLL_PHY_CTRL_SEQMSK_MASK |
ZLL_PHY_CTRL_AUTOACK_MASK |
ZLL_PHY_CTRL_TRCV_MSK_MASK;
/* Clear all PP IRQ bits to avoid unexpected interrupts immediately after init
disable all timer interrupts */
ZLL->IRQSTS = ZLL->IRQSTS;
/* Clear HW indirect queue */
ZLL->SAM_TABLE |= ZLL_SAM_TABLE_INVALIDATE_ALL_MASK;
/* Frame Filtering
FRM_VER[7:6] = b11. Accept FrameVersion 0 and 1 packets, reject all others */
ZLL->RX_FRAME_FILTER &= ~ZLL_RX_FRAME_FILTER_FRM_VER_FILTER_MASK;
ZLL->RX_FRAME_FILTER = ZLL_RX_FRAME_FILTER_FRM_VER_FILTER(3) |
ZLL_RX_FRAME_FILTER_CMD_FT_MASK |
ZLL_RX_FRAME_FILTER_DATA_FT_MASK |
ZLL_RX_FRAME_FILTER_BEACON_FT_MASK;
/* Set prescaller to obtain 1 symbol (16us) timebase */
ZLL->TMR_PRESCALE = 0x05;
/* Set CCA threshold to -75 dBm */
ZLL->CCA_LQI_CTRL &= ~ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK;
ZLL->CCA_LQI_CTRL |= ZLL_CCA_LQI_CTRL_CCA1_THRESH(RF_CCA_THRESHOLD);
/* Set the default power level */
PhyPlmeSetPwrLevelRequest(gPhyDefaultTxPowerLevel_d);
/* Adjust ACK delay to fulfill the 802.15.4 turnaround requirements */
ZLL->ACKDELAY &= ~ZLL_ACKDELAY_ACKDELAY_MASK;
ZLL->ACKDELAY |= ZLL_ACKDELAY_ACKDELAY(-8);
/* Adjust LQI compensation */
ZLL->CCA_LQI_CTRL &= ~ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP_MASK;
ZLL->CCA_LQI_CTRL |= ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP(96);
/* Enable the RxWatermark IRQ */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_RX_WMRK_MSK_MASK;
/* Set Rx watermark level */
ZLL->RX_WTR_MARK = 0;
/* Set default channels */
PhyPlmeSetCurrentChannelRequest(0x0B, 0); /* 2405 MHz */
PhyPlmeSetCurrentChannelRequest(0x0B, 1); /* 2405 MHz */
/* DSM settings */
phyReg = (RSIM->RF_OSC_CTRL & RSIM_RF_OSC_CTRL_BB_XTAL_READY_COUNT_SEL_MASK) >>
RSIM_RF_OSC_CTRL_BB_XTAL_READY_COUNT_SEL_SHIFT;
phyReg = (1024U << phyReg) / (SystemCoreClock / 32768) + 1;
RSIM->DSM_OSC_OFFSET = phyReg;
osStatus status = rf_thread.start(mbed::callback(rf_thread_loop));
MBED_ASSERT(status == osOK);
/** Clear and enable MAC IRQ at task level, when scheduler is on. */
InstallIRQHandler((IRQn_Type)Radio_1_IRQn, (uint32_t)PHY_InterruptHandler);
/* Unmask Transceiver Global Interrupts */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TRCV_MSK_MASK;
NVIC_ClearPendingIRQ(Radio_1_IRQn);
NVIC_EnableIRQ(Radio_1_IRQn);
}
/*
* \brief Function reads a time-stamp value from XCVR [symbols]
*
* \param pEndTime pointer to location where time-stamp will be stored
*
* \return none
*/
static void rf_get_timestamp(uint32_t *pRetClk)
{
if (NULL == pRetClk) {
return;
}
platform_enter_critical();
*pRetClk = 0;
*pRetClk = ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
platform_exit_critical();
}
/*
* \brief Function starts the ACK wait time-out.
*
* \param slots The ACK wait time-out in [symbols]
*
* \return none
*/
static void rf_ack_wait_timer_start(uint16_t time)
{
uint32_t timestamp, t;
rf_get_timestamp(&timestamp);
t = (rf_get_timeout() - timestamp) & gPhyTimeMask_c;
if (t > 1) {
timestamp += time;
rf_set_timeout(timestamp);
}
}
/*
* \brief Function sets the RF in RX state.
*
* \param none
*
* \return none
*/
static void rf_receive(void)
{
uint32_t irqSts;
/* RX can start only from Idle state */
if (mPhySeqState != gIdle_c) {
rf_abort();
}
mPhySeqState = gRX_c;
/* Ensure that no spurious interrupts are raised, but do not change TMR1 and TMR4 IRQ status */
irqSts = ZLL->IRQSTS;
irqSts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
ZLL->IRQSTS = irqSts;
/* unmask SEQ interrupt */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_SEQMSK_MASK;
/* Start the RX sequence */
ZLL->PHY_CTRL |= gRX_c;
}
static void rf_mac_ed_state_enable(void)
{
uint32_t ccaMode, irqSts;
mPhySeqState = gCCA_c;
/* Switch to ED mode */
ccaMode = (ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCATYPE_MASK) >> ZLL_PHY_CTRL_CCATYPE_SHIFT;
if (ccaMode != gCcaED_c) {
ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_CCATYPE_MASK);
}
/* Ensure that no spurious interrupts are raised(do not change TMR1 and TMR4 IRQ status) */
irqSts = ZLL->IRQSTS;
irqSts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
ZLL->IRQSTS = irqSts;
/* Unmask SEQ interrupt */
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_SEQMSK_MASK;
/* start ED sequence */
ZLL->PHY_CTRL |= gCCA_c;
}
/*
* \brief Function is a call back for TX end interrupt.
*
* \param none
*
* \return none
*/
static void rf_handle_tx_end(bool framePending)
{
/*Start receiver*/
rf_receive();
if (!device_driver.phy_tx_done_cb) {
return;
}
/*Call PHY TX Done API*/
if (need_ack) {
if (framePending) {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle, PHY_LINK_TX_DONE_PENDING, 1, 1);
} else {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle, PHY_LINK_TX_DONE, 1, 1);
}
} else {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle, PHY_LINK_TX_SUCCESS, 1, 1);
}
}
/*
* \brief Function converts LQI into RSSI.
*
* \param LQI
*
* \return RSSI
*/
static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi)
{
int32_t rssi = (36 * lqi - 9836) / 109;
return (int8_t)rssi;
}
/*
* \brief Function scale the LQI value reported by RF into a 0-255 value.
*
* \param hwLqi - the LQI value reported by RF
*
* \return scaled LQI
*/
static uint8_t rf_convert_LQI(uint8_t hwLqi)
{
if (hwLqi >= 220) {
return 255;
} else {
return (51 * hwLqi) / 44;
}
}
/*
* \brief Function is a call back for RX end interrupt.
*
* \param none
*
* \return none
*/
static void rf_handle_rx_end(void)
{
uint8_t rf_lqi = (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_LQI_VALUE_MASK) >>
ZLL_LQI_AND_RSSI_LQI_VALUE_SHIFT;
int8_t rf_rssi = 0;
uint8_t len;
uint8_t i;
volatile uint8_t *pPB;
len = (ZLL->IRQSTS & ZLL_IRQSTS_RX_FRAME_LENGTH_MASK) >> ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT; /* Including FCS (2 bytes) */
/* Excluding FCS (2 bytes) */
len -= 2;
/*Check the length is valid*/
if (len > 1 && len < MAC_PACKET_SIZE) {
rf_lqi = rf_convert_LQI(rf_lqi);
rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi);
/* Load data from Packet Buffer */
pPB = (uint8_t *)ZLL->PKT_BUFFER_RX;
for (i = 0; i < len; i++) {
PHYPAYLOAD[i] = *pPB++;
}
/* Start receiver */
rf_receive();
if (device_driver.phy_rx_cb) {
device_driver.phy_rx_cb(PHYPAYLOAD, len, rf_lqi, rf_rssi, rf_radio_driver_id);
}
} else {
/* Start receiver */
rf_receive();
}
}
static void handle_IRQ_events(void)
{
uint8_t xcvseqCopy;
uint32_t irqStatus;
/* Read current XCVRSEQ and interrupt status */
xcvseqCopy = ZLL->PHY_CTRL & ZLL_PHY_CTRL_XCVSEQ_MASK;
irqStatus = ZLL->IRQSTS;
/* Clear all xcvr interrupts */
ZLL->IRQSTS = irqStatus;
/* Filter Fail IRQ */
if (irqStatus & ZLL_IRQSTS_FILTERFAIL_IRQ_MASK) {
} else {
/* Rx Watermark IRQ */
if ((!(ZLL->PHY_CTRL & ZLL_PHY_CTRL_RX_WMRK_MSK_MASK)) &&
(irqStatus & ZLL_IRQSTS_RXWTRMRKIRQ_MASK)) {
uint32_t rx_len = (irqStatus & ZLL_IRQSTS_RX_FRAME_LENGTH_MASK) >> ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT;
/* Convert to symbols and add IFS and ACK duration */
rx_len = rx_len * 2 + 12 + 22 + 2;
rf_ack_wait_timer_start(rx_len);
}
}
/* Sequencer interrupt, the autosequence has completed */
if (irqStatus & ZLL_IRQSTS_SEQIRQ_MASK) {
/* XCVR will be set to Idle */
mPhySeqState = gIdle_c;
/* PLL unlock, the autosequence has been aborted due to PLL unlock */
if (irqStatus & ZLL_IRQSTS_PLL_UNLOCK_IRQ_MASK) {
PhyIsrSeqCleanup();
/* Start receiver */
rf_receive();
}
/* TMR3 timeout, the autosequence has been aborted due to TMR3 timeout */
else if ((irqStatus & ZLL_IRQSTS_TMR3IRQ_MASK) &&
(!(irqStatus & ZLL_IRQSTS_RXIRQ_MASK)) &&
(xcvseqCopy != gTX_c)) {
PhyIsrTimeoutCleanup();
/* Start receiver */
rf_receive();
} else {
PhyIsrSeqCleanup();
switch (xcvseqCopy) {
case gTX_c:
if ((ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCABFRTX_MASK) &&
(irqStatus & ZLL_IRQSTS_CCA_MASK)) {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle,
PHY_LINK_CCA_FAIL, 1, 1);
} else {
rf_handle_tx_end(false);
}
break;
case gTR_c:
if ((ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCABFRTX_MASK) &&
(irqStatus & ZLL_IRQSTS_CCA_MASK)) {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle,
PHY_LINK_CCA_FAIL, 1, 1);
} else {
rf_handle_tx_end((irqStatus & ZLL_IRQSTS_RX_FRM_PEND_MASK) > 0);
}
break;
case gRX_c:
rf_handle_rx_end();
break;
case gCCA_c:
rf_ed_value = rf_convert_energy_level((ZLL->LQI_AND_RSSI &
ZLL_LQI_AND_RSSI_CCA1_ED_FNL_MASK) >>
ZLL_LQI_AND_RSSI_CCA1_ED_FNL_SHIFT);
break;
default:
break;
}
}
}
}
NanostackRfPhyKw41z::NanostackRfPhyKw41z()
{
memcpy(MAC64_addr, MAC64_addr_default, sizeof(MAC64_addr));
}
NanostackRfPhyKw41z::~NanostackRfPhyKw41z()
{
// Do nothing
}
int8_t NanostackRfPhyKw41z::rf_register()
{
platform_enter_critical();
if (rf != NULL) {
platform_exit_critical();
error("Multiple registrations of NanostackRfPhyKw41z not supported");
return -1;
}
rf = this;
int8_t radio_id = rf_device_register();
if (radio_id < 0) {
rf = NULL;
}
platform_exit_critical();
return radio_id;
}
void NanostackRfPhyKw41z::rf_unregister()
{
platform_enter_critical();
if (rf != this) {
platform_exit_critical();
return;
}
rf_device_unregister();
rf = NULL;
platform_exit_critical();
}
void NanostackRfPhyKw41z::get_mac_address(uint8_t *mac)
{
platform_enter_critical();
memcpy((void *)mac, (void *)MAC64_addr, sizeof(MAC64_addr));
platform_exit_critical();
}
void NanostackRfPhyKw41z::set_mac_address(uint8_t *mac)
{
platform_enter_critical();
if (NULL != rf) {
error("NanostackRfPhyKw41z cannot change mac address when running");
platform_exit_critical();
return;
}
memcpy((void *)MAC64_addr, (void *)mac, sizeof(MAC64_addr));
platform_exit_critical();
}
NanostackRfPhy &NanostackRfPhy::get_default_instance()
{
static NanostackRfPhyKw41z rf_phy;
return rf_phy;
}