📄 linkestimatorp.nc
字号:
/* $Id: LinkEstimatorP.nc,v 1.15 2008/06/04 05:45:20 regehr Exp $ *//* * "Copyright (c) 2006 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, the following two paragraphs and the author 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." * *//* @ author Omprakash Gnawali @ Created: April 24, 2006 */#include "LinkEstimator.h"module LinkEstimatorP { provides { interface StdControl; interface AMSend as Send; interface Receive; interface LinkEstimator; interface Init; interface Packet; interface CompareBit; } uses { interface AMSend; interface AMPacket as SubAMPacket; interface Packet as SubPacket; interface Receive as SubReceive; interface LinkPacketMetadata; interface Random; }}implementation { // configure the link estimator and some constants enum { // If the eetx estimate is below this threshold // do not evict a link EVICT_EETX_THRESHOLD = 55, // maximum link update rounds before we expire the link MAX_AGE = 6, // if received sequence number if larger than the last sequence // number by this gap, we reinitialize the link MAX_PKT_GAP = 10, BEST_EETX = 0, INVALID_RVAL = 0xff, INVALID_NEIGHBOR_ADDR = 0xff, // if we don't know the link quality, we need to return a value so // large that it will not be used to form paths VERY_LARGE_EETX_VALUE = 0xff, // decay the link estimate using this alpha // we use a denominator of 10, so this corresponds to 0.2 ALPHA = 9, // number of packets to wait before computing a new // DLQ (Data-driven Link Quality) DLQ_PKT_WINDOW = 5, // number of beacons to wait before computing a new // BLQ (Beacon-driven Link Quality) BLQ_PKT_WINDOW = 3, // largest EETX value that we feed into the link quality EWMA // a value of 60 corresponds to having to make six transmissions // to successfully receive one acknowledgement LARGE_EETX_VALUE = 60 }; // keep information about links from the neighbors neighbor_table_entry_t NeighborTable[NEIGHBOR_TABLE_SIZE]; // link estimation sequence, increment every time a beacon is sent uint8_t linkEstSeq = 0; // if there is not enough room in the packet to put all the neighbor table // entries, in order to do round robin we need to remember which entry // we sent in the last beacon uint8_t prevSentIdx = 0; // get the link estimation header in the packet linkest_header_t* getHeader(message_t* m) { return (linkest_header_t*)call SubPacket.getPayload(m, sizeof(linkest_header_t)); } // get the link estimation footer (neighbor entries) in the packet linkest_footer_t* getFooter(message_t* ONE m, uint8_t len) { // To get a footer at offset "len", the payload must be len + sizeof large. return (linkest_footer_t* ONE)(len + (uint8_t *)call Packet.getPayload(m,len + sizeof(linkest_footer_t))); } // add the link estimation header (seq no) and link estimation // footer (neighbor entries) in the packet. Call just before sending // the packet. uint8_t addLinkEstHeaderAndFooter(message_t * ONE msg, uint8_t len) { uint8_t newlen; linkest_header_t *hdr; linkest_footer_t *footer; uint8_t i, j, k; uint8_t maxEntries, newPrevSentIdx; dbg("LI", "newlen1 = %d\n", len); hdr = getHeader(msg); footer = getFooter(msg, len); maxEntries = ((call SubPacket.maxPayloadLength() - len - sizeof(linkest_header_t)) / sizeof(linkest_footer_t)); // Depending on the number of bits used to store the number // of entries, we can encode up to NUM_ENTRIES_FLAG using those bits if (maxEntries > NUM_ENTRIES_FLAG) { maxEntries = NUM_ENTRIES_FLAG; } dbg("LI", "Max payload is: %d, maxEntries is: %d\n", call SubPacket.maxPayloadLength(), maxEntries); j = 0; newPrevSentIdx = 0; for (i = 0; i < NEIGHBOR_TABLE_SIZE && j < maxEntries; i++) { uint8_t neighborCount; neighbor_stat_entry_t * COUNT(neighborCount) neighborLists; if(maxEntries <= NEIGHBOR_TABLE_SIZE) neighborCount = maxEntries; else neighborCount = NEIGHBOR_TABLE_SIZE; neighborLists = TCAST(neighbor_stat_entry_t * COUNT(neighborCount), footer->neighborList); k = (prevSentIdx + i + 1) % NEIGHBOR_TABLE_SIZE; if ((NeighborTable[k].flags & VALID_ENTRY) && (NeighborTable[k].flags & MATURE_ENTRY)) { neighborLists[j].ll_addr = NeighborTable[k].ll_addr; neighborLists[j].inquality = NeighborTable[k].inquality; newPrevSentIdx = k; dbg("LI", "Loaded on footer: %d %d %d\n", j, neighborLists[j].ll_addr, neighborLists[j].inquality); j++; } } prevSentIdx = newPrevSentIdx; hdr->seq = linkEstSeq++; hdr->flags = 0; hdr->flags |= (NUM_ENTRIES_FLAG & j); newlen = sizeof(linkest_header_t) + len + j*sizeof(linkest_footer_t); dbg("LI", "newlen2 = %d\n", newlen); return newlen; } // initialize the given entry in the table for neighbor ll_addr void initNeighborIdx(uint8_t i, am_addr_t ll_addr) { neighbor_table_entry_t *ne; ne = &NeighborTable[i]; ne->ll_addr = ll_addr; ne->lastseq = 0; ne->rcvcnt = 0; ne->failcnt = 0; ne->flags = (INIT_ENTRY | VALID_ENTRY); ne->inage = MAX_AGE; ne->outage = MAX_AGE; ne->inquality = 0; ne->outquality = 0; ne->eetx = 0; } // find the index to the entry for neighbor ll_addr uint8_t findIdx(am_addr_t ll_addr) { uint8_t i; for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) { if (NeighborTable[i].flags & VALID_ENTRY) { if (NeighborTable[i].ll_addr == ll_addr) { return i; } } } return INVALID_RVAL; } // find an empty slot in the neighbor table uint8_t findEmptyNeighborIdx() { uint8_t i; for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) { if (NeighborTable[i].flags & VALID_ENTRY) { } else { return i; } } return INVALID_RVAL; } // find the index to the worst neighbor if the eetx // estimate is greater than the given threshold uint8_t findWorstNeighborIdx(uint8_t thresholdEETX) { uint8_t i, worstNeighborIdx; uint16_t worstEETX, thisEETX; worstNeighborIdx = INVALID_RVAL; worstEETX = 0; for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) { if (!(NeighborTable[i].flags & VALID_ENTRY)) { dbg("LI", "Invalid so continuing\n"); continue; } if (!(NeighborTable[i].flags & MATURE_ENTRY)) { dbg("LI", "Not mature, so continuing\n"); continue; } if (NeighborTable[i].flags & PINNED_ENTRY) { dbg("LI", "Pinned entry, so continuing\n"); continue; } thisEETX = NeighborTable[i].eetx; if (thisEETX >= worstEETX) { worstNeighborIdx = i; worstEETX = thisEETX; } } if (worstEETX >= thresholdEETX) { return worstNeighborIdx; } else { return INVALID_RVAL; } } // update the quality of the link link: self->neighbor // this is found in the entries in the footer of incoming message void updateReverseQuality(am_addr_t neighbor, uint8_t outquality) { uint8_t idx; idx = findIdx(neighbor); if (idx != INVALID_RVAL) { NeighborTable[idx].outquality = outquality; NeighborTable[idx].outage = MAX_AGE; } } // update the EETX estimator // called when new beacon estimate is done // also called when new DEETX estimate is done void updateEETX(neighbor_table_entry_t *ne, uint16_t newEst) { ne->eetx = (ALPHA * ne->eetx + (10 - ALPHA) * newEst)/10; } // update data driven EETX void updateDEETX(neighbor_table_entry_t *ne) { uint16_t estETX; if (ne->data_success == 0) { // if there were no successful packet transmission in the // last window, our current estimate is the number of failed // transmissions estETX = (ne->data_total - 1)* 10; } else { estETX = (10 * ne->data_total) / ne->data_success - 10; ne->data_success = 0; ne->data_total = 0; } updateEETX(ne, estETX); } // EETX (Extra Expected number of Transmission) // EETX = ETX - 1 // computeEETX returns EETX*10 uint8_t computeEETX(uint8_t q1) { uint16_t q; if (q1 > 0) { q = 2550 / q1 - 10; if (q > 255) { q = VERY_LARGE_EETX_VALUE; } return (uint8_t)q; } else { return VERY_LARGE_EETX_VALUE; } } // BidirETX = 1 / (q1*q2) // BidirEETX = BidirETX - 1 // computeBidirEETX return BidirEETX*10 uint8_t computeBidirEETX(uint8_t q1, uint8_t q2) { uint16_t q; if ((q1 > 0) && (q2 > 0)) { q = 65025u / q1; q = (10*q) / q2 - 10; if (q > 255) { q = LARGE_EETX_VALUE; } return (uint8_t)q; } else { return LARGE_EETX_VALUE; } } // update the inbound link quality by // munging receive, fail count since last update void updateNeighborTableEst(am_addr_t n) { uint8_t i, totalPkt; neighbor_table_entry_t *ne; uint8_t newEst; uint8_t minPkt; minPkt = BLQ_PKT_WINDOW; dbg("LI", "%s\n", __FUNCTION__); for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) { ne = &NeighborTable[i]; if (ne->ll_addr == n) { if (ne->flags & VALID_ENTRY) { if (ne->inage > 0) ne->inage--; if (ne->outage > 0) ne->outage--; if ((ne->inage == 0) && (ne->outage == 0)) { ne->flags ^= VALID_ENTRY; ne->inquality = ne->outquality = 0; } else { dbg("LI", "Making link: %d mature\n", i); ne->flags |= MATURE_ENTRY; totalPkt = ne->rcvcnt + ne->failcnt; dbg("LI", "MinPkt: %d, totalPkt: %d\n", minPkt, totalPkt); if (totalPkt < minPkt) { totalPkt = minPkt; } if (totalPkt == 0) { ne->inquality = (ALPHA * ne->inquality) / 10; } else { newEst = (255 * ne->rcvcnt) / totalPkt; dbg("LI,LITest", " %hu: %hhu -> %hhu", ne->ll_addr, ne->inquality, (ALPHA * ne->inquality + (10-ALPHA) * newEst)/10); ne->inquality = (ALPHA * ne->inquality + (10-ALPHA) * newEst)/10; } ne->rcvcnt = 0; ne->failcnt = 0; } updateEETX(ne, computeBidirEETX(ne->inquality, ne->outquality)); } else { dbg("LI", " - entry %i is invalid.\n", (int)i); } } } } // we received seq from the neighbor in idx // update the last seen seq, receive and fail count // refresh the age void updateNeighborEntryIdx(uint8_t idx, uint8_t seq) { uint8_t packetGap; if (NeighborTable[idx].flags & INIT_ENTRY) { dbg("LI", "Init entry update\n"); NeighborTable[idx].lastseq = seq; NeighborTable[idx].flags &= ~INIT_ENTRY; } packetGap = seq - NeighborTable[idx].lastseq; dbg("LI", "updateNeighborEntryIdx: prevseq %d, curseq %d, gap %d\n", NeighborTable[idx].lastseq, seq, packetGap); NeighborTable[idx].lastseq = seq; NeighborTable[idx].rcvcnt++; NeighborTable[idx].inage = MAX_AGE; if (packetGap > 0) { NeighborTable[idx].failcnt += packetGap - 1; } if (packetGap > MAX_PKT_GAP) { NeighborTable[idx].failcnt = 0; NeighborTable[idx].rcvcnt = 1; NeighborTable[idx].outage = 0; NeighborTable[idx].outquality = 0; NeighborTable[idx].inquality = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -