⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mac.c

📁 adhoc信息节点程序源代码(点对多点)——for atmega128
💻 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 + -