private static void Send_Heartbeat(object state) { _numBeat++; #if RELAY_NODE || CLIENT_NODE var size = NetManagerGlobal.MoteMessages.Compose.Heartbeat(NetManagerGlobal.MsgBytes, _netManagerPipe.MACRadioObj.RadioAddress, (ushort)_numBeat, SystemGlobal.NodeType, RoutingGlobal.Parent, RoutingGlobal.Infinity); // 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(_netManagerPipe, 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 } else //Retry once { #if !DBG_LOGIC Debug.Print("Retrying packet"); #endif RoutingGlobal.CleanseCandidateTable(_netManagerPipe); Candidate tmpBest = CandidateTable.GetBestCandidate(false); NetManagerGlobal.TempParent = tmpBest.GetMacID(); status = NetManagerGlobal.SendToTempParent(_netManagerPipe, 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 } } } #region unused // Otherwise, broadcast it // { // SystemGlobal.BroadcastBeacon(_netManagerPipe, NetManagerGlobal.MsgBytes, size); //#if DBG_VERBOSE // DebuggingSupport.PrintMessageSent(_netManagerPipe, "(broadcast) Heartbeat #" + _numBeat); // SystemGlobal.PrintNumericVals("Net Manager ", NetManagerGlobal.MsgBytes, size); //#elif DBG_SIMPLE // Debug.Print("\tBroadcastBeacon heartbeat # " + _numBeat); //#endif // } #endregion #endif #if BASE_STATION var msg = NetManagerGlobal.PCMessages.Compose.Heartbeat(_netManagerPipe.MACRadioObj.RadioAddress, _numBeat, SystemGlobal.NodeTypes.Base, RoutingGlobal.Parent); try { var status = _serialComm.Write(msg); if (status) { #if DBG_VERBOSE Debug.Print("\n************ Heartbeat generated to PC " + msg.Substring(1, msg.Length - 2)); #elif DBG_SIMPLE Debug.Print("Heartbeat generated"); #endif } else { Debug.Print("Error sending [" + msg + "] to PC"); } } catch (Exception ex) { Debug.Print("SerialComm exception for Heartbeat message [" + msg + "]\n" + ex); } #endif }
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; } }
/// <summary> /// /// </summary> /// <param name="macBase"></param> /// <param name="dateTime"></param> private static void NetManagerStreamReceive(IMAC macBase, DateTime dateTime, Packet packet) { #if DBG_VERBOSE DebuggingSupport.PrintMessageReceived(macBase, "Net Manager"); #elif DBG_SIMPLE Debug.Print(""); #endif //Debug.Print("\ton " + packet.PayloadType); var rcvPayloadBytes = packet.Payload; //var payload = new string(Encoding.UTF8.GetChars(rcvPayloadBytes)); #if DBG_VERBOSE SystemGlobal.PrintNumericVals("Net Manager Rcv: ", rcvPayloadBytes); #elif DBG_SIMPLE Debug.Print(""); #endif switch ((NetManagerGlobal.MessageIds)rcvPayloadBytes[0]) { case NetManagerGlobal.MessageIds.Heartbeat: ushort originator; ushort numBeat; SystemGlobal.NodeTypes nodeType; ushort parent; byte TTL; NetManagerGlobal.MoteMessages.Parse.HeartBeat(rcvPayloadBytes, out originator, out numBeat, out nodeType, out parent, out TTL); // NetManagerGlobal.MoteMessages.Parse.HeartBeat(rcvPayloadBytes, out originator, out numBeat, out nodeType, out parent, out bestetx, out neighbors, out nbrStatus, out numSamplesRec, out numSyncSent, out avgRSSI, out ewrnp); // NetManagerGlobal.MoteMessages.Parse.HeartBeat(rcvPayloadBytes, out originator, out numBeat, out nodeType, out parent, out bestetx, out num_nbrs, out neighbors, out nbrStatus, out numSamplesRec, out numSyncSent, out avgRSSI, out ewrnp, out isAvailableForUpperLayers, out TTL); Debug.Print("\t>>> Heartbeat #" + numBeat + " from neighbor " + packet.Src + " by " + originator + " with TTL " + TTL); #if DBG_DIAGNOSTIC Debug.Print("Parent: " + parent); Debug.Print(""); #endif #if RELAY_NODE || CLIENT_NODE // If we're the originator of the message, or if (TTL-1) is 0, do not pass it on. if (originator == _netManagerPipe.MACRadioObj.RadioAddress || --TTL == 0) { return; } RoutingGlobal.AddChild(originator, packet.Src); #region Uncomment when not using scheduler // TODO: Uncomment lines 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) { byte[] routedMsg = new byte[rcvPayloadBytes.Length]; var size = NetManagerGlobal.MoteMessages.Compose.Heartbeat(routedMsg, originator, numBeat, nodeType, parent, TTL); var status = RoutingGlobal.SendToParent(_netManagerPipe, routedMsg, 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 } else //Retry once { #if !DBG_LOGIC Debug.Print("Retrying packet"); #endif RoutingGlobal.CleanseCandidateTable(_netManagerPipe); Candidate tmpBest = CandidateTable.GetBestCandidate(false); NetManagerGlobal.TempParent = tmpBest.GetMacID(); status = NetManagerGlobal.SendToTempParent(_netManagerPipe, routedMsg, size); if (status != 999) { tmpBest.UpdateNumTriesInCurrentWindow(1); #if !DBG_LOGIC Debug.Print("Updated numTriesInCurrentWindow for TempParent " + NetManagerGlobal.TempParent + "; new value = " + tmpBest.GetNumTriesInCurrentWindow()); #endif } } } #endregion #region unused // If parent is not available, broadcast it //{ // //var size = NetManagerGlobal.ComposeMessages.CreateHeartbeat(NetManagerGlobal.MsgBytes, _netManagerPipe.MACRadioObj.RadioAddress); // SystemGlobal.BroadcastBeacon(_netManagerPipe, rcvPayloadBytes, packet.Size); //} //if (payload.Substring(0, 9).Equals("Heartbeat")) //Relay heartbeats, generated hourly //{ // Debug.Print("\tReceived Heartbeat: " + payload.Substring(0, 9) + "; source: " + payload.Substring(9) + "; from neighbor: " + packet.Src); // if (RoutingGlobal.Parent == SystemGlobal.NoParent) // { // return; // } // var toSendByte = Encoding.UTF8.GetBytes(payload); // var status = _netManagerPipe.Send(RoutingGlobal.Parent, toSendByte, 0, (ushort)toSendByte.Length); // if (status != NetOpStatus.S_Success) // { // Debug.Print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Send status: " + status); // } // SystemGlobal.PrintNumericVals("Net Manager Snd: ", toSendByte); // Debug.Print("Forwarded Heartbeat: " + payload.Substring(0, 9) + "; source: " + payload.Substring(9) + "; from Node: " + packet.Src + " to Node: " + RoutingGlobal.Parent); //} #endregion #endif #if BASE_STATION string msg = NetManagerGlobal.PCMessages.Compose.Heartbeat(originator, numBeat, nodeType, parent); try { _serialComm.Write(msg); #if DBG_VERBOSE Debug.Print("\n************ Heartbeat forwarded to PC " + msg.Substring(1, msg.Length - 2)); #endif } catch (Exception ex) { Debug.Print("SerialComm exception for Heartbeat message [" + msg + "]\n" + ex); } #endif break; default: throw new ArgumentOutOfRangeException(); } }
/*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 }