/** * \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