Add ncs36510 RF phy

Check in the RF phy for the ncs36510. Note that the RF phy is included
in the built when nanostack is included since the phy is specific to
nanostack.
pull/2916/head
Russ Butler 2016-10-04 14:13:06 -05:00
parent cb9a4b124b
commit 1aec3700de
2 changed files with 943 additions and 0 deletions

View File

@ -0,0 +1,910 @@
/*
* Copyright (c) 2016, ARM Limited, All Rights Reserved
*/
#include "ns_types.h"
#include <string.h>
#include "common_functions.h"
#include "randLIB.h"
#include "platform/arm_hal_interrupt.h"
#include "platform/arm_hal_phy.h"
#include "NanostackRfPhyNcs36510.h"
extern "C" {
#include "TARGET_NCS36510/memory_map.h"
#include "TARGET_NCS36510/clock.h"
#include "TARGET_NCS36510/ticker.h"
#include "TARGET_NCS36510/rfAna.h"
}
#include "cmsis_os.h"
#ifdef MBED_CONF_RTOS_PRESENT
#include "cmsis.h"
#include "cmsis_os.h"
#define RF_THREAD_STACK_SIZE 1024
#define SIGNAL_COUNT_RADIO 1
static void rf_thread_loop(const void *arg);
static osThreadDef(rf_thread_loop, osPriorityRealtime, /*1,*/ RF_THREAD_STACK_SIZE);
static osThreadId rf_thread_id;
#endif
#define PHY_MTU_SIZE 127
#define CRC_LENGTH 0
#define PHY_HEADER_LENGTH 0
/**
* MAC status code bit definition
*/
#define MAC_STATUS_SUCCESS (0x0) /**< Success */
#define MAC_STATUS_TIMEOUT (0x1) /**< Time out */
#define MAC_STATUS_BUSY (0x2) /**< Channel Busy */
#define MAC_STATUS_CRCFAIL (0x3) /**< CRC Failed */
#define MAC_STATUS_NOACK (0x5) /**< No ACK */
#define MAC_STATUS_UNLOCK (0x6) /**< PLL unlocked */
#define MAC_STATUS_BADSTART (0x7) /**< Bad Start */
#define MAC_STATUS_RXACK_PENDING (0x8) /**< ACK frame was received with the Pending bit set */
#define MAC_STATUS_TXACK_PENDING (0x9) /**< ACK frame was transmitted with the Pending bit set */
#define MAC_STATUS_FAIL_FILTER (0xA) /**< One or more frame filtering tests has failed */
#define MAC_STATUS_PANID_CONFLICT (0xB) /**< A PANID conflict has been detected */
#define MAC_STATUS_NOTCOMPLETE (0xF) /**< Not complete */
/**
* MAC sequence modes
*/
#define MAC_SEQUENCE_NOP (0x0) /**< NOP */
#define MAC_SEQUENCE_RX (0x3) /**< RX */
#define MAC_SEQUENCE_TX (0x4) /**< TX */
#define MAC_SEQUENCE_ED (0x5) /**< ED */
#define MAC_SEQUENCE_CCA (0x6) /**< CCA */
/**
* MAC Interrupt enable / disable
*/
#define MAC_IRQ_NONE (0x0) /**< No IRQ */
#define MAC_IRQ_COMPLETE (0x1) /**< Event-complete IRQ */
#define MAC_IRQ_EVENT_STARTED (0x2) /**< Event-started IRQ */
#define MAC_IRQ_DATA (0x4) /**< Data-arrived IRQ */
#define MAC_IRQ_FRAME_STARTED (0x8) /**< Frame-started IRQ */
#define MAC_IRQ_PACKET_FAIL (0x10) /**< Failed-packet IRQ */
#define MAC_IRQ_FRAME_MATCH (0x20) /**< Frame-match IRQ (indicating matching process is done) */
#define MAC_IRQ_ALL (0x3F) /**< All IRQs */
#define MAC_RSSI_TO_ED 0
#define MAC_RSSI_TO_LQI 1
#define MAC_RF_TRX_OFF 0
#define MAC_RF_RX_ON 1
#define MAC_RF_TX_ON 2
#define MAC_RF_ED_SCAN 3
static int8_t rf_radio_driver_id = -1;
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_timers_disable_trig_event(void);
static void rf_mac_reset(void);
static void rf_mac_rx_enable(void);
static void rf_mac_ed_state_enable(void);
static uint8_t rf_mac_convert_rssi(uint8_t scale);
static int8_t rf_mac_get_rssi(void);
static void rf_mac_set_rx_on_state(bool enable);
static void rf_mac_write(uint8_t *data_ptr, uint8_t length);
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 void rf_mac_get_mac64(uint8_t* valueAddress);
static int8_t set_channel(uint8_t channel);
static void handle_IRQ_events(void);
static uint8_t MAC64_addr_default[8] = {1, 2, 3, 4, 5, 6, 7, 8};
static uint8_t MAC64_addr[8];
static uint8_t rf_mac_state = MAC_RF_TRX_OFF;
static bool rf_ack_pending_state = false;
static bool rf_mac_ack_requsted = false;
static uint8_t rf_mac_handle;
volatile uint8_t rf_ed_value = 0;
static NanostackRfPhyNcs36510 *rf = NULL;
#define MAC_PACKET_SIZE 127 //MAX MAC payload is 127 bytes
static uint8_t PHYPAYLOAD[MAC_PACKET_SIZE];
//TODO: verify these values
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*)"ON Semi ncs36510",
CRC_LENGTH,
PHY_HEADER_LENGTH,
&rf_interface_state_control,
&rf_start_cca,
&rf_address_write,
&rf_extension,
phy_channel_pages,
NULL,
NULL,
NULL,
NULL
};
#ifdef MBED_CONF_RTOS_PRESENT
static void rf_thread_loop(const void *arg)
{
for (;;) {
osEvent event = osSignalWait(0, osWaitForever);
if (event.status != osEventSignal) {
continue;
}
platform_enter_critical();
if (event.value.signals & SIGNAL_COUNT_RADIO) {
handle_IRQ_events();
}
platform_exit_critical();
NVIC_ClearPendingIRQ(MacHw_IRQn);
NVIC_EnableIRQ(MacHw_IRQn);
}
}
#endif
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(MACHWREG->LONG_ADDRESS_HIGH, MAC64_addr);
common_write_32_bit(MACHWREG->LONG_ADDRESS_LOW, 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);
}
void rf_read_mac_address(uint8_t *address_ptr)
{
platform_enter_critical();
rf_mac_get_mac64(address_ptr);
platform_exit_critical();
}
int8_t rf_read_random(void)
{
//TODO: Read random from randomizer
return 1;
}
void rf_set_mac_address(const uint8_t *ptr)
{
platform_enter_critical();
rf_mac_set_mac64(ptr);
platform_exit_critical();
}
static void rf_mac_set_pending(uint8_t status) {
if (status) {
MACHWREG->OPTIONS.BITS.TFPO = 0;
MACHWREG->OPTIONS.BITS.TFP = 1;
rf_ack_pending_state = true;
} else {
rf_ack_pending_state = false;
MACHWREG->OPTIONS.BITS.TFPO = 0;
MACHWREG->OPTIONS.BITS.TFP = 0;
}
}
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
{
platform_enter_critical();
switch(new_state){
case PHY_INTERFACE_RESET: { /**< Reset PHY driver and set to idle. */
rf_mac_set_rx_on_state(false);
break;
}
case PHY_INTERFACE_DOWN: { /**< Disable PHY interface driver (RF radio disable). */
rf_mac_set_rx_on_state(false);
break;
}
case PHY_INTERFACE_UP: { /**< Enable PHY interface driver (RF radio receiver ON). */
set_channel(rf_channel);
rf_mac_set_rx_on_state(true);
break;
}
case PHY_INTERFACE_RX_ENERGY_STATE: { /**< Enable wirless interface ED scan mode. */
rf_ed_value = 0;
set_channel(rf_channel);
rf_mac_set_rx_on_state(false);
rf_mac_ed_state_enable();
break;
}
case PHY_INTERFACE_SNIFFER_STATE: {
set_channel(rf_channel);
rf_mac_set_rx_on_state(true);
break;
}
}
platform_exit_critical();
return 0;
}
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
{
platform_enter_critical();
(void)data_protocol;
rf_mac_handle = tx_handle;
rf_mac_write(data_ptr, data_length);
platform_exit_critical();
return 0;
}
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
{
int ret_value = 0;
platform_enter_critical();
switch (address_type) {
case PHY_MAC_64BIT: /**< RF/PLC link layer address. */
rf_mac_set_mac64(address_ptr);
break;
case PHY_MAC_16BIT: /**< RF interface short address. */
rf_mac_set_shortAddress(address_ptr);
break;
case PHY_MAC_PANID: /**< RF interface 16-Bit PAN-ID. */
rf_mac_set_panId(address_ptr);
break;
default:
ret_value = -1;
}
platform_exit_critical();
return ret_value;
}
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;
case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: /**< Read status if the last ACK is still pending. */
*data_ptr = rf_ack_pending_state;
break;
case PHY_EXTENSION_SET_CHANNEL: /**< Net library channel set. */
return set_channel(*data_ptr);
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;
}
static int8_t set_channel(uint8_t channel)
{
if( channel > 10 && channel < 27 ){
fRfAnaIoctl(SET_RF_CHANNEL, &channel);
return 0;
}
return -1;
}
/**
* SET MAC 16 address to Register
*/
static void rf_mac_set_shortAddress(uint8_t* valueAddress) {
MACHWREG->SHORT_ADDRESS = common_read_16_bit(valueAddress);
}
/**
* SET PAN-ID to Register
*/
static void rf_mac_set_panId(uint8_t* valueAddress) {
MACHWREG->PANID = common_read_16_bit(valueAddress);
}
/**
* SET MAC64 address to register
*/
static void rf_mac_set_mac64(const uint8_t* valueAddress) {
MACHWREG->LONG_ADDRESS_HIGH = common_read_32_bit(valueAddress);
valueAddress += 4;
MACHWREG->LONG_ADDRESS_LOW = common_read_32_bit(valueAddress);
}
static void rf_mac_get_mac64(uint8_t* valueAddress) {
valueAddress = common_write_32_bit(MACHWREG->LONG_ADDRESS_HIGH, valueAddress);
common_write_32_bit(MACHWREG->LONG_ADDRESS_LOW, valueAddress);
}
static void rf_mac_timers_disable_trig_event(void) {
MACHWREG->TIMER_DISABLE.BITS.START = true;
MACHWREG->TIMER_DISABLE.BITS.STOP = true;
MACHWREG->SEQ_OPTIONS.BITS.NOW = true;
}
/**
* Call this only One time
*/
static void rf_mac_hw_init(void) {
uint32_t periphClockfrequency;
uint8_t lutIndex;
volatile uint8_t *pMatchReg = MACMATCHREG;
/** Initialize rf peripheral */
fRfAnaInit();
/** Enable mac clock */
CLOCK_ENABLE(CLOCK_MACHW);
/** Disable and clear IRQs */
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_NONE;
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_ALL;
NVIC_ClearPendingIRQ(MacHw_IRQn);
/** Set sequence options */
MACHWREG->SEQ_OPTIONS.BITS.MODE = 0x1;
MACHWREG->SEQ_OPTIONS.BITS.NOACK = false;
MACHWREG->SEQ_OPTIONS.BITS.NOW = true;
MACHWREG->SEQ_OPTIONS.BITS.PRM = false;
MACHWREG->SEQ_OPTIONS.BITS.ACK_ENABLE = false;
MACHWREG->SEQ_OPTIONS.BITS.RES_ENABLE = false;
/** Set clocks */
periphClockfrequency = fClockGetPeriphClockfrequency();
MACHWREG->DIVIDER.BITS.BIT_CLOCK_DIVIDER = (periphClockfrequency / 250000) - 1;
MACHWREG->DIVIDER.BITS.SYSTEM_CLOCK_DIVIDER = (periphClockfrequency / 1000000) - 1;
MACHWREG->DIVIDER.BITS.CHIP_CLOCK_DIVIDER = (periphClockfrequency / 2000000) - 1;
/** Set miscellaneous */
/** This value should be tuned tuned to hit tx sw ack window (192us-204us) */
MACHWREG->RX_TX_WARMPUPS.BITS.TRANSMIT_WARMPUP = 0x16;
/** This value is selected to allocate 1 bit margin between tr sw ack and tx sw ack */
MACHWREG->RX_TX_WARMPUPS.BITS.RECEIVE_WARMPUP = 0x15;
MACHWREG->TXCCA = 0x30;
MACHWREG->CCA.BITS.CCA_LENGTH = 0x43;
MACHWREG->CCA.BITS.CCA_DELAY = 0x26;
MACHWREG->TX_ACK_DELAY = 0x21;
MACHWREG->ACK_STOP.BITS.RXACK_END = 0xA8;
MACHWREG->SLOT_OFFSET.WORD = 0x00070007;
MACHWREG->TX_LENGTH.BITS.TX_PRE_CHIPS = 0x6;
MACHWREG->TX_FLUSH = 0x00000008; /** Transmit flush duration (8 x 4us = 32 us) */
/** Set AGC */
MACHWREG->AGC_CONTROL.WORD = 0x00000007; // AGC enabled / AGC freeze enabled / Preamble detection mode
/** It is unclear from design specification if a 16MHz is mandatory for AGC operations or only to build
* settle and measurements delays */
if (periphClockfrequency == CPU_CLOCK_ROOT_HZ) {
/** AGC time unit = T(PCLK) x 2 = 16MHz period */
MACHWREG->AGC_SETTINGS.BITS.DIVIDER = 1;
/** settle delay = (value + 1) * AGC time unit = 500ns targeted */
MACHWREG->AGC_SETTINGS.BITS.SETTLE_DELAY = 7;
/** measurement delay = (value + 1) * AGC time unit = 1500ns targeted */
MACHWREG->AGC_SETTINGS.BITS.MEASURE_DELAY = 0x17;
} else {
/** AGC time unit is T(PCLK) */
MACHWREG->AGC_SETTINGS.BITS.DIVIDER = 0;
/** settle delay = (value + 1) * AGC time unit = 500ns targeted */
MACHWREG->AGC_SETTINGS.BITS.SETTLE_DELAY = (16 / CPU_CLOCK_DIV) - 1;
/** measurement delay = (value + 1) * AGC time unit = 1500ns targeted */
MACHWREG->AGC_SETTINGS.BITS.MEASURE_DELAY = (48 / CPU_CLOCK_DIV) - 1;
}
/** AGC high threshold: 3dB below the clipping level */
MACHWREG->AGC_SETTINGS.BITS.HIGH_THRESHOLD = 1;
/** AGC low threshold: 9dB below the high threshold */
MACHWREG->AGC_SETTINGS.BITS.LOW_THRESHOLD = 0;
/** Set Demodulator */
DMDREG->DMD_CONTROL0.WORD = 0x7FFF0004;
MACHWREG->SHORT_ADDRESS = 0x0000ffff;
MACHWREG->PANID = 0x0000ffff;
/** Reset macHw peripheral */
rf_mac_reset();
/** Initialise LUT RAM */
for (lutIndex=0;lutIndex<96;lutIndex++) {
*(pMatchReg + lutIndex) = 0xFF;
}
#ifdef MBED_CONF_RTOS_PRESENT
rf_thread_id = osThreadCreate(osThread(rf_thread_loop), NULL);
#endif
/** Clear and enable MAC IRQ at task level, when scheduler is on. */
NVIC_ClearPendingIRQ(MacHw_IRQn);
NVIC_EnableIRQ(MacHw_IRQn);
}
static void rf_mac_set_rx_on_state(bool enable) {
/** Abort ongoing sequence */
rf_mac_reset();
/** Start rx if requested */
if (enable) {
/** Set requested filtering */
MACHWREG->SEQ_OPTIONS.BITS.BEA_ENABLE = true;
MACHWREG->SEQ_OPTIONS.BITS.DATA_ENABLE = true;
MACHWREG->SEQ_OPTIONS.BITS.CMD_ENABLE = true;
/** Start receiver */
rf_mac_rx_enable();
}
}
static void rf_mac_write(uint8_t *data_ptr, uint8_t length) {
uint8_t i;
volatile uint8_t *txRam = MACTXREG;
/* This is not make sense but... */
rf_mac_reset();
/* Set tx state */
rf_mac_state = MAC_RF_TX_ON;
if (*data_ptr & 0x20) {
MACHWREG->SEQ_OPTIONS.BITS.ACK_ENABLE = true;
} else {
MACHWREG->SEQ_OPTIONS.BITS.ACK_ENABLE = false;
}
rf_mac_ack_requsted = MACHWREG->SEQ_OPTIONS.BITS.ACK_ENABLE;
/* Set data length */
MACHWREG->TX_LENGTH.BITS.TXLENGTH = length + 2;
*txRam++ = *data_ptr++;
*txRam++ = *data_ptr++;
*txRam++ = *data_ptr;
//RR: Retransmission for Data request should have same DSN
MACHWREG->TX_SEQ_NUMBER = *data_ptr++;
for (i = 3; i < length; i++) {
*txRam++ = *data_ptr++;
}
MACHWREG->SEQ_OPTIONS.BITS.PRM = 0;
MACHWREG->SEQ_OPTIONS.BITS.NOACK = false;
rf_mac_state = MAC_RF_TX_ON;
/* Start CCA immediately */
rf_mac_timers_disable_trig_event();
while (MACHWREG->TIMER != 0x0) MACHWREG->TIMER = 0x0; // HW ISSUE: field is not set immediately
/* Enable tx irq, reset protocol timer and start tx sequence */
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_COMPLETE;
MACHWREG->SEQUENCER = MAC_SEQUENCE_TX;
}
static void rf_mac_ed_state_enable(void) {
rf_mac_state = MAC_RF_ED_SCAN;
/** Enable Energy scan state and event complete interrupt */
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_COMPLETE;
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_COMPLETE;
MACHWREG->SEQUENCER = MAC_SEQUENCE_ED;
}
static void rf_mac_rx_enable(void) {
rf_mac_state = MAC_RF_RX_ON;
/** Enable rx irqs, reset protocol timer and start rx sequence */
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_COMPLETE | MAC_IRQ_FRAME_MATCH | MAC_IRQ_DATA;
while (MACHWREG->TIMER != 0x0) MACHWREG->TIMER = 0x0; // HW ISSUE: field is not set immediately
MACHWREG->SEQUENCER = MAC_SEQUENCE_RX;
return;
}
static void rf_mac_reset(void) {
uint32_t macHwDivider;
/** Recommended abort sequence (with synchronous reset) */
/** 1. Set clock divider to minimum (for single clock response) */
macHwDivider = MACHWREG->DIVIDER.WORD;
/** (to cope with protocol timer and ed REVB silicon issues it is required
* to set protocol timer to 1 and not to 0 as suggested in macHw specification) */
/* PK !!!MAC_REVD RevB -> RevD change list Item 25: protocol timer */
MACHWREG->DIVIDER.WORD = 1;
/** 2. Disable interrupts */
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_NONE;
/** 3. Clear interrupts */
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_ALL;
NVIC_ClearPendingIRQ(MacHw_IRQn);
/** 4. Clear previous sequence type (write no-op sequence) */
MACHWREG->SEQUENCER = MAC_SEQUENCE_NOP;
/** 5. Move all MAC state machines to idle state (on, with synchronous reset) */
MACHWREG->CONTROL.WORD = 0x00000003;
/** 6. Release reset */
MACHWREG->CONTROL.WORD = 0x00000002;
/** 7. Disable start, stop timers */
rf_mac_timers_disable_trig_event();
/** 8. Return clock dividers to original value */
MACHWREG->DIVIDER.WORD = macHwDivider;
MACHWREG->SEQ_OPTIONS.BITS.BEA_ENABLE = False;
MACHWREG->SEQ_OPTIONS.BITS.DATA_ENABLE = False;
MACHWREG->SEQ_OPTIONS.BITS.CMD_ENABLE = False;
/** Set MAC_HW state */
rf_mac_state = MAC_RF_TRX_OFF;
}
static uint8_t rf_mac_convert_rssi(uint8_t scale) {
/* RSSI Value: The value is captured at the end of packet reception or at the end of ED/CCA
* measurements and is interpreted in dBm as follows:
* 1xxxxxxx: not used
* 01111111: 0 dBm (or above)
* 01111110: -1 dBm
* 01111101: -2 dBm
* -
* 00000010: -125 dBm
* 00000001: -126 dBm
* 00000000: -127 dBm (or below)
*/
/* check rssi is well in spec range */
//ASSERT ((DMDREG->DMD_STATUS.BITS.RSSI_VALUE & 0x80) != 0x80);
if (DMDREG->DMD_STATUS.BITS.RSSI_VALUE & 0x80) {
return 0;
}
/* convert rssi in sign char: translate 01111111 into 0 and following alike, make negative */
signed char rssi_value = -1 * (DMDREG->DMD_STATUS.BITS.RSSI_VALUE ^ 0x7F);
if (scale == MAC_RSSI_TO_ED ) {
/**
* For ED (IEEE 6.9.7) "The ED result shall be reported to the MLME as an 8 bit integer
* ranging from 0x00 to 0xff. The minimum ED value (zero) shall indicate received power less than 10 dB
* above the specified receiver sensitivity (see 6.5.3.3 and 6.6.3.4), and the range of received power spanned by
* the ED values shall be at least 40 dB. Within this range, the mapping from the received power in decibels to
* ED value shall be linear with an accuracy of <EFBFBD> 6 dB."
* (-85dBm receiver sensitivity will be targeted => zero ED value is associated to -75dBm)
* (span will have 51dBm range from 0x0=-75dBm to 0xff=-24dBm)
*/
/* Clip maximal and minimal rssi value reported by ED */
if (rssi_value < -75) rssi_value = -75;
if (rssi_value > -24) rssi_value = -24;
/* scale the span -75dBm --> -24dBm to 0x00 --> 0xFF
* Attention: This scaling implies that granularity of the result is changing from 1dBm per unit to 1/5 dBm per unit
* 0xFF: -24 dBm (or above)
* 0xFE - 0xFB: (impossible code)
* 0xFA: -25 dBm
* 0xF9 - 0xF6: (impossible code)
* 0xF5: -26 dBm
* ...
* 0x05: -74 dBm
* 0x01 - 0x04: (impossible code)
* 0x00: -75 dBm (or below)
*/
return (rssi_value + 75) * 5;
} else {
/**
* For LQI: (IEEE 6.9.7) "The LQI measurement shall be performed for each received packet, and the result shall be reported to the
* MAC sublayer using PD-DATA.indication (see 6.2.1.3) as an integer ranging from 0x00 to 0xff. The
* minimum and maximum LQI values (0x00 and 0xff) should be associated with the lowest and highest
* quality compliant signals detectable by the receiver, and LQI values in between should be uniformly
* distributed between these two limits. At least eight unique values of LQI shall be used."
* (-85dBm sensitivity will be targeted => zero LQI value will be associated to -85dBm)
* (span will have 64dBm range from 0x0=-85dBm to 0xff=-21dBm)
*/
/* Clip maximal and minimal rssi value reported by LQI */
if (rssi_value < -85) rssi_value = -85;
if (rssi_value > -21) rssi_value = -21;
/* scale the span -85dBm --> -21,25dBm to 0x00 --> 0xFF
* Attention: This scaling implies that granularity of the result is changing from 1dBm per unit to 1/4 dBm per unit
* 0xFF: -21,25 dBm (or above)
* 0xFE: (impossible code)
* 0xFD: (impossible code)
* 0xFC: -22 dBm
* 0xFB: (impossible code)
* 0xFA: (impossible code)
* 0xF9: (impossible code)
* 0xF8: -23 dBm
* ...
* 0x05: (impossible code)
* 0x04: - 84dBm
* 0x03: (impossible code)
* 0x02: (impossible code)
* 0x01: (impossible code)
* 0x00: - 85dBm
*/
if (rssi_value == -21)
return ((rssi_value + 85) * 4) - 1;
else
return (rssi_value + 85) * 4;
}
}
static int8_t rf_mac_get_rssi(void) {
int8_t rssi_value = -1 * (DMDREG->DMD_STATUS.BITS.RSSI_VALUE ^ 0x7F);
return rssi_value;
}
static void rf_rx_ed_scan_interrupt() {
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_COMPLETE;
if (MACHWREG->STATUS.BITS.CODE == MAC_STATUS_SUCCESS) {
uint8_t ed = rf_mac_convert_rssi(MAC_RSSI_TO_ED);
if (ed) {
if (ed > rf_ed_value) {
rf_ed_value = ed;
}
}
}
MACHWREG->MASK_IRQ.WORD = MAC_IRQ_COMPLETE;
MACHWREG->SEQUENCER = MAC_SEQUENCE_ED;
}
static void rf_rx_interrupt() {
// Frame match is used for association and data frames
uint8_t seqSts = MACHWREG->STATUS.BITS.CODE;
if (MACHWREG->IRQ_STATUS.BITS.FM) {
if (!rf_ack_pending_state) {
MACHWREG->OPTIONS.BITS.TFP = 0;
MACHWREG->OPTIONS.BITS.TFPO = 1;
} else {
MACHWREG->OPTIONS.BITS.TFP = 1;
MACHWREG->OPTIONS.BITS.TFPO = 1;
}
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_FRAME_MATCH;
return;
}
/** RR: Process the event complete IRQ */
if (MACHWREG->IRQ_STATUS.BITS.EC || MACHWREG->IRQ_STATUS.BITS.DATA) {
/** Clear the event */
if (MACHWREG->IRQ_STATUS.BITS.EC) {
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_COMPLETE;
}
if (MACHWREG->IRQ_STATUS.BITS.DATA) {
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_DATA;
}
/** Build frame (containing received frame or timeout) */
volatile uint8_t *rxRam = MACRXREG;
uint8_t length;
int8_t rssi;
uint8_t lqi;
/** Return directly in case of timeout */
if (seqSts == MAC_STATUS_TIMEOUT) {
/* Initialize frame status */
return;
}
length = *rxRam++;
if (length < 5){
rf_mac_rx_enable();
return;
}
length -= 2; //Cut CRC OUT
/* Initialize frame status */
for (uint8_t i=0; i < length; i++) {
PHYPAYLOAD[i] = *rxRam++;
}
lqi = rf_mac_convert_rssi(MAC_RSSI_TO_LQI);
rssi = rf_mac_get_rssi();
rf_mac_rx_enable();
//Call ARM API
if( device_driver.phy_rx_cb ){
device_driver.phy_rx_cb(PHYPAYLOAD, length, lqi, rssi, rf_radio_driver_id);
}
}
}
static void rf_mac_tx_interrupt(void)
{
phy_link_tx_status_e status;
/** Clear the event complete IRQ */
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_COMPLETE;
/* This IRQ means that Data Request is complete; check the status */
uint8_t sharedSeqSts = MACHWREG->STATUS.BITS.CODE;
rf_mac_set_rx_on_state(true);
switch (sharedSeqSts) {
case MAC_STATUS_SUCCESS: /* Positive */
//SET Success
if (rf_mac_ack_requsted) {
status = PHY_LINK_TX_DONE;
} else {
status = PHY_LINK_TX_SUCCESS;
}
break;
case MAC_STATUS_RXACK_PENDING: /* Positive for broadcast */
status = PHY_LINK_TX_DONE_PENDING;
break;
case MAC_STATUS_BUSY:
status = PHY_LINK_CCA_FAIL;
break;
default:
status = PHY_LINK_TX_FAIL;
break;
}
rf_mac_ack_requsted = false;
//Call RX TX complete
if( device_driver.phy_tx_done_cb ) {
device_driver.phy_tx_done_cb(rf_radio_driver_id, rf_mac_handle, status, 1, 1);
}
}
/**
* RF MAC Interrupt handler
*/
extern "C" void fIrqMacHwHandler(void)
{
#ifdef MBED_CONF_RTOS_PRESENT
NVIC_DisableIRQ(MacHw_IRQn);
osSignalSet(rf_thread_id, SIGNAL_COUNT_RADIO);
#else
handle_IRQ_events();
#endif
}
static void handle_IRQ_events(void)
{
/** Set MAC timers to initial state */
MACHWREG->TIMER_ENABLE.BITS.START = false;
MACHWREG->TIMER_ENABLE.BITS.STOP = false;
MACHWREG->TIMER_DISABLE.BITS.START = false;
MACHWREG->TIMER_DISABLE.BITS.STOP = false;
/** Disarm start/stop timers, disable and clear irq (event_complete) */
rf_mac_timers_disable_trig_event();
/** REVD changes to sequence tracking register. Sequence register can be used instead of rf_mac_state */
if (rf_mac_state == MAC_RF_RX_ON) {
rf_rx_interrupt();
} else if(rf_mac_state == MAC_RF_TX_ON) {
rf_mac_tx_interrupt();
} else if (rf_mac_state == MAC_RF_ED_SCAN){
rf_rx_ed_scan_interrupt();
} else {
/** Clear the event complete IRQ */
MACHWREG->CLEAR_IRQ.WORD = MAC_IRQ_COMPLETE;
uint8_t sharedSeqSts = MACHWREG->STATUS.BITS.CODE;
}
}
NanostackRfPhyNcs36510::NanostackRfPhyNcs36510()
{
memcpy(MAC64_addr, MAC64_addr_default, sizeof(MAC64_addr));
}
NanostackRfPhyNcs36510::~NanostackRfPhyNcs36510()
{
// Do nothing
}
int8_t NanostackRfPhyNcs36510::rf_register()
{
platform_enter_critical();
if (rf != NULL) {
platform_exit_critical();
error("Multiple registrations of NanostackRfPhyNcs36510 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 NanostackRfPhyNcs36510::rf_unregister()
{
platform_enter_critical();
if (rf != this) {
platform_exit_critical();
return;
}
rf_device_unregister();
rf = NULL;
platform_exit_critical();
}
void NanostackRfPhyNcs36510::get_mac_address(uint8_t *mac)
{
platform_enter_critical();
memcpy((void*)mac, (void*)MAC64_addr, sizeof(MAC64_addr));
platform_exit_critical();
}
void NanostackRfPhyNcs36510::set_mac_address(uint8_t *mac)
{
platform_enter_critical();
if (NULL != rf) {
error("NanostackRfPhyNcs36510 cannot change mac address when running");
platform_exit_critical();
return;
}
memcpy((void*)MAC64_addr, (void*)mac, sizeof(MAC64_addr));
platform_exit_critical();
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2014-2015 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.
*/
#ifndef NANOSTACK_PHY_NCS36510_H_
#define NANOSTACK_PHY_MCR20A_H_
#include "mbed.h"
#include "NanostackRfPhy.h"
class NanostackRfPhyNcs36510 : public NanostackRfPhy {
public:
NanostackRfPhyNcs36510();
~NanostackRfPhyNcs36510();
int8_t rf_register();
void rf_unregister();
void get_mac_address(uint8_t *mac);
void set_mac_address(uint8_t *mac);
};
#endif /* NANOSTACK_PHY_MCR20A_H_ */