private static void OnSendStatus(IMAC macInstance, DateTime time, SendPacketStatus ACKStatus, uint transmitDestination, ushort index) { var pipe = macInstance as MACPipe; switch (ACKStatus) { case SendPacketStatus.SendACKed: #if DBG_DIAGNOSTIC Debug.Print("\t\tNet Manager: Retry queue length = " + _retriedPackets.Count); #endif #if !DBG_LOGIC Debug.Print("Heartbeat to " + transmitDestination.ToString() + " ACKed"); #endif // Update link metrics if ((ushort)transmitDestination == RoutingGlobal.Parent) { RoutingGlobal.UpdateNumReceivedInCurrentWindow_Parent(1); #if !DBG_LOGIC Debug.Print("Updated numReceivedInCurrentWindow for parent " + transmitDestination + "; new value = " + RoutingGlobal.GetNumReceivedInCurrentWindow_Parent()); #endif } else { byte cindex = CandidateTable.findIndex((ushort)transmitDestination); if (cindex < byte.MaxValue) { CandidateTable._candidateList[cindex].UpdateNumReceivedInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numReceivedInCurrentWindow for candidate " + transmitDestination + "; new value = " + CandidateTable._candidateList[cindex].GetNumReceivedInCurrentWindow()); #endif } } if (_retriedPackets.Contains(index)) // If this was a re-try, remove packet from queue { _retriedPackets.Remove(index); } break; case SendPacketStatus.SendNACKed: #if !DBG_LOGIC Debug.Print("Heartbeat to " + transmitDestination.ToString() + " NACKed"); #endif // Update link metrics if ((ushort)transmitDestination == RoutingGlobal.Parent) { RoutingGlobal.UpdateNumTriesInCurrentWindow_Parent(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for parent " + transmitDestination + "; new value = " + RoutingGlobal.GetNumTriesInCurrentWindow_Parent()); #endif } else { byte cindex = CandidateTable.findIndex((ushort)transmitDestination); if (cindex < byte.MaxValue) { CandidateTable._candidateList[cindex].UpdateNumTriesInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for candidate " + transmitDestination + "; new value = " + CandidateTable._candidateList[cindex].GetNumTriesInCurrentWindow()); #endif } } break; case SendPacketStatus.SendFailed: #if DBG_DIAGNOSTIC Debug.Print("\t\tNet Manager: Retry queue length = " + _retriedPackets.Count); #endif #if !DBG_LOGIC Debug.Print("Heartbeat to " + transmitDestination.ToString() + " failed"); #endif // Update link metrics if ((ushort)transmitDestination == RoutingGlobal.Parent) { RoutingGlobal.UpdateNumTriesInCurrentWindow_Parent(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for parent " + transmitDestination + "; new value = " + RoutingGlobal.GetNumTriesInCurrentWindow_Parent()); #endif } else { byte cindex = CandidateTable.findIndex((ushort)transmitDestination); if (cindex < byte.MaxValue) { CandidateTable._candidateList[cindex].UpdateNumTriesInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for candidate " + transmitDestination + "; new value = " + CandidateTable._candidateList[cindex].GetNumTriesInCurrentWindow()); #endif } } // Retry if (!_retriedPackets.Contains(index) && RoutingGlobal._color == Color.Green) // If packet not there, enqueue it and retry it once { RoutingGlobal.CleanseCandidateTable(pipe); Candidate tmpBst = CandidateTable.GetBestCandidate(false); NetManagerGlobal.TempParent = tmpBst.GetMacID(); byte[] msg = new byte[NetManagerGlobal.HeartbeatMessageSize]; if (pipe.GetMsgWithMsgID(ref msg, index) == DeviceStatus.Success) { NetManagerGlobal.SendToTempParent(pipe, msg, msg.Length); tmpBst.UpdateNumTriesInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for TempParent " + transmitDestination + "; new value = " + tmpBst.GetNumTriesInCurrentWindow()); #endif _retriedPackets.Add(index); } } else // Retried once; drop packet { _retriedPackets.Remove(index); } break; default: break; } }
/*CAUTION: Any change in the advanced heartbeat structure should be accounted for in variables * NetManagerGlobal.AdvHeartbeatFixedSize and NetManagerGlobal.EachNeighborInfoSize */ private static void Send_AdvancedHeartbeat(object state) { ushort[] neighbors = MACBase.NeighborListArray(); _neighborInfoManagerPipe.MACBase.MACNeighborList(neighbors); // Find the number of neighbors byte num_nbrs = 0; for (int i = 0; i < neighbors.Length; i++) { if (neighbors[i] == 0) // At the end { break; } num_nbrs++; } if (num_nbrs == 0) { return; } _numBeat++; ushort[] valid_nbrs; byte[] nbrStatus; ushort[] numSamplesRec; ushort[] numSyncSent; byte[] avgRSSI; byte[] ewrnp; byte[] isAvailableForUpperLayers; // TODO: Make this if-else more compact if (num_nbrs <= NetManagerGlobal.MaxNeighborsPerHeartbeat) // Send all information { valid_nbrs = new ushort[num_nbrs]; nbrStatus = new byte[num_nbrs]; numSamplesRec = new ushort[num_nbrs]; numSyncSent = new ushort[num_nbrs]; avgRSSI = new byte[num_nbrs]; ewrnp = new byte[num_nbrs]; isAvailableForUpperLayers = new byte[num_nbrs]; // Initialize ewrnp array with maxEtx for (int i = 0; i < ewrnp.Length; i++) { ewrnp[i] = RoutingGlobal.MaxEtx; } for (int i = 0; i < num_nbrs; i++) { var nbr_name = neighbors[i]; Neighbor nbr = _neighborInfoManagerPipe.NeighborStatus(nbr_name); valid_nbrs[i] = nbr_name; nbrStatus[i] = (byte)nbr.NeighborStatus; numSamplesRec[i] = nbr.NumOfTimeSamplesRecorded; numSyncSent[i] = nbr.NumTimeSyncMessagesSent; avgRSSI[i] = (byte)((nbr.ReceiveLink.AverageRSSI + nbr.SendLink.AverageRSSI)); // * 0.5; int index = CandidateTable.findIndex(nbr_name); if (RoutingGlobal.Parent == nbr_name) { ewrnp[i] = RoutingGlobal.GetPathEWRNP(); } else if (index < byte.MaxValue) { ewrnp[i] = (byte)CandidateTable._candidateList[index].GetPathEWRNP(); } isAvailableForUpperLayers[i] = nbr.IsAvailableForUpperLayers ? (byte)1 : (byte)0; } } else // Starting with the current head pointer, use neighbor list as a circular array to send out info for NetManagerGlobal.MaxNeighborsPerHeartbeat consecutive neighbors { valid_nbrs = new ushort[NetManagerGlobal.MaxNeighborsPerHeartbeat]; nbrStatus = new byte[NetManagerGlobal.MaxNeighborsPerHeartbeat]; numSamplesRec = new ushort[NetManagerGlobal.MaxNeighborsPerHeartbeat]; numSyncSent = new ushort[NetManagerGlobal.MaxNeighborsPerHeartbeat]; avgRSSI = new byte[NetManagerGlobal.MaxNeighborsPerHeartbeat]; ewrnp = new byte[NetManagerGlobal.MaxNeighborsPerHeartbeat]; isAvailableForUpperLayers = new byte[NetManagerGlobal.MaxNeighborsPerHeartbeat]; // Initialize ewrnp array with maxEtx for (int i = 0; i < ewrnp.Length; i++) { ewrnp[i] = RoutingGlobal.MaxEtx; } for (int i = 0; i < NetManagerGlobal.MaxNeighborsPerHeartbeat; i++) { // If current head pointer has a higher index than number of neighbors (owing to loss), restart at index 0; otherwise, start at current head pointer circ_headptr = (circ_headptr < num_nbrs) ? (byte)(circ_headptr % num_nbrs) : (byte)0; var nbr_name = neighbors[circ_headptr]; Neighbor nbr = _neighborInfoManagerPipe.NeighborStatus(nbr_name); valid_nbrs[i] = nbr_name; nbrStatus[i] = (byte)nbr.NeighborStatus; numSamplesRec[i] = nbr.NumOfTimeSamplesRecorded; numSyncSent[i] = nbr.NumTimeSyncMessagesSent; avgRSSI[i] = (byte)((nbr.ReceiveLink.AverageRSSI + nbr.SendLink.AverageRSSI)); // * 0.5; int index = CandidateTable.findIndex(nbr_name); if (RoutingGlobal.Parent == nbr_name) { ewrnp[i] = RoutingGlobal.GetPathEWRNP(); } else if (index < byte.MaxValue) { ewrnp[i] = (byte)CandidateTable._candidateList[index].GetPathEWRNP(); } isAvailableForUpperLayers[i] = nbr.IsAvailableForUpperLayers ? (byte)1 : (byte)0; circ_headptr = (byte)((circ_headptr + 1) % num_nbrs); } // Adjust circular buffer head pointer at the end circ_headptr = (byte)((circ_headptr + 1) % num_nbrs); } #if DBG_DIAGNOSTIC SystemGlobal.PrintNumericVals("Neighbor names: ", valid_nbrs); SystemGlobal.PrintNumericVals("Neighbor status: ", nbrStatus); SystemGlobal.PrintNumericVals("Avg RSSI: ", avgRSSI); SystemGlobal.PrintNumericVals("Routing EWRNP: ", ewrnp); SystemGlobal.PrintNumericVals("# samples rcvd: ", numSamplesRec); SystemGlobal.PrintNumericVals("# timesync sent: ", numSyncSent); SystemGlobal.PrintNumericVals("Available for upper layers: ", isAvailableForUpperLayers); Debug.Print("Parent: " + RoutingGlobal.Parent); Debug.Print(""); #endif var size = NetManagerGlobal.MoteMessages.Compose.Heartbeat(NetManagerGlobal.MsgBytes, _neighborInfoManagerPipe.MACRadioObj.RadioAddress, (ushort)_numBeat, SystemGlobal.NodeType, RoutingGlobal.Parent, (byte)RoutingGlobal.GetPathEWRNP(), valid_nbrs, nbrStatus, numSamplesRec, numSyncSent, avgRSSI, ewrnp, isAvailableForUpperLayers, RoutingGlobal.Infinity); //var size = NetManagerGlobal.MoteMessages.Compose.Heartbeat(NetManagerGlobal.MsgBytes, _neighborInfoManagerPipe.MACRadioObj.RadioAddress, (ushort)_numBeat, SystemGlobal.NodeType, RoutingGlobal.Parent, (byte)RoutingGlobal.BestEtx, neighbors, nbrStatus, avgRSSI, ewrnp); #if !DBG_LOGIC Debug.Print("NeighborInfo#" + _numBeat + " size: " + size); #endif #region Uncomment when not using scheduler // If in a reset, do not forward TODO: Change this to "spray" if (RoutingGlobal._color == Color.Red) { #if DBG_VERBOSE Debug.Print("\tIn a Reset wave... not forwarded"); #endif return; } // If parent is available, pass it on if (RoutingGlobal.IsParent) { var status = RoutingGlobal.SendToParent(_neighborInfoManagerPipe, NetManagerGlobal.MsgBytes, size); if (status != 999) { RoutingGlobal.UpdateNumTriesInCurrentWindow_Parent(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for Parent " + RoutingGlobal.Parent + "; new value = " + RoutingGlobal.GetNumTriesInCurrentWindow_Parent()); #endif if (!_sentPacketSizes.Contains(status)) { _sentPacketSizes.Add(status, size); } } else //Retry once { #if !DBG_LOGIC Debug.Print("Retrying packet"); #endif RoutingGlobal.CleanseCandidateTable(_neighborInfoManagerPipe); Candidate tmpBest = CandidateTable.GetBestCandidate(false); NetManagerGlobal.TempParent = tmpBest.GetMacID(); status = NetManagerGlobal.SendToTempParent(_neighborInfoManagerPipe, NetManagerGlobal.MsgBytes, size); if (status != 999) { tmpBest.UpdateNumTriesInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for TempParent " + NetManagerGlobal.TempParent + "; new value = " + tmpBest.GetNumTriesInCurrentWindow()); #endif if (!_sentPacketSizes.Contains(status)) { _sentPacketSizes.Add(status, size); } } } } #endregion }