📄 mac.c
字号:
/*
****************************************************************************
*
* 宁波中科集成电路设计中心 版权所有 Copyright 2005
*
*文件名: mac.c
*程序员: xp
*主要内容:mac通信协议栈MAC层
*完成日期:2005.8.28
****************************************************************************
*/
#include "os.h"
#include "mac.h"
#include "message.h"
#include "app.h"
#include "led.h"
#include "physical.h"
#include "uartDebug.h"
#include "fun.h"
#include "macClock.h"
#include "radiocontrol.h" // 载波监听
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t OS_LOCAL_ADDRESS = 0x12;
uint8_t OS_BCAST_ADDR = 0xFF;
#define MAC_RETRY_LIMIT 2 // RTS重传最大次数
#define DIFS 10 // 空闲监听间隔
#define SIFS 1 // CTS,DATA,ACK包之前
#define EIFS 10 // 802.11在接收到错误帧后的重新监听间隔
#define TX_PKT_DONE_TIME 2000
#define SLOTTIME 1 // MAC层竞争窗口时隙长度
#define DATA_CW 31 // 数据帧退避窗口最大值
#define GUARDTIME 5
// MAC层状态
enum {
SLEEP,
IDLE,
CARR_SENSE,
TX_PKT,
BACKOFF,
WAIT_CTS,
WAIT_DATA,
WAIT_ACK
};
// 射频状态
enum { RADIO_SLEEP, RADIO_IDLE, RADIO_RX, RADIO_TX };
// 发送方式
enum { BCAST_DATA, SEND_SYNC, SEND_RTS, SEND_CTS, SEND_DATA, SEND_ACK };
// MAC 数据包类型
enum { RTS_PKT, CTS_PKT, DATA_PKT, ACK_PKT };
// 状态变量
static char state; // MAC 状态变量
static char radioState; //
// 计时变量
uint32_t clockTime; // 微秒为单位的MAC层时钟计数变量
uint16_t durCtrlPkt; // 发送控制帧需要的时间
uint16_t timeWaitCtrl; // 等待控制帧CTS、ACK的时间
uint16_t durDataPkt;
uint16_t timeWaitData; // 等待DATA的时间
uint16_t geneTime; //
uint8_t txDelay; // 短帧间隔到达定时,发送CTS、DATA、ACK之前等待的时间
uint8_t retryTime; //
// 发送相关变量
char txRequest; // 是否接受了一个发送请求,且未发送
char howToSend; // 发送包方式
uint16_t sendAddr; // 目的节点地址
uint8_t numRetry; // RTS重传次数
uint8_t numExtend; // ACK超时时发送时间的扩展次数
uint8_t txPktLen; // 传输的包长度
static OSMACMsgPtr dataPkt;// MAC包头指针
OSMACCtrlMsg ctrlPkt; // 控制包
// 接收相关变量
uint16_t recvAddr; // 数据包源地址
static void handleRTS(void* packet);
static void handleCTS(void* packet);
static void* handleDATA(void* packet);
static void handleACK(void* packet);
static void startBcast(void);
static void sendRTS(void);
static void sendCTS(void);
static void sendDATA(void);
static void sendACK(void);
static void tryToSend(void);
static void tryToResend(uint8_t delay);
static void txMsgDone(void);
/**********************************************************************************
初始化:
等待控制包的时间:timeWaitCtrl
**********************************************************************************/
result_t MACInit()
{
// 初始化状态变量
state = IDLE;
radioState = RADIO_IDLE;
// 初始化计时变量
clockTime = 0;
txDelay = 0;
// 初始化发送相关变量
txRequest = 0;
// 控制包初始化
ctrlPkt.fromAddr = OS_LOCAL_ADDRESS;
retryTime = 0;
// 初始化UART debugging
uartDebug_init();
// 初始化随机数生成器
RandomInit();
// 初始化并启动MAC层定时器
ClockStart();
// 初始化物理层
PhysicalInit();
return SUCCESS;
}
/*************************************************************************
*功能描述:发送数据包的开始,开始空闲监听,准备发送广播或者RTS数据包
*参数说明:
*返回值:
**************************************************************************/
static void tryToSend() // 判断是否允许发送,如果是,则进行监听
{
uint16_t backoffSlots, listenBits;
char intEnabled;
if (state == IDLE) { // 空闲时
howToSend = BCAST_DATA;
backoffSlots = RandomLFSRGen() & (uint16_t)DATA_CW; // 退避时间<=DATA_CW
listenBits = (DIFS + SLOTTIME * backoffSlots) * LISTEN_RATE; // 监听数 = kbps * ms = bits
// 开始载波监听,采用原子操作,防止起始字符检测到调用
intEnabled = inp(SREG) & 0x80;
cli();
if (RadiocontrolCarrierSenseStart(listenBits) == SUCCESS) { // 调用监听函数
state = CARR_SENSE;
}
if(intEnabled)
sei();
}
return;
}
/*************************************************************************
*功能描述:发送广播数据包的接口函数
*参数说明:包地址,包长度(MAC包数据部分的长度)
*返回值:
**************************************************************************/
result_t MACBroadcastMsg(void* data, uint8_t length)
{
char intEnabled;
// 错误的发送方式
if (data == 0 || length == 0 || length > MAX_PKT_LEN - - MAC_HEADER_LEN) {
return FAIL;
}
// 设置发送请求标识
intEnabled = inp(SREG) & 0x80;
cli();
if (txRequest == 0) {
txRequest = 1;
if (intEnabled) sei();
} else {
if (intEnabled) sei();
return FAIL;
}
dataPkt = (OSMACMsgPtr)data;
txPktLen = length + MAC_HEADER_LEN;
sendAddr = OS_BCAST_ADDR;
// 数据包包头设置
dataPkt->type = DATA_PKT;
dataPkt->toAddr = OS_BCAST_ADDR;
dataPkt->fromAddr = OS_LOCAL_ADDRESS;
dataPkt->group = 0x01;
tryToSend();
return SUCCESS;
}
/*************************************************************************
*功能描述:发送单播数据包的接口函数
*参数说明:包地址,包长度(包括包头),目的地址
*返回值:
**************************************************************************/
result_t MACUnicastMsg(void* data, uint8_t length, uint16_t toAddr)
{
return SUCCESS;
}
/*************************************************************************
*功能描述:强行取消所有正在发送的任务
*参数说明:无
*返回值:
**************************************************************************/
result_t MACTxReset()
{
txRequest = 0;
state = IDLE;
return SUCCESS;
}
/*************************************************************************
*功能描述:发送广播包
*参数说明:无
*返回值:
**************************************************************************/
static void startBcast()
{
PhysicalTxPkt(dataPkt, txPktLen); // 调用物理层发送接口发送数据包
radioState = RADIO_TX;
state = TX_PKT;
geneTime = TX_PKT_DONE_TIME; // 设置超时计时
}
/*************************************************************************
*功能描述:单播包分段发送完成,通知上层
*参数说明:无
*返回值:
**************************************************************************/
static void txMsgDone()
{
// 发送下一个分段
txRequest = 0;
state = IDLE;
// testMACUnicastDone(dataPkt);
LedYellowToggle();
}
/*************************************************************************
*功能描述:物理层发送完成,通知MAC
*参数说明:包地址
*返回值:
**************************************************************************/
result_t MACPhysicalTxPktDone(void* packet)
{
char pktType;
geneTime = 0;
radioState = RADIO_IDLE;
if (packet == 0 || state != TX_PKT)
return FAIL;
pktType = *((char*)packet + 1);
switch (pktType) {
case RTS_PKT:
break;
case CTS_PKT:
break;
case DATA_PKT:
if (((OSMACMsgPtr)packet)->toAddr == OS_BCAST_ADDR) {
state = IDLE;
txRequest = 0;
// testMACBroadcastDone(dataPkt);
LedYellowToggle();
}
break;
case ACK_PKT: // ACK发送完成,进入空闲
break;
}
return SUCCESS;
}
/*************************************************************************
*功能描述:CTS或ACK超时后尝试重发
*参数说明:包地址
*返回值:
**************************************************************************/
static void tryToResend(uint8_t delay)
{
if (numRetry < MAC_RETRY_LIMIT) {
numRetry++;
state = IDLE;
if (delay == 0) // 无延迟,立即重发
tryToSend();
else
retryTime = delay;
} else {
// 超过重发次数,发送失败
txMsgDone(); // txFragCount < txFragsAll;
}
}
/*************************************************************************
*功能描述:MAC定时维护,1ms一次
*参数说明:
*返回值:
**************************************************************************/
void MACClockFire()
{
// 本地时钟
clockTime++;
// ----------------------------generic timer-------------------------
// ----------------------------处理超时事件--------------------------
if (geneTime > 0) { // 为零时不执行
geneTime--;
if (geneTime == 0) {
if (state == WAIT_CTS) { // CTS timeout CTS等待超时
} else if (state == WAIT_ACK) { // ACK timeout等待超时
} else if (state == TX_PKT) { // 发送完成时限到达时仍未发送完成,即发包超时
PhysicalIdle();
radioState = RADIO_IDLE;
state = IDLE;
if (txRequest == 1) {
tryToSend();
}
}
}
}
if (retryTime > 0) {
retryTime--;
if (retryTime == 0) {
tryToSend();
// LedGreenToggle();
}
}
}
/*************************************************************************
*功能描述:物理层调用,通知MAC层信道忙,MAC转入空闲态,可以接收数据
*参数说明:
*返回值: 执行结果
**************************************************************************/
result_t MACChannelBusy()
{
if (state == CARR_SENSE) {
state = IDLE;
retryTime = EIFS;
}
return SUCCESS;
}
/*************************************************************************
*功能描述:物理层调用,通知MAC层信道闲,根据发送方式发送数据包
*参数说明:
*返回值: 执行结果
**************************************************************************/
result_t MACChannelIdle()
{
if (state != CARR_SENSE)
return FAIL;
if (howToSend == BCAST_DATA) {
startBcast();
} else if (howToSend == SEND_RTS) {
sendRTS();
}
return SUCCESS;
}
/*************************************************************************
*功能描述:物理层调用,检测到起始字符,通知MAC准备接收数据包
*参数说明:
*返回值: 执行结果
**************************************************************************/
result_t MACStartSymDetected(void* pkt)
{
radioState = RADIO_RX;
if (state == IDLE || state == CARR_SENSE) {
state = BACKOFF;
retryTime = 0;
}
return SUCCESS;
}
/*************************************************************************
*功能描述:处理错误数据包,进入睡眠
*参数说明:
*返回值: 执行结果
**************************************************************************/
static void handleErrPkt(void)
{
if (state == BACKOFF) state = IDLE;
if (state == IDLE) {
if (txRequest == 1) {
retryTime = EIFS;
}
}
}
/*************************************************************************
*功能描述:物理层调用,对已经接收到的数据包根据包类型调用相就的处理函数
*参数说明:包地址 接收出错标志
*返回值: 执行结果
**************************************************************************/
void* MACPhysicalRxPktDone(void* packet, char error)
{
char pktType;
radioState = RADIO_IDLE;
if (error) { // 接收到错误包,有碰撞发生
handleErrPkt();
return packet;
}
pktType = *((char*)packet + 1);
if (pktType == DATA_PKT) {
return handleDATA(packet);
} else if (pktType == RTS_PKT) {
handleRTS(packet);
} else if (pktType == CTS_PKT) {
handleCTS(packet);
} else if (pktType == ACK_PKT) {
handleACK(packet);
} else {
handleErrPkt();
}
return packet;
}
/*************************************************************************
*功能描述:对接收到的RTS数据包进行处理
*参数说明:包地址
*返回值:
**************************************************************************/
static void handleRTS(void* pkt)
{
}
/*************************************************************************
*功能描述:对接收到的CTS数据包进行处理
*参数说明:包地址
*返回值:
**************************************************************************/
static void handleCTS(void* pkt)
{
}
/*************************************************************************
*功能描述:对接收到的DATA数据包进行处理
*参数说明:包地址
*返回值: 包地址
**************************************************************************/
static void* handleDATA(void* pkt)
{
void* tmp = pkt;
OSMACMsgPtr packet = (OSMACMsgPtr)pkt;
if (packet->toAddr == OS_BCAST_ADDR) {
if (state == BACKOFF)
state = IDLE;
if (state == IDLE) {
if (txRequest == 1) {
tryToSend();
}
}
// tmp = testMACRxMsgDone(packet);
return tmp;
} else if (packet->toAddr == OS_LOCAL_ADDRESS) {
} else {
state = IDLE;
}
return pkt;
}
/*************************************************************************
*功能描述:对接收到的ACK数据包进行处理
*参数说明:包地址
*返回值:
**************************************************************************/
static void handleACK(void* pkt)
{
}
/*************************************************************************
*功能描述:设置RTS帧,发送RTS数据包
*参数说明:
*返回值:
**************************************************************************/
static void sendRTS()
{
}
/*************************************************************************
*功能描述:设置CTS帧,发送CTS数据包
*参数说明:
*返回值:
**************************************************************************/
static void sendCTS()
{
}
/*************************************************************************
*功能描述:设置DATA帧,发送数据包
*参数说明:
*返回值:
**************************************************************************/
static void sendDATA()
{
}
/*************************************************************************
*功能描述:设置ACK帧,发送数据包
*参数说明:
*返回值:
**************************************************************************/
static void sendACK()
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -