📄 smacm.nc
字号:
/* * Copyright (c) 2002 the University of Southern California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF SOUTHERN CALIFORNIA BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE * UNIVERSITY OF SOUTHERN CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF SOUTHERN CALIFORNIA HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR * MODIFICATIONS. * * Authors: Wei Ye, Honghui Chen * * This module implements Sensor-MAC (S-MAC) * http://www.isi.edu/scadds/papers/smac_infocom.pdf * * It has the following functions. * 1) Low-duty-cycle operation on radio -- periodic listen and sleep * Option to disable sleep cycles * 2) Broadcast only uses CSMA * 3) Many features for unicast * - RTS/CTS for hidden terminal problem * - fragmentation support for a long message * A long message is divided (by upper layer) into multiple fragments. * The RTS/CTS reserves the medium for the entire message. * ACK is used for each fragment for immediate error recovery. * - Node goes to sleep when its neighbors are talking to other nodes. */includes uartDebug;module SMACM{ provides { interface StdControl as MACControl; interface MACComm; interface LinkState; interface MACTest; interface MACPerformance; interface MACReport; } uses { interface StdControl as PhyControl; interface RadioState; interface CarrierSense; interface PhyComm; interface Random; interface ClockSMAC as Clock; interface TimeStamp; interface PowerManagement; }}implementation{#include "SMACMsg.h"#include "PhyConst.h"#include "SMACConst.h"#include "smacEvents.h"//#define SMAC_DEBUG//#define SMAC_PERFORMANCE/* Internal S-MAC parameters * Do NOT change them unless for tuning S-MAC * User adjustable parameters are in SMACConst.h *-------------------------- * SLOTTIME: time of each slot in contention window, in ms. It should be large * enough to receive the whole start symbol. * DIFS: DCF interframe space (from 802.11), in ms. It is used at the beginning * of each contention window. It's the minmum time to wait to start a new * transmission. * SIFS: short interframe space (from 802.11), in ms. It is used before sending * an CTS or ACK packet. It takes care of the processing delay of each pkt. * TX_PKT_DONE_TIME: maximum time waiting for the packet TX done signal, in ms. * SYNC_CW: number of slots in the sync contention window, must be 2^n - 1 * DATA_CW: number of slots in the data contention window, must be 2^n - 1 * GUARDTIME: guard time at the end of each listen interval, in ms. * SYNC_PERIOD: period to send a sync pkt, in ms. * UPDATE_NEIGHB_PERIOD: period to update neighbor list, is n times of * SYNC_PERIOD. It is used in low duty cycle mode. If there is no SYNC pkts * from a node within this period, it will be removed from neighbor list. * DATA_ACTIVE_PERIOD (ms): This is only used in fully active mode to update * neighbor list. Since there is no SYNC pkts, data pkts are used to measure * if a neighbor is active recently. */#define DIFS 10#define SIFS 5#define EIFS 50#define TX_PKT_DONE_TIME 2000#define SLOTTIME 1#define SYNC_CW 15#define DATA_CW 31#define GUARDTIME 5#define SYNC_PERIOD 10000#define UPDATE_NEIGHB_PERIOD 12#define DATA_ACTIVE_PERIOD 600000// hardware clock resolution in ms#define CLOCK_RES 1 /* MAC states *------------- * SLEEP: radio is turned off, can't Tx or Rx * IDLE: radio in idle mode, will go to Rx if start symbol is deteded. * Can start Tx in this state * CARR_SENSE: carrier sense. Do it before initiate a Tx * TX_PKT: transmitting packet * BACKOFF - medium is busy, and cannot Tx * WAIT_CTS - just sent RTS, and is waiting for CTS * WAIT_DATA - just sent CTS, and is waiting for DATA * WAIT_ACK - just sent DATA, and is waiting for ACK * TX_NEXT_FRAG - just send one fragment, waiting to tx next fragment */ enum { SLEEP, IDLE, CARR_SENSE, TX_PKT, BACKOFF, WAIT_CTS, WAIT_DATA, WAIT_ACK, TX_NEXT_FRAG, DATA_SENSE1, DATA_SENSE2 }; // radio states enum { RADIO_SLEEP, RADIO_IDLE, RADIO_RX, RADIO_TX }; // how to send a pkt: broadcast or unicast enum { BCAST_DATA, SEND_SYNC, SEND_RTS, SEND_CTS, SEND_DATA, SEND_ACK }; // MAC packet types enum { DATA_PKT, RTS_PKT, CTS_PKT, ACK_PKT, SYNC_PKT }; // how to enter sleep mode enum { TRY, FORCE }; // data type definitions // note: pkt formats are defined in tos/include/smac_msg.h typedef struct { uint8_t numNodes; // number of nodes on this schedule char txSync; // flag indicating need to send sync char txData; // flag indicating need to send data char chkSched; // flag indicating need to check numNodes uint16_t counter; // tick counter } SchedTable; typedef struct { char state; uint16_t nodeId; uint8_t schedId; uint8_t active; //flag indicating the node is active recently uint8_t txSeqNo; // Tx sequence no of unicast packets to a node uint8_t rxSeqNo; // Rx sequence no of unicast packets from a node } NeighbList; // state variables char state; // MAC state char srchNeighb; // flag to keep listening for finding possible neighbors char schedListen; // flag indicating the time of scheduled listen char updateNeighbList; // flag indicating need to update neighbor list uint8_t numNeighb; // number of known neighbors NeighbList neighbList[SMAC_MAX_NUM_NEIGHB]; // neighbor list uint8_t numSched; // number of different schedules SchedTable schedTab[SMAC_MAX_NUM_SCHED]; // schedule table char radioState; // radio state char schedState; // schedule state: first, second schedule... // timing variables uint32_t clockTime; // clock time in mili-second uint16_t syncTime; // time of listen/contention interval for sync pkt uint16_t dataTime; // time of listen/contention interval for data pkt uint16_t listenTime; // time of listening interval uint16_t sleepTime; // time of sleeping interval uint16_t period; // period of my schedule =listenTime + sleepTime uint16_t timeToTxSync; // timer for sending SYNC packets to all schedules uint8_t numSyncPrd; // number of SYNC peroids, for dependent timers uint16_t durDataPkt; // duration (tx time needed) of data packet uint16_t durCtrlPkt; // duration (tx time needed) of control packet uint16_t durSyncPkt; // duration (tx time needed) of sync packet uint16_t timeWaitCtrl; // time to wait for a control packet uint16_t nav; // network allocation vector. nav>0 -> medium busy uint16_t neighbNav; // track neighbors' NAV while I'm sending/receiving uint16_t geneTime; // generic timer uint8_t neighbListTime; // timer for track nodes activity in neighbor list uint8_t txDelay; // timer for carrier sense uint16_t adapTime; // timer for adaptive listen uint8_t retryTime; // number of retries in unicast#ifdef SMAC_NO_SLEEP_CYCLE uint32_t dataActiveTime; // timer for updating neighbor list#endif // Variables for Tx char txRequest; // if I have accept a tx request; char howToSend; // what action to take for tx uint16_t sendAddr; // node that I'm sending data to uint8_t dataSched; // current schedule I'm talking to uint8_t syncSched; // current schedule I'm talking to uint8_t numRetry; // number of RTS tries for a data pkt uint8_t numExtend; // number of Tx time extensions when ACK timeout uint8_t numSyncTx; // number of times to send a SYNC (multiple schedules) uint8_t numBcast; // number of times to broadcast a pkt (multiple scheds) uint8_t txFragAll; // number of fragments in this transmission uint8_t txFragCount; // number of transmitted fragments uint8_t txPktLen; // length of data pkt to be transmitted uint8_t syncSeqNo; // Tx sequence number for SYNC packets uint8_t bcastSeqNo; // Tx sequence number for broadcast data packets MACHeader* dataPkt; // pointer to tx data pkt, only access MAC header MACCtrlPkt ctrlPkt; // MAC control packet MACSyncPkt syncPkt; // MAC sync packet // Variables for Rx uint16_t recvAddr; // node that I'm receiving data from uint8_t rxFragAll; // number of fragments to be received in a msg uint8_t lastRxFrag; // fragment no of last received fragment // Variables for link state measurement uint8_t numTx1Msg; // number of Tx on a msg, including reTx on frags uint8_t numRx1Msg; // number of Rx on a msg, including duplicated frags uint8_t numTxFragOld; // number of Tx on a single fragment#ifdef SMAC_REPORT uint32_t crcErr; uint32_t lenErr; uint32_t retx; uint32_t ctrlPkts;#endif#ifdef SMAC_DEBUG char numLenErr; char numCrcErr; char numSlpPkt; char numCTStimeout; char numDATAtimeout; char numACKtimeout; char numSleeps; char numWakeups; char syncDiff1; // debug time difference in received SYNC pkt char syncDiff2; // time difference bigger than GUARDTIME#endif#ifdef SMAC_PERFORMANCE char cntRadioTime; RadioTime radioTime;#endif// update my NAV#define UPDATE_NAV(duration) { \ if (nav < duration) nav = duration; \}// track my neighbors' NAV#define TRACK_NAV(duration) { \ if (neighbNav < duration) neighbNav = duration; \} // function prototypes result_t getNodeIdx(uint16_t nodeAddr, uint8_t* nodeIdx, uint8_t* emptyIdx); void sleep(char manner); void wakeup(); void setMySched(MACSyncPkt* packet, uint16_t refTime); void update_neighbList(); void checkMySched(); void check_schedFlag(); void update_schedTab_neighbList(); void handleRTS(void* packet); void handleCTS(void* packet); void* handleDATA(void* packet); void handleACK(void* packet); void handleSYNC(void* packet); void startBcast(); void sendRTS(); void sendCTS(); void sendDATA(); void sendACK(); void sendSYNC(); void tryToSend(); void tryToResend(uint8_t delay); void txMsgDone(); command result_t MACControl.init() { uint8_t i; // initialize constants durCtrlPkt = (PRE_PKT_BYTES + sizeof(MACCtrlPkt) * ENCODE_RATIO) * 8 / BANDWIDTH + 1; durSyncPkt = (PRE_PKT_BYTES + sizeof(MACSyncPkt) * ENCODE_RATIO) * 8 / BANDWIDTH + 1; syncTime = DIFS + SLOTTIME * SYNC_CW + durSyncPkt + GUARDTIME; // added time for overhearing CTS so that can do adaptive listen dataTime = DIFS + SLOTTIME * DATA_CW + durCtrlPkt + PROC_DELAY + SIFS + durCtrlPkt + GUARDTIME; listenTime = syncTime + dataTime; period = listenTime * 100 / SMAC_DUTY_CYCLE + 1; sleepTime = period - listenTime; // time to wait for CTS or ACK timeWaitCtrl = PROC_DELAY + SIFS + durCtrlPkt + PROC_DELAY; // initialize state variables state = IDLE; radioState = RADIO_IDLE; // initialize neighbor list numNeighb = 0; // number of known neighbors neighbListTime = 0; updateNeighbList = 0; for (i = 0; i < SMAC_MAX_NUM_NEIGHB; i++) { neighbList[i].state = 0; // invalid or dead } // initialize schedule table for (i = 0; i < SMAC_MAX_NUM_SCHED; i++) { schedTab[i].numNodes = 0; } #ifndef SMAC_NO_SLEEP_CYCLE // choose a tentative schedule, but don't broadcast until // listening for a whole SYNC_PERIOD. schedState = 1; // this is my first schedule numSched = 1; schedTab[0].numNodes = 1; // I'm the only one on this schedule schedTab[0].txData = 0; schedTab[0].txSync = 0; schedTab[0].chkSched = 0; schedTab[0].counter = listenTime; // Don't go to sleep for the first SYNC period. srchNeighb = 1; numSyncPrd = 1; schedListen = 1;#ifdef SMAC_SLAVE_SCHED // don't broadcast my schedule, and keeps listening for an existing one timeToTxSync = 0;#else timeToTxSync = SYNC_PERIOD; // set timer to broadcast my schedule#endif // SMAC_SLAVE_SCHED#endif // SMAC_NO_SLEEP_CYCLE // initialize timing variables clockTime = 0; nav = 0; neighbNav = 0; txDelay = 0; adapTime = 0;#ifdef SMAC_NO_SLEEP_CYCLE retryTime = 0;#endif // initialize Tx variables txRequest = 0; syncSeqNo = 0; bcastSeqNo = 0; // fill in fixed portion of control packet ctrlPkt.fromAddr = TOS_LOCAL_ADDRESS; // fill in fixed portion of sync packet syncPkt.fromAddr = TOS_LOCAL_ADDRESS; syncPkt.type = SYNC_PKT << 4; syncPkt.state = schedState;#ifdef SMAC_DEBUG numLenErr = 0; numCrcErr = 0; numCTStimeout = 0; numDATAtimeout = 0; numACKtimeout = 0; numSleeps = 0; numWakeups = 0; syncDiff1 = 100; // initialize to a big value to easily see its change syncDiff2 = 100;#endif#ifdef SMAC_PERFORMANCE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -