@ Created: April 24, 2006
*/
-#include "LinkEstimator.h"
+#include "./LinkEstimator.h"
module LinkEstimatorP {
provides {
// configure the link estimator and some constants
enum {
- // If the eetx estimate is below this threshold
+ // If the etx 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,
+ EVICT_ETX_THRESHOLD = 65,
// 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,
+ BEST_ETX = 10,
INVALID_RVAL = 0xff,
INVALID_NEIGHBOR_ADDR = 0xff,
- INFINITY = 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_ETX_VALUE = 0xffff,
// decay the link estimate using this alpha
// we use a denominator of 10, so this corresponds to 0.2
- ALPHA = 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
+ // largest ETX value that we feed into the link quality EWMA
+ // a value of 70 corresponds to having to make six transmissions
// to successfully receive one acknowledgement
- LARGE_EETX_VALUE = 60
+ LARGE_ETX_VALUE = 70
};
// keep information about links from the neighbors
// the packet.
uint8_t addLinkEstHeaderAndFooter(message_t *msg, uint8_t len) {
uint8_t newlen;
- linkest_header_t *hdr;
- linkest_footer_t *footer;
+ linkest_header_t * ONE hdr;
+ linkest_footer_t * ONE footer;
uint8_t i, j, k;
uint8_t maxEntries, newPrevSentIdx;
dbg("LI", "newlen1 = %d\n", len);
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) {
- footer->neighborList[j].ll_addr = NeighborTable[k].ll_addr;
- footer->neighborList[j].inquality = NeighborTable[k].inquality;
+ 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, footer->neighborList[j].ll_addr,
- footer->neighborList[j].inquality);
+ dbg("LI", "Loaded on footer: %d %d %d\n", j, neighborLists[j].ll_addr,
+ neighborLists[j].inquality);
j++;
}
}
ne->rcvcnt = 0;
ne->failcnt = 0;
ne->flags = (INIT_ENTRY | VALID_ENTRY);
- ne->inage = MAX_AGE;
ne->inquality = 0;
- ne->eetx = 0;
+ ne->etx = 0;
}
// find the index to the entry for neighbor ll_addr
// 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 findWorstNeighborIdx(uint8_t thresholdETX) {
uint8_t i, worstNeighborIdx;
- uint16_t worstEETX, thisEETX;
+ uint16_t worstETX, thisETX;
worstNeighborIdx = INVALID_RVAL;
- worstEETX = 0;
+ worstETX = 0;
for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) {
if (!(NeighborTable[i].flags & VALID_ENTRY)) {
dbg("LI", "Invalid so continuing\n");
dbg("LI", "Pinned entry, so continuing\n");
continue;
}
- thisEETX = NeighborTable[i].eetx;
- if (thisEETX >= worstEETX) {
+ thisETX = NeighborTable[i].etx;
+ if (thisETX >= worstETX) {
worstNeighborIdx = i;
- worstEETX = thisEETX;
+ worstETX = thisETX;
}
}
- if (worstEETX >= thresholdEETX) {
+ if (worstETX >= thresholdETX) {
return worstNeighborIdx;
} else {
return INVALID_RVAL;
}
- // update the EETX estimator
+ // update the ETX 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;
+ void updateETX(neighbor_table_entry_t *ne, uint16_t newEst) {
+ ne->etx = (ALPHA * ne->etx + (10 - ALPHA) * newEst)/10;
}
- // update data driven EETX
- void updateDEETX(neighbor_table_entry_t *ne) {
+ // update data driven ETX
+ void updateDETX(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;
+ estETX = ne->data_total * 10;
} else {
- estETX = (10 * ne->data_total) / ne->data_success - 10;
+ estETX = (10 * ne->data_total) / ne->data_success;
ne->data_success = 0;
ne->data_total = 0;
}
- updateEETX(ne, estETX);
+ updateETX(ne, estETX);
}
- // EETX (Extra Expected number of Transmission)
- // EETX = ETX - 1
- // computeEETX returns EETX*10
- uint8_t computeEETX(uint8_t q1) {
+ // ETX (Expected number of Transmission)
+ // computeETX returns ETX*10
+ uint16_t computeETX(uint8_t q1) {
uint16_t q;
if (q1 > 0) {
- q = 2550 / q1 - 10;
- if (q > 255) {
- q = INFINITY;
+ q = 2500 / q1;
+ if (q > 250) {
+ q = VERY_LARGE_ETX_VALUE;
}
- return (uint8_t)q;
+ return q;
} else {
- return INFINITY;
+ return VERY_LARGE_ETX_VALUE;
}
}
ne = &NeighborTable[i];
if (ne->ll_addr == n) {
if (ne->flags & VALID_ENTRY) {
- if (ne->inage > 0)
- ne->inage--;
-
- if (ne->inage == 0) {
- ne->flags ^= VALID_ENTRY;
- ne->inquality = 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, computeEETX(ne->inquality));
- }
- 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);
+ newEst = (250UL * 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;
+ updateETX(ne, computeETX(ne->inquality));
+ } else {
dbg("LI", " - entry %i is invalid.\n", (int)i);
}
}
if (NeighborTable[idx].flags & INIT_ENTRY) {
dbg("LI", "Init entry update\n");
- NeighborTable[idx].lastseq = seq;
NeighborTable[idx].flags &= ~INIT_ENTRY;
}
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;
+ initNeighborIdx(idx, NeighborTable[idx].ll_addr);
+ NeighborTable[idx].lastseq = seq;
NeighborTable[idx].rcvcnt = 1;
- NeighborTable[idx].inquality = 0;
- }
-
- if (NeighborTable[idx].rcvcnt >= BLQ_PKT_WINDOW) {
+ } else if (((NeighborTable[idx].rcvcnt + NeighborTable[idx].failcnt) >= BLQ_PKT_WINDOW)
+ || (packetGap >= BLQ_PKT_WINDOW)) {
updateNeighborTableEst(NeighborTable[idx].ll_addr);
}
for (i = 0; i < NEIGHBOR_TABLE_SIZE; i++) {
ne = &NeighborTable[i];
if (ne->flags & VALID_ENTRY) {
- dbg("LI,LITest", "%d:%d inQ=%d, inA=%d, rcv=%d, fail=%d, Q=%d\n",
- i, ne->ll_addr, ne->inquality, ne->inage,
- ne->rcvcnt, ne->failcnt, computeEETX(ne->inquality));
+ dbg("LI,LITest", "%d:%d inQ=%d, rcv=%d, fail=%d, Q=%d\n",
+ i, ne->ll_addr, ne->inquality,
+ ne->rcvcnt, ne->failcnt, computeETX(ne->inquality));
}
}
}
}
// return bi-directional link quality to the neighbor
- command uint8_t LinkEstimator.getLinkQuality(am_addr_t neighbor) {
+ command uint16_t LinkEstimator.getLinkQuality(am_addr_t neighbor) {
uint8_t idx;
idx = findIdx(neighbor);
if (idx == INVALID_RVAL) {
- return INFINITY;
+ return VERY_LARGE_ETX_VALUE;
} else {
- return NeighborTable[idx].eetx;
- };
+ if (NeighborTable[idx].flags & MATURE_ENTRY) {
+ return NeighborTable[idx].etx;
+ } else {
+ return VERY_LARGE_ETX_VALUE;
+ }
+ }
}
// insert the neighbor at any cost (if there is a room for it)
initNeighborIdx(nidx, neighbor);
return SUCCESS;
} else {
- nidx = findWorstNeighborIdx(BEST_EETX);
+ nidx = findWorstNeighborIdx(BEST_ETX);
if (nidx != INVALID_RVAL) {
dbg("LI", "insert: inserted by replacing an entry for neighbor: %d\n",
NeighborTable[nidx].ll_addr);
ne->data_success++;
ne->data_total++;
if (ne->data_total >= DLQ_PKT_WINDOW) {
- updateDEETX(ne);
+ updateDETX(ne);
}
return SUCCESS;
}
ne = &NeighborTable[nidx];
ne->data_total++;
if (ne->data_total >= DLQ_PKT_WINDOW) {
- updateDEETX(ne);
+ updateDETX(ne);
}
return SUCCESS;
}
// done sending the message that originated by
// the user of this component
event void AMSend.sendDone(message_t* msg, error_t error ) {
- return signal Send.sendDone(msg, error);
+ signal Send.sendDone(msg, error);
}
// cascade the calls down
// called when link estimator generator packet or
// packets from upper layer that are wired to pass through
// link estimator is received
- void processReceivedMessage(message_t* msg, void* payload, uint8_t len) {
+ void processReceivedMessage(message_t* ONE msg, void* COUNT_NOK(len) payload, uint8_t len) {
uint8_t nidx;
uint8_t num_entries;
initNeighborIdx(nidx, ll_addr);
updateNeighborEntryIdx(nidx, hdr->seq);
} else {
- nidx = findWorstNeighborIdx(EVICT_EETX_THRESHOLD);
+ nidx = findWorstNeighborIdx(EVICT_ETX_THRESHOLD);
if (nidx != INVALID_RVAL) {
dbg("LI", "Evicted neighbor %d at idx %d\n",
NeighborTable[nidx].ll_addr, nidx);
initNeighborIdx(nidx, ll_addr);
} else {
dbg("LI", "No room in the table\n");
- if (signal CompareBit.shouldInsert(msg,
- call Packet.getPayload(msg, call Packet.payloadLength(msg)),
- call Packet.payloadLength(msg),
- call LinkPacketMetadata.highChannelQuality(msg))) {
- nidx = findRandomNeighborIdx();
- if (nidx != INVALID_RVAL) {
- signal LinkEstimator.evicted(NeighborTable[nidx].ll_addr);
- initNeighborIdx(nidx, ll_addr);
+
+ /* if the white bit is set, lets ask the router if the path through
+ this link is better than at least one known path - if so
+ lets insert this link into the table.
+ */
+ if (call LinkPacketMetadata.highChannelQuality(msg)) {
+ if (signal CompareBit.shouldInsert(msg,
+ call Packet.getPayload(msg, call Packet.payloadLength(msg)),
+ call Packet.payloadLength(msg))) {
+ nidx = findRandomNeighborIdx();
+ if (nidx != INVALID_RVAL) {
+ signal LinkEstimator.evicted(NeighborTable[nidx].ll_addr);
+ initNeighborIdx(nidx, ll_addr);
+ }
}
}
}
// application payload pointer is just past the link estimation header
command void* Packet.getPayload(message_t* msg, uint8_t len) {
- linkest_header_t *hdr = getHeader(msg);
- uint8_t footerLen = (hdr->flags & NUM_ENTRIES_FLAG) * sizeof(linkest_header_t);
- void* payload = call SubPacket.getPayload(msg, len + footerLen);
+ void* payload = call SubPacket.getPayload(msg, len + sizeof(linkest_header_t));
if (payload != NULL) {
payload += sizeof(linkest_header_t);
}