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

📄 timesyncp.nc

📁 tinyos2.0版本驱动
💻 NC
字号:
/* * Copyright (c) 2002, Vanderbilt University * 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, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY 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 VANDERBILT * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE VANDERBILT UNIVERSITY 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 VANDERBILT UNIVERSITY HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * @author: Miklos Maroti, Brano Kusy (kusy@isis.vanderbilt.edu), Janos Sallai * Ported to T2: 3/17/08 by Brano Kusy (branislav.kusy@gmail.com) */#include "TimeSyncMsg.h"generic module TimeSyncP(typedef precision_tag){    provides    {        interface Init;        interface StdControl;        interface GlobalTime<precision_tag>;        //interfaces for extra functionality: need not to be wired        interface TimeSyncInfo;        interface TimeSyncMode;        interface TimeSyncNotify;    }    uses    {        interface Boot;        interface SplitControl as RadioControl;        interface TimeSyncAMSend<precision_tag,uint32_t> as Send;        interface Receive;        interface Timer<TMilli>;        interface Leds;        interface TimeSyncPacket<precision_tag,uint32_t>;        interface LocalTime<precision_tag> as LocalTime;    }}implementation{#ifndef TIMESYNC_RATE#define TIMESYNC_RATE   10#endif    enum {        MAX_ENTRIES           = 8,              // number of entries in the table        BEACON_RATE           = TIMESYNC_RATE,  // how often send the beacon msg (in seconds)        ROOT_TIMEOUT          = 5,              //time to declare itself the root if no msg was received (in sync periods)        IGNORE_ROOT_MSG       = 4,              // after becoming the root ignore other roots messages (in send period)        ENTRY_VALID_LIMIT     = 4,              // number of entries to become synchronized        ENTRY_SEND_LIMIT      = 3,              // number of entries to send sync messages        ENTRY_THROWOUT_LIMIT  = 100,            // if time sync error is bigger than this clear the table    };    typedef struct TableItem    {        uint8_t     state;        uint32_t    localTime;        int32_t     timeOffset; // globalTime - localTime    } TableItem;    enum {        ENTRY_EMPTY = 0,        ENTRY_FULL = 1,    };    TableItem   table[MAX_ENTRIES];    uint8_t tableEntries;    enum {        STATE_IDLE = 0x00,        STATE_PROCESSING = 0x01,        STATE_SENDING = 0x02,        STATE_INIT = 0x04,    };    uint8_t state, mode;/*    We do linear regression from localTime to timeOffset (globalTime - localTime).    This way we can keep the slope close to zero (ideally) and represent it    as a float with high precision.        timeOffset - offsetAverage = skew * (localTime - localAverage)        timeOffset = offsetAverage + skew * (localTime - localAverage)        globalTime = localTime + offsetAverage + skew * (localTime - localAverage)*/    float       skew;    uint32_t    localAverage;    int32_t     offsetAverage;    uint8_t     numEntries; // the number of full entries in the table    message_t processedMsgBuffer;    message_t* processedMsg;    message_t outgoingMsgBuffer;    TimeSyncMsg* outgoingMsg;    uint8_t heartBeats; // the number of sucessfully sent messages                        // since adding a new entry with lower beacon id than ours    async command uint32_t GlobalTime.getLocalTime()    {        return call LocalTime.get();    }    async command error_t GlobalTime.getGlobalTime(uint32_t *time)    {        *time = call GlobalTime.getLocalTime();        return call GlobalTime.local2Global(time);    }    error_t is_synced()    {      if (numEntries>=ENTRY_VALID_LIMIT || outgoingMsg->rootID==TOS_NODE_ID)        return SUCCESS;      else        return FAIL;    }    async command error_t GlobalTime.local2Global(uint32_t *time)    {        *time += offsetAverage + (int32_t)(skew * (int32_t)(*time - localAverage));        return is_synced();    }    async command error_t GlobalTime.global2Local(uint32_t *time)    {        uint32_t approxLocalTime = *time - offsetAverage;        *time = approxLocalTime - (int32_t)(skew * (int32_t)(approxLocalTime - localAverage));        return is_synced();    }    void calculateConversion()    {        float newSkew = skew;        uint32_t newLocalAverage;        int32_t newOffsetAverage;        int64_t localSum;        int64_t offsetSum;        int8_t i;        for(i = 0; i < MAX_ENTRIES && table[i].state != ENTRY_FULL; ++i)            ;        if( i >= MAX_ENTRIES )  // table is empty            return;/*        We use a rough approximation first to avoid time overflow errors. The idea        is that all times in the table should be relatively close to each other.*/        newLocalAverage = table[i].localTime;        newOffsetAverage = table[i].timeOffset;        localSum = 0;        offsetSum = 0;        while( ++i < MAX_ENTRIES )            if( table[i].state == ENTRY_FULL ) {                localSum += (int32_t)(table[i].localTime - newLocalAverage) / tableEntries;                offsetSum += (int32_t)(table[i].timeOffset - newOffsetAverage) / tableEntries;            }        newLocalAverage += localSum;        newOffsetAverage += offsetSum;        localSum = offsetSum = 0;        for(i = 0; i < MAX_ENTRIES; ++i)            if( table[i].state == ENTRY_FULL ) {                int32_t a = table[i].localTime - newLocalAverage;                int32_t b = table[i].timeOffset - newOffsetAverage;                localSum += (int64_t)a * a;                offsetSum += (int64_t)a * b;            }        if( localSum != 0 )            newSkew = (float)offsetSum / (float)localSum;        atomic        {            skew = newSkew;            offsetAverage = newOffsetAverage;            localAverage = newLocalAverage;            numEntries = tableEntries;        }    }    void clearTable()    {        int8_t i;        for(i = 0; i < MAX_ENTRIES; ++i)            table[i].state = ENTRY_EMPTY;        atomic numEntries = 0;    }    uint8_t numErrors=0;    void addNewEntry(TimeSyncMsg *msg)    {        int8_t i, freeItem = -1, oldestItem = 0;        uint32_t age, oldestTime = 0;        int32_t timeError;        tableEntries = 0;        // clear table if the received entry's been inconsistent for some time        timeError = msg->localTime;        call GlobalTime.local2Global(&timeError);        timeError -= msg->globalTime;        if( (is_synced() == SUCCESS) &&            (timeError > ENTRY_THROWOUT_LIMIT || timeError < -ENTRY_THROWOUT_LIMIT))        {            if (++numErrors>3)                clearTable();        }        else            numErrors = 0;        for(i = 0; i < MAX_ENTRIES; ++i) {            age = msg->localTime - table[i].localTime;            //logical time error compensation            if( age >= 0x7FFFFFFFL )                table[i].state = ENTRY_EMPTY;            if( table[i].state == ENTRY_EMPTY )                freeItem = i;            else                ++tableEntries;            if( age >= oldestTime ) {                oldestTime = age;                oldestItem = i;            }        }        if( freeItem < 0 )            freeItem = oldestItem;        else            ++tableEntries;        table[freeItem].state = ENTRY_FULL;        table[freeItem].localTime = msg->localTime;        table[freeItem].timeOffset = msg->globalTime - msg->localTime;    }    void task processMsg()    {        TimeSyncMsg* msg = (TimeSyncMsg*)(processedMsg->data);        if( msg->rootID < outgoingMsg->rootID &&            // jw: after becoming the root ignore other roots messages (in send period)            ~(heartBeats < IGNORE_ROOT_MSG && outgoingMsg->rootID == TOS_NODE_ID) ){            outgoingMsg->rootID = msg->rootID;            outgoingMsg->seqNum = msg->seqNum;        }        else if( outgoingMsg->rootID == msg->rootID && (int8_t)(msg->seqNum - outgoingMsg->seqNum) > 0 ) {            outgoingMsg->seqNum = msg->seqNum;        }        else            goto exit;        call Leds.led0Toggle();        if( outgoingMsg->rootID < TOS_NODE_ID )            heartBeats = 0;        addNewEntry(msg);        calculateConversion();        signal TimeSyncNotify.msg_received();    exit:        state &= ~STATE_PROCESSING;    }    event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len)    {#ifdef TIMESYNC_DEBUG   // this code can be used to simulate multiple hopsf        uint8_t incomingID = (uint8_t)((TimeSyncMsg*)payload)->nodeID;        int8_t diff = (incomingID & 0x0F) - (TOS_NODE_ID & 0x0F);        if( diff < -1 || diff > 1 )            return msg;        diff = (incomingID & 0xF0) - (TOS_NODE_ID & 0xF0);        if( diff < -16 || diff > 16 )            return msg;#endif        if( (state & STATE_PROCESSING) == 0 ) {            message_t* old = processedMsg;            processedMsg = msg;            ((TimeSyncMsg*)(processedMsg->data))->localTime = call TimeSyncPacket.eventTime(msg);            state |= STATE_PROCESSING;            post processMsg();            return old;        }        return msg;    }    task void sendMsg()    {        uint32_t localTime, globalTime;        globalTime = localTime = call GlobalTime.getLocalTime();        call GlobalTime.local2Global(&globalTime);        // we need to periodically update the reference point for the root        // to avoid wrapping the 32-bit (localTime - localAverage) value        if( outgoingMsg->rootID == TOS_NODE_ID ) {            if( (int32_t)(localTime - localAverage) >= 0x20000000 )            {                atomic                {                    localAverage = localTime;                    offsetAverage = globalTime - localTime;                }            }        }        else if( heartBeats >= ROOT_TIMEOUT ) {            heartBeats = 0; //to allow ROOT_SWITCH_IGNORE to work            outgoingMsg->rootID = TOS_NODE_ID;            ++(outgoingMsg->seqNum); // maybe set it to zero?        }        outgoingMsg->globalTime = globalTime;        // we don't send time sync msg, if we don't have enough data        if( numEntries < ENTRY_SEND_LIMIT && outgoingMsg->rootID != TOS_NODE_ID ){            ++heartBeats;            state &= ~STATE_SENDING;        }        else if( call Send.send(AM_BROADCAST_ADDR, &outgoingMsgBuffer, TIMESYNCMSG_LEN, localTime ) != SUCCESS ){            state &= ~STATE_SENDING;            signal TimeSyncNotify.msg_sent();        }    }    event void Send.sendDone(message_t* ptr, error_t error)    {        if (ptr != &outgoingMsgBuffer)          return;        if(error == SUCCESS)        {            ++heartBeats;            call Leds.led1Toggle();            if( outgoingMsg->rootID == TOS_NODE_ID )                ++(outgoingMsg->seqNum);        }        state &= ~STATE_SENDING;        signal TimeSyncNotify.msg_sent();    }    void timeSyncMsgSend()    {        if( outgoingMsg->rootID == 0xFFFF && ++heartBeats >= ROOT_TIMEOUT ) {            outgoingMsg->seqNum = 0;            outgoingMsg->rootID = TOS_NODE_ID;        }        if( outgoingMsg->rootID != 0xFFFF && (state & STATE_SENDING) == 0 ) {           state |= STATE_SENDING;           post sendMsg();        }    }    event void Timer.fired()    {      if (mode == TS_TIMER_MODE) {        timeSyncMsgSend();      }      else        call Timer.stop();    }    command error_t TimeSyncMode.setMode(uint8_t mode_){        if (mode == mode_)            return SUCCESS;        if (mode_ == TS_USER_MODE){            call Timer.startPeriodic((uint32_t)1000 * BEACON_RATE);        }        else            call Timer.stop();        mode = mode_;        return SUCCESS;    }    command uint8_t TimeSyncMode.getMode(){        return mode;    }    command error_t TimeSyncMode.send(){        if (mode == TS_USER_MODE){            timeSyncMsgSend();            return SUCCESS;        }        return FAIL;    }    command error_t Init.init()    {        atomic{            skew = 0.0;            localAverage = 0;            offsetAverage = 0;        };        clearTable();        atomic outgoingMsg = (TimeSyncMsg*)call Send.getPayload(&outgoingMsgBuffer, sizeof(TimeSyncMsg));        outgoingMsg->rootID = 0xFFFF;        processedMsg = &processedMsgBuffer;        state = STATE_INIT;        return SUCCESS;    }    event void Boot.booted()    {      call RadioControl.start();      call StdControl.start();    }    command error_t StdControl.start()    {        mode = TS_TIMER_MODE;        heartBeats = 0;        outgoingMsg->nodeID = TOS_NODE_ID;        call Timer.startPeriodic((uint32_t)1000 * BEACON_RATE);        return SUCCESS;    }    command error_t StdControl.stop()    {        call Timer.stop();        return SUCCESS;    }    async command float     TimeSyncInfo.getSkew() { return skew; }    async command uint32_t  TimeSyncInfo.getOffset() { return offsetAverage; }    async command uint32_t  TimeSyncInfo.getSyncPoint() { return localAverage; }    async command uint16_t  TimeSyncInfo.getRootID() { return outgoingMsg->rootID; }    async command uint8_t   TimeSyncInfo.getSeqNum() { return outgoingMsg->seqNum; }    async command uint8_t   TimeSyncInfo.getNumEntries() { return numEntries; }    async command uint8_t   TimeSyncInfo.getHeartBeats() { return heartBeats; }    default event void TimeSyncNotify.msg_received(){}    default event void TimeSyncNotify.msg_sent(){}    event void RadioControl.startDone(error_t error){}    event void RadioControl.stopDone(error_t error){}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -