blob: b0c59e17bf18a38728c727a0472f1fda4235dd68 [file] [log] [blame]
/* Copyright (c) 2017, Nordic Semiconductor ASA
* All rights reserved.
*
* 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 procedures to set pending bit in nRF 802.15.4 radio driver.
*
*/
#include "nrf_drv_radio802154_ack_pending_bit.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_drv_radio802154_config.h"
#include "nrf_drv_radio802154_const.h"
#include "hal/nrf_radio.h"
/// Maximum number of Short Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_SHORT_ADDRESSES RADIO_PENDING_SHORT_ADDRESSES
/// Maximum number of Extended Addresses of nodes for which there is pending data in buffer.
#define NUM_PENDING_EXTENDED_ADDRESSES RADIO_PENDING_EXTENDED_ADDRESSES
/// Value used to mark Short Address as unused.
#define UNUSED_PENDING_SHORT_ADDRESS ((uint8_t [SHORT_ADDRESS_SIZE]) {0xff, 0xff})
/// Value used to mark Extended Address as unused.
#define UNUSED_PENDING_EXTENDED_ADDRESS ((uint8_t [EXTENDED_ADDRESS_SIZE]) {0})
/// If pending bit in ACK frame should be set to valid or default value.
static bool m_setting_pending_bit_enabled;
/// Array of Short Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_short[NUM_PENDING_SHORT_ADDRESSES][SHORT_ADDRESS_SIZE];
/// Array of Extended Addresses of nodes for which there is pending data in the buffer.
static uint8_t m_pending_extended[NUM_PENDING_EXTENDED_ADDRESSES][EXTENDED_ADDRESS_SIZE];
void nrf_drv_radio802154_ack_pending_bit_init(void)
{
memset(m_pending_extended, 0, sizeof(m_pending_extended));
memset(m_pending_short, 0xff, sizeof(m_pending_short));
m_setting_pending_bit_enabled = true;
}
void nrf_drv_radio802154_ack_pending_bit_set(bool enabled)
{
m_setting_pending_bit_enabled = enabled;
}
bool nrf_drv_radio802154_ack_pending_bit_for_addr_set(const uint8_t * p_addr, bool extended)
{
uint8_t * p_empty_slot = NULL;
if (extended)
{
for (uint32_t i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_extended[i], p_addr, sizeof(m_pending_extended[i])))
{
return true;
}
if (0 == memcmp(m_pending_extended[i], UNUSED_PENDING_EXTENDED_ADDRESS, sizeof(m_pending_extended[i])))
{
p_empty_slot = m_pending_extended[i];
}
}
if (p_empty_slot != NULL)
{
memcpy(p_empty_slot, p_addr, EXTENDED_ADDRESS_SIZE);
return true;
}
}
else
{
for (uint32_t i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_short[i], p_addr, sizeof(m_pending_short[i])))
{
return true;
}
if (0 == memcmp(m_pending_short[i], UNUSED_PENDING_SHORT_ADDRESS, sizeof(m_pending_short[i])))
{
p_empty_slot = m_pending_short[i];
}
}
if (p_empty_slot != NULL)
{
memcpy(p_empty_slot, p_addr, SHORT_ADDRESS_SIZE);
return true;
}
}
return false;
}
bool nrf_drv_radio802154_ack_pending_bit_for_addr_clear(const uint8_t * p_addr, bool extended)
{
bool result = false;
if (extended)
{
for (uint32_t i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_extended[i], p_addr, sizeof(m_pending_extended[i])))
{
memset(m_pending_extended[i], 0, sizeof(m_pending_extended[i]));
result = true;
}
}
}
else
{
for (uint32_t i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (0 == memcmp(m_pending_short[i], p_addr, sizeof(m_pending_short[i])))
{
memset(m_pending_short[i], 0xff, sizeof(m_pending_short[i]));
result = true;
}
}
}
return result;
}
void nrf_drv_radio802154_ack_pending_bit_for_addr_reset(bool extended)
{
if (extended)
{
memset(m_pending_extended, 0, sizeof(m_pending_extended));
}
else
{
memset(m_pending_short, 0xff, sizeof(m_pending_short));
}
}
bool nrf_drv_radio802154_ack_pending_bit_should_be_set(const uint8_t * p_psdu)
{
const uint8_t * p_src_addr;
uint32_t i;
// If automatic setting of pending bit in ACK frames is disabled the pending bit is always set.
if (!m_setting_pending_bit_enabled)
{
return true;
}
switch (p_psdu[DEST_ADDR_TYPE_OFFSET] & DEST_ADDR_TYPE_MASK)
{
case DEST_ADDR_TYPE_SHORT:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_SHORT_DST];
break;
case DEST_ADDR_TYPE_EXTENDED:
p_src_addr = &p_psdu[SRC_ADDR_OFFSET_EXTENDED_DST];
break;
default:
return true;
}
if (0 == (p_psdu[PAN_ID_COMPR_OFFSET] & PAN_ID_COMPR_MASK))
{
p_src_addr += 2;
}
switch (p_psdu[SRC_ADDR_TYPE_OFFSET] & SRC_ADDR_TYPE_MASK)
{
case SRC_ADDR_TYPE_SHORT:
for (i = 0; i < NUM_PENDING_SHORT_ADDRESSES; i++)
{
if (nrf_radio_state_get() != NRF_RADIO_STATE_TX_RU)
{
break;
}
if (0 == memcmp(p_src_addr, m_pending_short[i], sizeof(m_pending_short[i])))
{
return true;
}
}
break;
case SRC_ADDR_TYPE_EXTENDED:
for (i = 0; i < NUM_PENDING_EXTENDED_ADDRESSES; i++)
{
if (nrf_radio_state_get() != NRF_RADIO_STATE_TX_RU)
{
break;
}
if (0 == memcmp(p_src_addr, m_pending_extended[i], sizeof(m_pending_extended[i])))
{
return true;
}
}
break;
default:
return true;
}
return false;
}