/******************************************************************************
* 物联网黑手党出品
*******************************************************************************
文件名: mac.c
目标硬件: cc1110/CC2510
作者: 罗一鸣
修改日期: 2011-3-18
版本: 1.3.2
Description:
MAC层的收发控制
设置了Tx Cache和Rx Cache。
Tx Cache 设置的默认CSMA时间是250毫秒,一次发送,有应答请求。如果没有应答,应
在用户层手动设置应答。而如果模块收到应答请求,而有Tx Cache处于等待发送或者等待应
答,则优先发送Ack。
由于超时调度函数是用于CSMA监听和ACK接受,在收到ACK时,应停止MAC超时触发函数
调度。
******************************************************************************/
#include "hal_rf.h"
#include "mac_timer.h"
/* Tx Status */
#define MAC_TX_STA 0x0F
#define MAC_TX_IDLE 0x00
#define MAC_TX_CSMA 0x01
#define MAC_TX_ALLOW 0x02 //
#define MAC_TX_ING 0x03 // Transmiting
#define MAC_TX_WAIT 0x04 // Wait Ack
#define MAC_TX_END 0x05 // Tx is success
#define MAC_TX_NOACK 0x06 // Tx is no ack
#define MAC_TX_FAIL 0x07 // Tx is fail
/* ACK STA */
#define MAC_TX_ACKEN 0x10
/* CSMA EN */
#define MAC_TX_FAST 0x20
/* Tx Retry Time */
/* Define Mac Packet */
#define MAC_HEAD_PAD(x) ((MacHead_t*)(x))
//RF_DMA_PACKET MacTxCache;
typedef struct{
BOOL en;
UINT8 sta;
MacHead_t ack;
}MacAck_t;
/* Globle FIFO */
UINT16 MacRxTime;
RF_DMA_PACKET* MacRxDma = 0;
MacRxPkt_t MacRxCache;
MacTxPkt_t MacTxCache;
MacHead_t MacAck;
void (*AckCallbackStore)(void);
UINT8 AckTimeoutStore;
/* */
UINT8 MacMyAddr;
/* Rx Call back & Tx Call back */
void (*MacTxCb)(MacBuff_t* buff,UINT8 event,UINT8 sta);
void (*MacRxCb)(MacBuff_t* buff,UINT8 len,UINT8 rssi,UINT16 time);
/* MAC TIMER FUNTION */
UINT8 MacTimeoutKeep(MacTimerCb_t*);
void MacTimeoutSetCb(UINT8 time,void (*cb)(void));
void MacTimeoutClean(void);
void MacTimerPoll(void);
/*------------------------------------------------------------------------------
MAC in RF Interrupt's Funtion
------------------------------------------------------------------------------*/
void HalRfTxFinishIsr(RF_DMA_PACKET* pkt,UINT8 evt)
{
//If Tx Ack , pass
if(MacTxCache.event == evt && (MacTxCache.sta & MAC_TX_STA) == MAC_TX_ING) //Tx Normal Data
{
if((MacTxCache.sta & MAC_TX_ACKEN) == MAC_TX_ACKEN)
{
MacTxCache.sta = MAC_TX_WAIT; //MAC_TX_ACKEN is Cleaned
}
else
{
MacTxCache.sta = MAC_TX_END;
}
}
}
void HalRfRxFinishIsr(RF_DMA_PACKET* pkt,UINT16 time)
{
UINT8 len = pkt->len;
MacBuff_t* buff = (MacBuff_t*)pkt->buff;
//CRC chech;
if(!(pkt->buff[len+1] & 0x80)) //Check Crc is Ok? Or give up this packet
{
pkt->len = 0; //clean dma.
return;
}
//set buff
//Address Detect
if(buff->DestAddr != MacMyAddr && buff->DestAddr != 0xFF)
{
pkt->len = 0; //clean dma
return;
}
//Ack Req Proccess
if((buff->Cmd & MAC_ACK_MSK) == MAC_ACK_ASW)
{
//Rx a ack
if(MacTxCache.event == buff->Event) //ack is for now Tx packet
{
pkt->len = 0;
if(MacTxCache.sta == MAC_TX_WAIT)
{
MacTxCache.sta = MAC_TX_END; //ACK is Ok
}
return ;
}
}
//Rx Payload,Read Dma buffer,and Clean it.
if(MacRxCache.len == 0) //if Rx Cache is empty,push dma to cache
{
pkt->len = 0; //clean dma
MacRxCache.len = len;
MacRxCache.rssi = pkt->buff[len];
MacRxCache.time = time;
memcpy(&MacRxCache.buff,buff,len);
}
else //if chache is full,keep dma and push it to cache when cache empty.
{
MacRxTime = time;
MacRxDma = pkt;
}
}
/*------------------------------------------------------------------------------
MAC in Poll's Funtion
------------------------------------------------------------------------------*/
/* Mac Random Ms Timeout */
UINT8 MacRandomGet(void)
{
UINT8 random = 0;
GET_RANDOM_BYTE(random);
do{
GET_RANDOM_BYTE(random);
random &= 0x07;
}while(random == 0);
return random;
}
/* CSMA Start */
void MacCsmaCb(void)
{
if(MacTxCache.len)
{
if((MacTxCache.sta & MAC_TX_STA) == MAC_TX_CSMA) //timeout is finish
{
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_ALLOW; //if it is Txing,wait it finish.
}
}
}
void MacWaitAckCb(void)
{
if(MacTxCache.len)
{
if((MacTxCache.sta & MAC_TX_STA) == MAC_TX_WAIT)
{
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_NOACK;
}
}
}
void MacTxAck(void)
{
HalRfSendFast((UINT8*)&(MacAck),4,MacAck.Event);
}
/*------------------------------------------------------------------------------
MAC polls,include RxPoll,TxPoll and TxEndPoll
MAC层内部函数,用于NWK层调度。
------------------------------------------------------------------------------*/
/* Tx Poll , if there is data to be send and the channel is clear,send all data*/
void MacTxPoll(void)
{
if(MacTxCache.len) //TxBuffer is Full,wait to be send
{
if((MacTxCache.sta & MAC_TX_STA) == MAC_TX_ALLOW) //try to send
{
if(MacTxCache.sta & MAC_TX_FAST) //CSMA IS OFF
{
HalRfSendFast((UINT8*)&MacTxCache.buff,MacTxCache.len,MacTxCache.event); //No Csma
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_ING;
//If Need Wait Ack?
if((MacTxCache.sta & MAC_TX_ACKEN) == MAC_TX_ACKEN)
{
MacTimeoutSetCb(32,MacWaitAckCb);
}
}
else
{
if(HalRfSend((UINT8*)&MacTxCache.buff,MacTxCache.len,MacTxCache.event)) //SEND CSMA
{
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_ING;
//If Need Wait Ack?
if((MacTxCache.sta & MAC_TX_ACKEN) == MAC_TX_ACKEN)
{
MacTimeoutSetCb(32,MacWaitAckCb);
}
}
else //channel is busy
{
UINT8 random = MacRandomGet(); //ACK,16ms CSMA
if(MacTxCache.timeout) //CSMA timeout is still
{
if(MacTxCache.timeout > random)
{
MacTxCache.timeout -= random;
}
else
{
random = MacTxCache.timeout;
MacTxCache.timeout = 0;
}
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_CSMA;
MacTimeoutSetCb(random,MacCsmaCb);
}
else //CSMA timeout is runout
{
MacTxCache.sta &= 0xF0;
MacTxCache.sta |= MAC_TX_FAIL;
}
}
}
}
}
}
void MacTxEndPoll(void)
{
if(MacTxCache.sta == MAC_TX_END || MacTxCache.sta == MAC_TX_FAIL || MacTxCache.sta == MAC_TX_NOACK)
{
UINT8 sta = MacTxCache.sta;
MacTimeoutClean();
MacTxCache.len = 0;
MacTxCache.sta = MAC_TX_IDLE;
if(MacTxCb)
{
sta -= MAC_TX_END;
MacTxCb(&MacTxCache.buff, MacTxCache.event, sta);
}
}
}
void MacRxEndPoll(void)
{
if(MacRxCache.len)
{
if((MacRxCache.buff.Cmd & MAC_ACK_MSK) == MAC_ACK_REQ)
{
//Send Ack
MacAck.DestAddr = MacRxCache.buff.SrcAddr;
MacAck.SrcAddr = MacMyAddr;
MacAck.Cmd = MAC_ACK_ASW;
MacAck.Event = MacRxCache.buff.Event;
MacTxAck();
}
if(MacRxCb)//run rx callback
{
MacRxCb(&MacRxCache.buff,MacRxCache.len - 4,MacRxCache.rssi,MacRxCache.time);
}
// Clean Rx Cache
MacRxCache.len = 0;
// If Rx Dma have new data,copy to Rx Cache.
if(MacRxDma && MacRxDma->len)
{
UINT8 len = MacRxDma->len;
MacRxDma->len = 0;
MacRxCache.len = len;
MacRxCache.rssi = MacRxDma->buff[len];