/**
* \file phy.c
*
* \brief Physical Layer Abstraction for AT86RF212B implementation
*
* Copyright (c) 2018 - 2019 Microchip Technology Inc. and its subsidiaries.
*
* \asf_license_start
*
* \page License
*
* Subject to your compliance with these terms, you may use Microchip
* software and any derivatives exclusively with Microchip products.
* It is your responsibility to comply with third party license terms applicable
* to your use of third party software (including open source software) that
* may accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit Microchip Support
*/
#include
#include
#include
#include "miwi_config.h"
#if defined(PROTOCOL_P2P) || defined (PROTOCOL_STAR)
#include "miwi_config_p2p.h" //MiWi Protocol layer configuration file
#endif
#include "delay.h"
#include "sal.h"
#include "phy.h"
#include "phy_at86rf212b.h"
#include "mimem.h"
#include "miqueue.h"
#include "string.h"
/*- Definitions ------------------------------------------------------------*/
#define PHY_CRC_SIZE 2
/*- Types ------------------------------------------------------------------*/
typedef enum {
PHY_STATE_INITIAL,
PHY_STATE_IDLE,
PHY_STATE_SLEEP,
PHY_STATE_TX_WAIT_END,
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
PHY_STATE_TX_CONFIRM,
PHY_STATE_RX_IND,
PHY_STATE_ED_WAIT,
PHY_STATE_ED_DONE,
#endif
} PhyState_t;
/*- Prototypes -------------------------------------------------------------*/
static void phyWriteRegister(uint8_t reg, uint8_t value);
static uint8_t phyReadRegister(uint8_t reg);
static void phyWaitState(uint8_t state);
static void phyTrxSetState(uint8_t state);
static void phySetChannel(void);
static void phySetRxState(void);
static int8_t phyRssiBaseVal(void);
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
static void phyInterruptHandler(void);
#endif
/*- Variables --------------------------------------------------------------*/
static PhyState_t phyState = PHY_STATE_INITIAL;
static uint8_t phyRxBuffer[128];
static bool phyRxState;
static uint8_t phyBand;
static uint8_t phyChannel;// TODO
static uint8_t phyModulation;
RxBuffer_t RxBuffer[BANK_SIZE];
PHY_DataReq_t gPhyDataReq;
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
static PHY_DataInd_t ind;
volatile uint8_t phyTxStatus;
volatile int8_t phyRxRssi;
PHY_ReservedFrameIndCallback_t phyReserveFrameIndCallback = NULL;
#endif
MiQueue_t phyTxQueue;
/*************************************************************************//**
*****************************************************************************/
/* PHY Data Req */
void PHY_DataReq(PHY_DataReq_t* phyDataReq)
{
PhyTxFrame_t *phyDataRequestPtr = NULL;
phyDataRequestPtr = (PhyTxFrame_t *) MiMem_Alloc(sizeof(PhyTxFrame_t));
if (NULL == phyDataRequestPtr)
{
phyDataReq->confirmCallback(PHY_STATUS_ERROR);
return;
}
memcpy(&phyDataRequestPtr->phyDataReq, phyDataReq, sizeof(PHY_DataReq_t));
miQueueAppend(&phyTxQueue, (miQueueBuffer_t *)phyDataRequestPtr);
}
/* PHY Transmission Handler */
void PHY_TxHandler(void)
{
if (phyTxQueue.size && ((phyState == PHY_STATE_IDLE) || (phyState == PHY_STATE_SLEEP)))
{
PhyTxFrame_t *phyTxPtr = NULL;
phyTxPtr = (PhyTxFrame_t *)miQueueRemove(&phyTxQueue, NULL);
if (NULL != phyTxPtr)
{
/* Ignore sending packet if length is more than Max PSDU */
if (phyTxPtr->phyDataReq.data[0] > MAX_PSDU)
{
phyTxPtr->phyDataReq.confirmCallback(PHY_STATUS_ERROR);
return;
}
phyTrxSetState(TRX_CMD_TX_ARET_ON);
phyReadRegister(IRQ_STATUS_REG);
/* size of the buffer is sent as first byte of the data
* and data starts from second byte.
*/
phyTxPtr->phyDataReq.data[0] += 2;// 2
trx_frame_write(&phyTxPtr->phyDataReq.data[0], (phyTxPtr->phyDataReq.data[0]-1 ) /* length value*/);
phyState = PHY_STATE_TX_WAIT_END;
TRX_SLP_TR_HIGH();
TRX_TRIG_DELAY();
TRX_SLP_TR_LOW();
/* Save request information for further processing */
gPhyDataReq.polledConfirmation = phyTxPtr->phyDataReq.polledConfirmation;
gPhyDataReq.confirmCallback = phyTxPtr->phyDataReq.confirmCallback;
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
if(gPhyDataReq.polledConfirmation)
{
uint8_t status;
/* Clear the interrupt flag */
DISABLE_TRX_IRQ();
while(!(phyReadRegister(IRQ_STATUS_REG) & (1 << TRX_END)));
CLEAR_TRX_IRQ();
ENABLE_TRX_IRQ();
/* Read the transmit transaction status */
status = (phyReadRegister(TRX_STATE_REG) >> TRAC_STATUS) & 7;
if (TRAC_STATUS_SUCCESS == status)
{
status = PHY_STATUS_SUCCESS;
}
else if (TRAC_STATUS_CHANNEL_ACCESS_FAILURE == status)
{
status = PHY_STATUS_CHANNEL_ACCESS_FAILURE;
}
else if (TRAC_STATUS_NO_ACK == status)
{
status = PHY_STATUS_NO_ACK;
}
else
{
status = PHY_STATUS_ERROR;
}
/* Post the confirmation */
gPhyDataReq.confirmCallback(status);
gPhyDataReq.confirmCallback= NULL;
/* Set back the transceiver to RX ON state */
phySetRxState();
phyState = PHY_STATE_IDLE;
}
#endif
MiMem_Free((uint8_t *)phyTxPtr);
}
}
}
/*************************************************************************//**
*****************************************************************************/
void PHY_Init(void)
{
trx_spi_init();
PhyReset();
phyRxState = false;
phyBand = 0; // For RF212b-MiWi stack we fix the band to 0
phyModulation = phyReadRegister(TRX_CTRL_2_REG) & 0x3f;
phyState = PHY_STATE_IDLE;
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
phyWriteRegister(IRQ_MASK_REG , (1<> RND_VALUE) & 3;
rnd |= rndValue << i;
}
phySetRxState();
phyWriteRegister(RX_SYN_REG, prev_rx_pdt_dis);
return rnd;
}
/*************************************************************************//**
*****************************************************************************/
void PHY_EncryptReq(uint8_t *text, uint8_t *key)
{
sal_aes_setup(key, AES_MODE_ECB, AES_DIR_ENCRYPT);
#if (SAL_TYPE == AT86RF2xx)
sal_aes_wrrd(text, NULL);
#else
sal_aes_exec(text);
#endif
sal_aes_read(text);
}
void PHY_EncryptReqCBC(uint8_t *text, uint8_t *key)
{
sal_aes_setup(key, AES_MODE_CBC, AES_DIR_ENCRYPT);
#if (SAL_TYPE == AT86RF2xx)
sal_aes_wrrd(text, NULL);
#else
sal_aes_exec(text);
#endif
sal_aes_read(text);
}
/*************************************************************************//**
*****************************************************************************/
// Decrypt Block
void PHY_DecryptReq(uint8_t *text, uint8_t *key)
{
sal_aes_setup(key, AES_MODE_ECB, AES_DIR_DECRYPT);
sal_aes_wrrd(text, NULL);
sal_aes_read(text);
}
/*************************************************************************//**
*****************************************************************************/
uint8_t PHY_EdReq(void) //TODO datatype int8 or uint8
{
uint8_t ed;
uint8_t prev_rx_pdt_dis;
phyTrxSetState(TRX_CMD_PLL_ON);
phyReadRegister(IRQ_STATUS_REG);
/*Ensure that register bit RX_PDT_DIS is set to 0*/
prev_rx_pdt_dis = phyReadRegister(RX_SYN_REG);
phyWriteRegister(RX_SYN_REG, (prev_rx_pdt_dis | (1<<7)));
phyTrxSetState(TRX_CMD_RX_ON);
phyWriteRegister(PHY_ED_LEVEL_REG, 0xFF);
while (0 == (phyReadRegister(IRQ_STATUS_REG) & (1 << CCA_ED_DONE))) {
}
ed = (uint8_t)phyReadRegister(PHY_ED_LEVEL_REG);
phySetRxState();
phyWriteRegister(RX_SYN_REG, prev_rx_pdt_dis);
/* *Adding the base value gets the real value for ED which will be negative.
*Since the RSSI values will be used within the Same radio for comparisons
*Normalised value from the register is sufficient
*/
return ed + phyRssiBaseVal();
}
/*************************************************************************//**
*****************************************************************************/
static void phyWriteRegister(uint8_t reg, uint8_t value)
{
trx_reg_write(reg, value);
}
/*************************************************************************//**
*****************************************************************************/
static uint8_t phyReadRegister(uint8_t reg)
{
uint8_t value;
value = trx_reg_read(reg);
return value;
}
/*************************************************************************//**
*****************************************************************************/
static void phyWaitState(uint8_t state)
{
while (state != (phyReadRegister(TRX_STATUS_REG) & TRX_STATUS_MASK)) {
}
}
/*************************************************************************//**
*****************************************************************************/
static void phySetChannel(void)
{
uint8_t reg;
if(phyChannel == 0)
{
phyModulation = PHY_MOD_BPSK20_CHAN_0;
}
else
{
phyModulation = PHY_MOD_BPSK40_CHAN_N;
}
phyWriteRegister(CC_CTRL_1_REG, phyBand);
if (0 == phyBand) {
reg = phyReadRegister(PHY_CC_CCA_REG) & ~0x1f;
phyWriteRegister(PHY_CC_CCA_REG, reg | phyChannel);
} else {
phyWriteRegister(CC_CTRL_0_REG, phyChannel);
}
}
/*************************************************************************//**
*****************************************************************************/
static void phySetRxState(void)
{
phyTrxSetState(TRX_CMD_TRX_OFF);
phyReadRegister(IRQ_STATUS_REG);
if (phyRxState) {
phyTrxSetState(TRX_CMD_RX_AACK_ON);
phyState = PHY_STATE_IDLE;
}
}
/*************************************************************************//**
*****************************************************************************/
static void phyTrxSetState(uint8_t state)
{
if (PHY_STATE_SLEEP == phyState)
{
TRX_SLP_TR_LOW();
}
do { phyWriteRegister(TRX_STATE_REG, TRX_CMD_FORCE_TRX_OFF);
} while (TRX_STATUS_TRX_OFF !=
(phyReadRegister(TRX_STATUS_REG) & TRX_STATUS_MASK));
do { phyWriteRegister(TRX_STATE_REG,
state); } while (state !=
(phyReadRegister(TRX_STATUS_REG) & TRX_STATUS_MASK));
}
/*************************************************************************//**
*****************************************************************************/
static int8_t phyRssiBaseVal(void)
{
bool oqpsk = (phyModulation & (1 << BPSK_OQPSK));
bool sub = (phyModulation & (1 << SUB_MODE));
bool rc = (phyModulation & (1 << 4 /*ALT_SPEC*/));
if (0 == oqpsk) {
if (0 == sub) {
return PHY_RSSI_BASE_VAL_BPSK_20;
} else {
return PHY_RSSI_BASE_VAL_BPSK_40;
}
} else {
if (0 == sub) {
return PHY_RSSI_BASE_VAL_OQPSK_SIN_RC_100;
} else {
if (0 == rc) {
return PHY_RSSI_BASE_VAL_OQPSK_SIN_250;
} else {
return PHY_RSSI_BASE_VAL_OQPSK_RC_250;
}
}
}
}
/*************************************************************************//**
*****************************************************************************/
void PHY_SetIEEEAddr(uint8_t *ieee_addr)
{
uint8_t *ptr_to_reg = ieee_addr;
for (uint8_t i = 0; i < 8; i++) {
trx_reg_write((IEEE_ADDR_0_REG + i), *ptr_to_reg);
ptr_to_reg++;
}
}
/*************************************************************************//**
*****************************************************************************/
#if (defined(OTAU_ENABLED) && defined(OTAU_PHY_MODE))
void PHY_EnableReservedFrameRx(void)
{
uint8_t reg;
reg = phyReadRegister(XAH_CTRL_1_REG) & ~0x07;
reg = reg | (1 << AACK_FLTR_RES_FT) | (1 << AACK_UPLD_RES_FT);
phyWriteRegister(XAH_CTRL_1_REG, reg);
}
/*************************************************************************//**
*****************************************************************************/
bool PHY_SubscribeReservedFrameIndicationCallback(PHY_ReservedFrameIndCallback_t callback)
{
if (NULL != callback)
{
phyReserveFrameIndCallback = callback;
PHY_EnableReservedFrameRx();
return true;
}
return false;
}
/*************************************************************************//**
*****************************************************************************/
void PHY_DataInd(PHY_DataInd_t *dataInd)
{
uint8_t i,RxBank=0xFF;
for (i = 0; i < BANK_SIZE; i++)
{
if (RxBuffer[i].PayloadLen == 0)
{
RxBank = i;
break;
}
}
if (RxBank < BANK_SIZE)
{
if(dataInd->size <= MAX_PSDU)
{
RxBuffer[RxBank].PayloadLen = dataInd->size + 2;
if (RxBuffer[RxBank].PayloadLen < RX_PACKET_SIZE)
{
//copy all of the data from the FIFO into the RxBuffer, plus RSSI and LQI
for (i = 0; i <= dataInd->size; i++)
{
RxBuffer[RxBank].Payload[i] = dataInd->data[i];
}
RxBuffer[RxBank].Payload[RxBuffer[RxBank].PayloadLen - 2] = dataInd->lqi + phyRssiBaseVal();
RxBuffer[RxBank].Payload[RxBuffer[RxBank].PayloadLen - 1] = dataInd->rssi + phyRssiBaseVal();
}
}
}
}
void PHY_TaskHandler(void)
{
PHY_TxHandler();
if (PHY_STATE_SLEEP == phyState)
{
return;
}
if (PHY_STATE_TX_CONFIRM == phyState)
{
uint8_t status = (phyReadRegister(TRX_STATE_REG) >> TRAC_STATUS) & 7;
if (TRAC_STATUS_SUCCESS == status)
{
status = PHY_STATUS_SUCCESS;
}
else if (TRAC_STATUS_CHANNEL_ACCESS_FAILURE == status)
{
status = PHY_STATUS_CHANNEL_ACCESS_FAILURE;
}
else if (TRAC_STATUS_NO_ACK == status)
{
status = PHY_STATUS_NO_ACK;
}
else
{
status = PHY_STATUS_ERROR;
}
gPhyDataReq.confirmCallback(status);
gPhyDataReq.confirmCallback = NULL;
phySetRxState();
phyState = PHY_STATE_IDLE;
}
else if (PHY_STATE_RX_IND == phyState)
{
#ifdef OTAU_SERVER
uint16_t fcf = convert_byte_array_to_16_bit(ind.data);
if(FCF_GET_FRAMETYPE(fcf) == 0x07)
{
//delay_us(500);
phyReserveFrameIndCallback(&ind);
}
else
#endif
{
PHY_DataInd(&ind);
}
while (TRX_CMD_PLL_ON != (phyReadRegister(TRX_STATUS_REG) & TRX_STATUS_TRX_STATUS_MASK));
phyState = PHY_STATE_IDLE;
phySetRxState();
}
}
static void phyInterruptHandler(void)
{
uint8_t irq;
irq = phyReadRegister(IRQ_STATUS_REG);
/* Keep compiler happy */
irq = irq;
if (PHY_STATE_TX_WAIT_END == phyState)
{
phyTxStatus = (phyReadRegister(TRX_STATE_REG) >> 5) & 0x07;
phyWriteRegister(TRX_STATE_REG, TRX_CMD_PLL_ON);
phyState = PHY_STATE_TX_CONFIRM;
}
else if (PHY_STATE_IDLE == phyState)
{
uint8_t size;
phyWriteRegister(TRX_STATE_REG, TRX_CMD_PLL_ON);
phyRxRssi = (int8_t)phyReadRegister(PHY_ED_LEVEL_REG);
trx_frame_read(&size,1);
if(size <= MAX_PSDU)
{
trx_frame_read(phyRxBuffer,size+2);
ind.data = phyRxBuffer+1;
ind.size = size;
ind.lqi = phyRxBuffer[size+1];
ind.rssi = phyRxRssi + phyRssiBaseVal();
#ifndef OTAU_SERVER
uint16_t fcf;
fcf = convert_byte_array_to_16_bit(ind.data);
if(FCF_GET_FRAMETYPE(fcf) == 0x07)
{
delay_us(500);
phyReserveFrameIndCallback(&ind);
phySetRxState();
}
else
#endif
{
phyState = PHY_STATE_RX_IND;
}
}
}
}
#else
// Handle Packet Received
void PHY_TaskHandler(void)
{
PHY_TxHandler();
if (PHY_STATE_SLEEP == phyState)
{
return;
}
if (phyReadRegister(IRQ_STATUS_REG) & (1 << TRX_END))
{
if (PHY_STATE_IDLE == phyState)
{
uint8_t size,i,RxBank=0xFF;
for (i = 0; i < BANK_SIZE; i++)
{
if (RxBuffer[i].PayloadLen == 0)
{
RxBank = i;
break;
}
}
if (RxBank < BANK_SIZE)
{
int8_t rssi;
rssi = (int8_t)phyReadRegister(PHY_ED_LEVEL_REG);
trx_frame_read(&size, 1);
if(size <= MAX_PSDU)
{
trx_frame_read(phyRxBuffer, size + 2);
RxBuffer[RxBank].PayloadLen = size + 2;
if (RxBuffer[RxBank].PayloadLen < RX_PACKET_SIZE)
{
//copy all of the data from the FIFO into the RxBuffer, plus RSSI and LQI
for (i = 1; i <= size+2; i++)
{
RxBuffer[RxBank].Payload[i-1] = phyRxBuffer[i];
}
RxBuffer[RxBank].Payload[RxBuffer[RxBank].PayloadLen - 1] = rssi + phyRssiBaseVal();
}
}
phyWaitState(TRX_STATUS_RX_AACK_ON);
}
}
else if (PHY_STATE_TX_WAIT_END == phyState)
{
uint8_t status = (phyReadRegister(TRX_STATE_REG) >> TRAC_STATUS) & 7;
if (TRAC_STATUS_SUCCESS == status)
{
status = PHY_STATUS_SUCCESS;
}
else if (TRAC_STATUS_CHANNEL_ACCESS_FAILURE == status)
{
status = PHY_STATUS_CHANNEL_ACCESS_FAILURE;
}
else if (TRAC_STATUS_NO_ACK == status)
{
status = PHY_STATUS_NO_ACK;
}
else
{
status = PHY_STATUS_ERROR;
}
gPhyDataReq.confirmCallback(status);
gPhyDataReq.confirmCallback = NULL;
phySetRxState();
phyState = PHY_STATE_IDLE;
}
}
}
#endif