13721449590 李燕茹
S-MAC 的实现主要继承于 BasicMac 类,而 BasicMac 主要继承于 cSimpleModule。此外,
S-MAC 根据自己的算法,添加了一些与协议有关的函数。S-MAC 类定义如下:
class SMac: public BasicMac
{
//构造,析构,模块
Module_Class_Members(SMac, BasicMac, 0);
protected:
unsigned int listen_time;
unsigned int sleep_time;
unsigned int frame_time;
ushort sched_table[10]; // 邻居调度表
int sched_count;
SchedStates sched_state;
ushort time_last_sched;
// 节点自身上次调度的时间
ProtoState proto_state;
ProtoState proto_next_state;
int nav_state;
ushort nav_end_time;
int must_send_sync;
int resync_counter;
Packet * tx_msg;
int rts_contend_time;
int cts_to;
ushort cts_nav_end;
ushort cts_nav_rcv;
ushort cts_nav_t;
int ack_to;
int ack_serial;
int my_serial;
void setMySchedule(ushort time); // 产生自己的调度
void evalState();
// 检查状态
void startContending(int time);
void sendSync();
void sendRts();
// 竞争,冲突避免
// 发送同步消息
// 接收同步消息
void sendCts();
void sendData();
void sendAck();
void receiveSync(Packet * msg);
void receiveRts(Packet * msg);
void receiveCts(Packet * msg);
void receiveData(Packet * msg);
void receiveAck(Packet * msg);
void adoptSchedule(int offset); // 其他调度
void calcSchedState();
void setIdle();
// 重新计算调度状态
void protocolTimeout();
void navTimeout();
void schedTimeout();
void setProtocolTimeout(int t);
void setNavTimeout(int t);
void setSchedTimeout(int t);
void updateNav(ushort nav);
void txDone();
virtual void endForce();
int isSameSchedule(int time1, int time2);
virtual int mustUseCA(Packet * msg);
//virtual void incBackoff();
virtual void decBackoff();
virtual void init();
virtual void timeout(int which);
virtual void txPacket(Packet * msg);
virtual void rxFrame(Packet * msg);
virtual void transmitDone();
virtual void rxFailed();
virtual void rxStarted();
virtual int headerLength();
};
S-MAC 协议的主要函数实现如下:
调度函数
void SMac::setMySchedule(ushort time)
{
// 在时间
assert(time < frame_time);
time_last_sched = currentTime() + time - frame_time; // 计算自己的帧的调度时间
must_send_sync = 1;
resync_counter = NEW_RESYNC_COUNTER;
printf(PRINT_MAC, "schedule: %d", time_last_sched % frame_time);
calcSchedState();
}
状态检查函数
void SMac::evalState()
{
if (proto_state == PROTO_STATE_IDLE && !isReceiving())
{
// 空闲
if (nav_state == NAV_STATE_CLEAR && sched_state !=
CHED_STATE_SLEEP)
{
// 侦听 / 活动状态
if (must_send_sync)
{
printf(PRINT_MAC, "preparing to send SYNC %s",tx_msg?"(data
pending)":"");
// 开始竞争
proto_next_state = PROTO_STATE_SEND_SYNC;
startContending(SYNC_CONTEND_TIME);
return;
}
if (tx_msg && sched_state == SCHED_STATE_OWN)
{
if (mustUseCA(tx_msg)) //冲突避免
{
printf(PRINT_MAC, "preparing to send RTS");
// 开始竞争
proto_next_state = PROTO_STATE_SEND_RTS;
startContending(rts_contend_time);
}
else
{
printf(PRINT_MAC, "preparing to send data");
proto_next_state = PROTO_STATE_SEND_DATA;
startContending(RTS_CONTEND_TIME);
}
return;
}
// 只侦听
printf(PRINT_MAC, "idle listening");
setRadioListen();
// 睡眠状态
printf(PRINT_MAC, "idle sleeping");
if (getForce() != FORCE_NOSLEEP)
setRadioSleep();
}
else
{
}
}
}
竞争函数
void SMac::startContending(int time)
{
assert(proto_next_state >= 0);
assert(time >= 5);
if (nav_state == NAV_STATE_BUSY)
{
printf(PRINT_MAC, "contend: skipping because nav is busy");
proto_next_state = PROTO_STATE_INVALID;
setIdle();
proto_state = PROTO_STATE_CONTEND;
int ctime = (int) intuniform(5, time);
printf(PRINT_MAC, "starting contention, will fire in %d", ctime);
setRadioListen();
setProtocolTimeout(ctime);
}
else
{
}
}
接收函数
void SMac::rxFrame(Packet * msg)
{
assert(msg);
if (sched_state == SCHED_STATE_SLEEP && getForce()!=FORCE_NOSLEEP)
return; // 睡眠中,放弃
if (proto_state == PROTO_STATE_WFCTS && (PKT_KIND(msg) != KIND_CTS ||
msg->local_to != nodeId()))
{
printf(PRINT_MAC, "received packet, but not cts we want");
cancelTimeout(TIMER_PROTOCOL);
proto_state = PROTO_STATE_IDLE;
}
if (proto_state == PROTO_STATE_WFACK && (PKT_KIND(msg) != KIND_ACK ||
msg->local_to != nodeId() || PKT_SERIAL(msg) != my_serial))
{
}
printf(PRINT_MAC, "received packet, but not ack we want");
cancelTimeout(TIMER_PROTOCOL);
proto_state = PROTO_STATE_IDLE;
assert(sched_state != SCHED_STATE_SLEEP || getForce() == FORCE_NOSLEEP);
switch (PKT_KIND(msg))
{
case KIND_SYNC:
receiveSync(msg);
break;
case KIND_RTS:
receiveRts(msg);
break;
case KIND_CTS:
receiveCts(msg);
break;
case KIND_DATA:
receiveData(msg);
break;
case KIND_ACK:
receiveAck(msg);
break;
default:
assert(false);
}
evalState();
}
协议超时处理函数
void SMac::protocolTimeout()
{
int next_state;
switch (proto_state)
{
case PROTO_STATE_CONTEND:
assert(proto_next_state >= 0);
assert(!isReceiving());
assert(nav_state == NAV_STATE_CLEAR);
// RSSI 是接收信号强度指示
setRadioListen(); // 侦听信号
if(getRssi()>0.5) { // 有信号
printf(PRINT_MAC,
"sensed communication, cancelling");
setIdle();
return;
}
// 启动下个状态
next_state = proto_next_state;
proto_next_state = PROTO_STATE_INVALID;
switch (next_state)
{
case PROTO_STATE_SEND_SYNC:
sendSync();
break;
case PROTO_STATE_SEND_RTS:
sendRts();
break;
case PROTO_STATE_SEND_CTS:
sendCts();
break;
case PROTO_STATE_SEND_DATA:
sendData();
break;
case PROTO_STATE_SEND_ACK:
sendAck();
break;
default:
assert(false);
}
break;
case PROTO_STATE_WFCTS:
printf(PRINT_MAC, "wait-for-cts timeout");
setIdle();
break;
case PROTO_STATE_WFDATA:
printf(PRINT_MAC, "wait-for-data timeout");
setIdle();
break;
case PROTO_STATE_WFACK:
printf(PRINT_MAC, "wait-for-ack timeout");
setIdle();
break;
default:
assert(false);
}
}
发送同步消息函数
void SMac::sendSync()
{
printf(PRINT_MAC, "sending sync");
must_send_sync = 0;
proto_state = PROTO_STATE_SEND_SYNC;
Packet *msg = new Packet("sync");
msg->local_from = nodeId();
msg->local_to = -1;
//-1 表示广播
PKT_KIND(msg) = KIND_SYNC;
ushort now = currentTime();
unsigned long est = EST_SYNC_TIME;
assert(time_last_sched+(int)frame_time > now+EST_SYNC_TIME);
unsigned long stime = time_last_sched + frame_time // 下一帧的时间
- now
// 发送时延
- est;
//- EST_SYNC_TIME;
// 下一帧之前的时间
// 发送时延
//assert(now>900);
assert(stime>0);
stime &= 0xFFFF;
assert(stime < frame_time);
PKT_SYNC(msg) = stime;
msg->setLength(SYNC_SIZE);
setRadioTransmit();
reg_tx_overhead(msg);
startTransmit(msg);
}
接收同步消息函数
void SMac::receiveSync(Packet * msg)
{
assert(msg);
reg_rx_overhead(msg);
ushort stime = (ushort) PKT_SYNC(msg);
delete msg;
if (sched_state == SCHED_STATE_STARTUP)
{
cancelTimeout(TIMER_SCHED);
printf(PRINT_MAC, "received SYNC, following");
setMySchedule(stime);
return;
}
// 检查偏移
int ftime = (int)currentTime() + stime;
if (isSameSchedule(ftime, time_last_sched))
{
// 帧启动时间
printf(PRINT_MAC, "received SYNC, my own schedule");
return;
}
// 检查其他调度
int i;
for (i = 0; i < sched_count; i++)
{
if (isSameSchedule(ftime, time_last_sched + sched_table[i]))
{
printf(PRINT_MAC, "received SYNC, known schedule");
return;
}
}
// 新的调度
printf(PRINT_MAC, "adopting foreign schedule");
int offset = ftime - time_last_sched;
if (offset < 0)
offset += 65536;
offset %= frame_time;
assert(offset > 0);
//assert(offset < (int)frame_time);
adoptSchedule(offset);
}
计算调度状态函数
void SMac::calcSchedState()
{
ushort t = currentTime();
unsigned in_f = (ushort) (t - time_last_sched);
assert(listen_time>0);
// 检查是否在自己当前帧的发送时间内