diff --git a/examples/manetrouting/leach/LeachExample.ned b/examples/manetrouting/leach/LeachExample.ned new file mode 100644 index 00000000000..6d3812c81ed --- /dev/null +++ b/examples/manetrouting/leach/LeachExample.ned @@ -0,0 +1,37 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +package inet.examples.manetrouting.leach; + +import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator; +import inet.node.contract.INetworkNode; +import inet.node.inet.SensorNode; +import inet.physicallayer.wireless.common.contract.packetlevel.IRadioMedium; +import inet.visualizer.contract.IIntegratedVisualizer; +import inet.environment.common.PhysicalEnvironment; + +network LeachExample +{ + parameters: + int numNodes; + @display("bgb=200,200;bgg=100,1,grey95"); + @figure[title](type=label; pos=0,-1; anchor=sw; color=darkblue); + + submodules: + configurator: Ipv4NetworkConfigurator { + @display("p=100,100"); + } + radioMedium: like IRadioMedium { + @display("p=100,100"); + } + physicalEnvironment: PhysicalEnvironment { + @display("p=100,100"); + } + host[numNodes]: like INetworkNode { + @display("i=misc/sensor2"); + } + baseStation: like INetworkNode { + @display("p=50,50;i=misc/sensorgateway"); + } +} diff --git a/examples/manetrouting/leach/address.xml b/examples/manetrouting/leach/address.xml new file mode 100644 index 00000000000..116b8d5051a --- /dev/null +++ b/examples/manetrouting/leach/address.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/manetrouting/leach/omnetpp.ini b/examples/manetrouting/leach/omnetpp.ini new file mode 100644 index 00000000000..c981a815934 --- /dev/null +++ b/examples/manetrouting/leach/omnetpp.ini @@ -0,0 +1,84 @@ +[General] +network = LeachExample + +num-rngs = 2 +seed-0-mt= 4900 # used for node layout generation (can set any preferred value) +seed-1-mt = 7 # used for threshold comparison (can set any preferred value) + +**.arp.typename = "GlobalArp" + +*.radioMedium.typename = "Ieee802154NarrowbandScalarRadioMedium" +*.radioMedium.backgroundNoise.typename = "IsotropicScalarBackgroundNoise" +*.radioMedium.backgroundNoise.power = -100dBm +*.radioMedium.mediumLimitCache.centerFrequency = 2GHz + +*.host*.hasStatus = true +*.visualizer.energyStorageVisualizer.displayEnergyStorages = true + +*.configurator.config = xmldoc ("address.xml") + +*.baseStation.typename = "LeachBS" +*.host*.typename = "LeachNode" + +*.numNodes = 100 #100 +*.host*.mobility.typename = "StationaryMobility" +*.host*.mobility.rng-0 = 0 # random number generator mapping + +*.host[*].mobility.initFromDisplayString = false + +**.constraintAreaMinX = 1m +**.constraintAreaMaxX = 100m +**.constraintAreaMinY = 1m +**.constraintAreaMaxY = 100m + +*.host*.wlan[0].typename = "Ieee802154NarrowbandInterface" +*.host*.wlan[0].radio.typename = "ApskScalarRadio" +*.host*.wlan[0].radio.centerFrequency = 2.5GHz # based on TI CC2520 +*.host*.wlan[0].radio.bandwidth = 2MHz +*.host*.wlan[0].radio.transmitter.power = 60.5mW # determines communication range - based on CC2520 +*.host*.wlan[0].radio.transmitter.preambleDuration = 192us # based on TI CC2520 +*.host*.wlan[0].radio.transmitter.headerLength = 6B # based on TI CC2520 +*.host*.wlan[0].radio.receiver.sensitivity = -98dBm # based on TI CC2520 +*.host*.wlan[0].radio.receiver.energyDetection = -85dBm +*.host*.wlan[0].radio.receiver.snirThreshold = 4dB +*.host*.wlan[0].radio.displayCommunicationRange = true + + +*.baseStation.wlan[0].typename = "Ieee802154NarrowbandInterface" +*.baseStation.wlan[0].radio.typename = "ApskScalarRadio" +*.baseStation.wlan[0].radio.centerFrequency = 2.5GHz +*.baseStation.wlan[0].radio.bandwidth = 2MHz +*.baseStation.wlan[0].radio.transmitter.power = 60.5mW +*.baseStation.wlan[0].radio.transmitter.preambleDuration = 192us +*.baseStation.wlan[0].radio.transmitter.headerLength = 6B +*.baseStation.wlan[0].radio.receiver.sensitivity = -98dBm +*.baseStation.wlan[0].radio.receiver.energyDetection = -85dBm +*.baseStation.wlan[0].radio.receiver.snirThreshold = 4dB +*.baseStation.wlan[0].radio.displayCommunicationRange = true + +*.host*.**.bitrate = 250kbps # based on TI CC2520 +*.baseStation.**.bitrate = 250kbps + +[Config LeachPower] +extends = General + +*.host*.energyStorage.typename = "SimpleCcBattery" +*.host*.energyStorage.nominalCapacity = 7200C # calculated for 2 x AA cells +*.host*.energyStorage.initialCapacity = 7100C +*.host*.energyStorage.nominalVoltage = 1.5V +*.host*.energyStorage.internalResistance = 0.1Ohm + +*.host*.wlan[0].radio.energyConsumer.typename = "StateBasedCcEnergyConsumer" +*.host*.wlan[0].radio.energyConsumer.offCurrentConsumption = 0A +*.host*.wlan[0].radio.energyConsumer.switchingCurrentConsumption = 1mA +*.host*.wlan[0].radio.energyConsumer.receiverIdleCurrentConsumption = 18.8mA # based on CC2520 +*.host*.wlan[0].radio.energyConsumer.receiverBusyCurrentConsumption = 24.8mA # based on CC2520 +*.host*.wlan[0].radio.energyConsumer.receiverReceivingCurrentConsumption = 26.3mA # based on CC2520 +*.host*.wlan[0].radio.energyConsumer.transmitterIdleCurrentConsumption = 25.8mA # based on CC2520 +*.host*.wlan[0].radio.energyConsumer.transmitterTransmittingCurrentConsumption = 33.6mA # based on CC2520 + +[Config LeachPathLoss] +extends = General + +*.host*.wlan[0].radio.displayInterferenceRange = true +*.radioMedium.pathLoss.typename = "LogNormalShadowing" diff --git a/src/inet/node/leach/LeachBS.ned b/src/inet/node/leach/LeachBS.ned new file mode 100644 index 00000000000..4654b134852 --- /dev/null +++ b/src/inet/node/leach/LeachBS.ned @@ -0,0 +1,29 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +package inet.node.leach; + +import inet.node.inet.AdhocHost; +import inet.routing.leach.LeachBS; + +// +// This module provides Low-Energy Adaptive Clustering Hierarchy (LEACH) +// routing protocol for the data sink/base station. +// This implementation is designed to use a a single wireless interface and run on +// the IEEE 802.15.4 standard for MAC and Physical layers. +// This module simply receives data from the sensor nodes. +// +// For more information on the algorithm, see the LEACH paper +// https://ieeexplore.ieee.org/document/926982 +// +module LeachBS extends AdhocHost +{ + submodules: + LeachBS: LeachBS { + @display("p=825,226"); + } + connections: + LeachBS.ipOut --> tn.in++; + LeachBS.ipIn <-- tn.out++; +} diff --git a/src/inet/node/leach/LeachNode.ned b/src/inet/node/leach/LeachNode.ned new file mode 100644 index 00000000000..6f24a11f1ec --- /dev/null +++ b/src/inet/node/leach/LeachNode.ned @@ -0,0 +1,31 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +package inet.node.leach; + +import inet.node.inet.AdhocHost; +import inet.routing.leach.Leach; + +// +// This module provides Low-Energy Adaptive Clustering Hierarchy (LEACH) +// routing protocol for sensor nodes. +// LEACH is a hierachical adhoc routing protocol for Wireless Sensor Networks. +// This implementation is designed to use a a single wireless interface and run on +// the IEEE 802.15.4 standard for MAC and Physical layers. +// Therefore the standard TDMA scheduling system has been implemented +// with delayed time slots due to the use of CSMA in the 802.15.4 standard. +// +// For more information on the algorithm, see the LEACH paper +// https://ieeexplore.ieee.org/document/926982 +// +module LeachNode extends AdhocHost +{ + submodules: + LeachNode: Leach { + @display("p=825,226"); + } + connections: + LeachNode.ipOut --> tn.in++; + LeachNode.ipIn <-- tn.out++; +} diff --git a/src/inet/routing/leach/Leach.cc b/src/inet/routing/leach/Leach.cc new file mode 100644 index 00000000000..ef93c13fd6b --- /dev/null +++ b/src/inet/routing/leach/Leach.cc @@ -0,0 +1,478 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#include "inet/common/IProtocolRegistrationListener.h" +#include "inet/common/ModuleAccess.h" +#include "inet/common/ProtocolTag_m.h" +#include "inet/linklayer/common/InterfaceTag_m.h" +#include "inet/networklayer/common/L3AddressTag_m.h" +#include "inet/physicallayer/wireless/common/contract/packetlevel/SignalTag_m.h" +#include "inet/networklayer/common/L3AddressResolver.h" +#include "inet/common/lifecycle/LifecycleOperation.h" +#include "inet/common/lifecycle/ModuleOperations.h" +#include "inet/common/lifecycle/NodeStatus.h" +#include "inet/common/lifecycle/LifecycleController.h" +#include "inet/routing/leach/Leach.h" +#include "inet/transportlayer/contract/udp/UdpControlInfo.h" + +namespace inet { +namespace leach { + +Register_Enum(inet::leach::Leach, (Leach::ch, Leach::nch)); +Define_Module(Leach); + +Leach::Leach() { + +} + +Leach::~Leach() { + cancelAndDelete(event); + stop(); +} + +void Leach::initialize(int stage) { + RoutingProtocolBase::initialize(stage); + + //reads from omnetpp.ini + if (stage == INITSTAGE_LOCAL) { + sequencenumber = 0; + host = getContainingNode(this); + interfaceTable.reference(this, "interfaceTableModule", true); + + clusterHeadRatio = par("clusterHeadRatio"); + roundDurationVariance = par("roundDurationVariance"); + interfaces = par("interfaces"); + + roundDuration = dblrand(0) * roundDurationVariance; + TDMADelayCounter = 1; + event = new cMessage("event"); + wasCH = false; + + } else if (stage == INITSTAGE_ROUTING_PROTOCOLS) { + registerProtocol(Protocol::manet, gate("ipOut"), gate("ipIn")); + } +} + +void Leach::start() { + // Search the 802154 interface + configureInterfaces(); + + // schedules a random periodic event + scheduleAt(simTime() + uniform(0.0, par("startupDelay").doubleValue()), + event); +} + +void Leach::stop() { + nodeMemory.clear(); + nodeCHMemory.clear(); + extractedTDMASchedule.clear(); + TDMADelayCounter = 1; +} + +void Leach::configureInterfaces() { + cPatternMatcher interfaceMatcher(interfaces, false, true, false); + int numInterfaces = interfaceTable->getNumInterfaces(); + for (int i = 0; i < numInterfaces; i++) { + NetworkInterface *networkInterface = interfaceTable->getInterface(i); + if (networkInterface->isMulticast() + && interfaceMatcher.matches( + networkInterface->getInterfaceName())) { + wirelessInterface = networkInterface; + } + } +} + +void Leach::handleMessageWhenUp(cMessage *msg) { + // if node is sending message + if (msg->isSelfMessage()) { + double randNo = dblrand(1); + double threshold = generateThresholdValue(round); + + if (randNo < threshold && wasCH == false) { + setLeachState(ch); // Set state for GUI visualization + wasCH = true; + handleSelfMessage(msg); + } + + round += 1; + int intervalLength = 1.0 / clusterHeadRatio; + if (fmod(round, intervalLength) == 0) { // reset values at end of number of subintervals + wasCH = false; + nodeMemory.clear(); + nodeCHMemory.clear(); + extractedTDMASchedule.clear(); + TDMADelayCounter = 1; + } + + // schedule another self message every time new one is received by node + scheduleAt(simTime() + roundDuration, event); + } else { + // if node is receiving message + processMessage(msg); + } +} + +void Leach::handleMessageWhenDown(cMessage *msg) { + delete msg; + OperationalBase::handleMessageWhenDown(msg); +} + +void Leach::handleSelfMessage(cMessage *msg) { + if (msg == event) { + broadcastCtrlToNCH(); + } else { + delete msg; + } +} + +void Leach::processMessage(cMessage *msg) { + Ipv4Address selfAddr = + (wirelessInterface->getProtocolData()->getIPAddress()); + auto receivedCtrlPkt = dynamic_cast(msg); + receivedCtrlPkt->popAtFront(); + + Packet *receivedPkt = check_and_cast(msg); + auto &leachControlPkt = receivedCtrlPkt->peekAtFront(); + auto packetType = leachControlPkt->getPacketType(); + + // filter packet based on type and run specific functions + if (msg->arrivedOn("ipIn")) { + // first broadcast from CH to NCH nodes + if (packetType == CH) { + Ipv4Address CHAddr = leachControlPkt->getSrcAddress(); + + auto signalPowerInd = receivedPkt->getTag(); + double rxPower = signalPowerInd->getPower().get(); + + addToNodeMemory(selfAddr, CHAddr, rxPower); + sendAckToCH(selfAddr, CHAddr); + + // ACK packet from NCH node to CH + } else if (packetType == ACK && leachState == ch) { + Ipv4Address nodeAddr = leachControlPkt->getSrcAddress(); + + addToNodeCHMemory(nodeAddr); + if (nodeCHMemory.size() > 2) { + sendSchToNCH(selfAddr); + } + + // TDMA schedule from CH to NCH + } else if (packetType == SCH) { + Ipv4Address CHAddr = leachControlPkt->getSrcAddress(); + + int scheduleArraySize = leachControlPkt->getScheduleArraySize(); + // Traverses through schedule array in packets and sets values into a vector in local node memory + for (int counter = 0; counter < scheduleArraySize; counter++) { + ScheduleEntry tempScheduleEntry = leachControlPkt->getSchedule( + counter); + TDMAScheduleEntry extractedTDMAScheduleEntry; + extractedTDMAScheduleEntry.nodeAddress = + tempScheduleEntry.getNodeAddress(); + extractedTDMAScheduleEntry.TDMAdelay = + tempScheduleEntry.getTDMAdelay(); + extractedTDMASchedule.push_back(extractedTDMAScheduleEntry); + } + + // Finds TDMA slot for self by traversing through earlier generated vector + double receivedTDMADelay = -1; + for (auto &it : extractedTDMASchedule) { + if (it.nodeAddress == selfAddr) { + receivedTDMADelay = it.TDMAdelay; + break; + } + } + + if (receivedTDMADelay > -1) { // Only sends data to CH if self address is included in schedule + sendDataToCH(selfAddr, CHAddr, receivedTDMADelay); + } + // Data packet from NCH to CH + } else if (packetType == DATA) { + Ipv4Address NCHAddr = leachControlPkt->getSrcAddress(); + + sendDataToBS(selfAddr); + + // BS packet from CH to BS - deleted in the case of standard nodes + } else if (packetType == BS) { + delete msg; + } + } else { + throw cRuntimeError("Message arrived on unknown gate %s", + msg->getArrivalGate()->getName()); + } +} + +// Runs during node shutdown events +void Leach::handleStopOperation(LifecycleOperation *operation) { + cancelAndDelete(event); + +} + +// Runs during node crash events +void Leach::handleCrashOperation(LifecycleOperation *operation) { + cancelAndDelete(event); +} + +// Threshold value for CH selection +double Leach::Leach::generateThresholdValue(int round) { + int intervalLength = 1.0 / clusterHeadRatio; + double threshold = (clusterHeadRatio + / (1 - clusterHeadRatio * (fmod(round, intervalLength)))); + + return threshold; +} + +// Add CH to non CH node memory +void Leach::addToNodeMemory(Ipv4Address nodeAddr, Ipv4Address CHAddr, + double energy) { + if (!isCHAddedInMemory(CHAddr)) { + nodeMemoryObject node; + node.nodeAddr = nodeAddr; + node.CHAddr = CHAddr; + node.energy = energy; + nodeMemory.push_back(node); + } +} + +// Add non CH to CH node memory for TDMA schedule generation +void Leach::addToNodeCHMemory(Ipv4Address NCHAddr) { + if (!isNCHAddedInCHMemory(NCHAddr)) { + TDMAScheduleEntry scheduleEntry; + scheduleEntry.nodeAddress = NCHAddr; + scheduleEntry.TDMAdelay = TDMADelayCounter; + nodeCHMemory.push_back(scheduleEntry); + TDMADelayCounter++; // Counter increases and sets slots for NCH transmission time + } +} + +// Checks non CH nodes memory for CH records +bool Leach::isCHAddedInMemory(Ipv4Address CHAddr) { + for (auto &it : nodeMemory) { + if (it.CHAddr == CHAddr) { + return true; + } + } + return false; +} + +// Checks CH nodes memory to generate TDMA schedule +bool Leach::isNCHAddedInCHMemory(Ipv4Address NCHAddr) { + for (auto &it : nodeCHMemory) { + if (it.nodeAddress == NCHAddr) { + return true; + } + } + return false; +} + +void Leach::generateTDMASchedule() { + for (auto &it : nodeCHMemory) { + ScheduleEntry scheduleEntry; + scheduleEntry.setNodeAddress(it.nodeAddress); + scheduleEntry.setTDMAdelay(it.TDMAdelay); + } +} + +// Set CH/non CH states for GUI visualization - optional +void Leach::setLeachState(LeachState ls) { + leachState = ls; +} + +void Leach::broadcastCtrlToNCH() { + Packet *udpPacket = new Packet("LeachCtrlPkt"); + + auto udpHeader = makeShared(); + udpHeader->setSourcePort(LEACH_UDP_PORT); + udpHeader->setDestinationPort(LEACH_UDP_PORT); + udpHeader->setCrcMode(CRC_DISABLED); + udpPacket->insertAtFront(udpHeader); + + auto ctrlPayload = makeShared(); + ctrlPayload->setPacketType(CH); + ctrlPayload->setChunkLength(b(128)); + Ipv4Address source = + (wirelessInterface->getProtocolData()->getIPAddress()); + ctrlPayload->setSrcAddress(source); + udpPacket->insertAtBack(ctrlPayload); + + auto addressReq = udpPacket->addTag(); + addressReq->setDestAddress(Ipv4Address(255, 255, 255, 255)); + addressReq->setSrcAddress(source); + udpPacket->addTag()->setInterfaceId( + wirelessInterface->getInterfaceId()); + udpPacket->addTag()->setProtocol(&Protocol::manet); + udpPacket->addTag()->setProtocol(&Protocol::ipv4); + + send(udpPacket, "ipOut"); +} + +// Send broadcast acknowledgement to CH from non CH nodes +void Leach::sendAckToCH(Ipv4Address nodeAddr, Ipv4Address CHAddr) { + Packet *udpPacket = new Packet("LeachAckPkt"); + + auto udpHeader = makeShared(); + udpHeader->setSourcePort(LEACH_UDP_PORT); + udpHeader->setDestinationPort(LEACH_UDP_PORT); + udpHeader->setCrcMode(CRC_DISABLED); + udpPacket->insertAtFront(udpHeader); + + auto ackPkt = makeShared(); + ackPkt->setPacketType(ACK); + ackPkt->setChunkLength(b(128)); ///size of Hello message in bits + ackPkt->setSrcAddress(nodeAddr); + udpPacket->insertAtBack(ackPkt); + + auto addressReq = udpPacket->addTag(); + addressReq->setDestAddress(getIdealCH(nodeAddr, CHAddr)); + addressReq->setSrcAddress(nodeAddr); + udpPacket->addTag()->setInterfaceId( + wirelessInterface->getInterfaceId()); + udpPacket->addTag()->setProtocol(&Protocol::manet); + udpPacket->addTag()->setProtocol(&Protocol::ipv4); + + send(udpPacket, "ipOut"); +} + +// Sends TDMA schedule to non CH nodes +void Leach::sendSchToNCH(Ipv4Address selfAddr) { + Packet *udpPacket = new Packet("LeachSchedulePkt"); + + auto udpHeader = makeShared(); + udpHeader->setSourcePort(LEACH_UDP_PORT); + udpHeader->setDestinationPort(LEACH_UDP_PORT); + udpHeader->setCrcMode(CRC_DISABLED); + udpPacket->insertAtFront(udpHeader); + + auto schedulePkt = makeShared(); + schedulePkt->setPacketType(SCH); + schedulePkt->setChunkLength(b(128)); ///size of Hello message in bits + schedulePkt->setSrcAddress(selfAddr); + for (auto &it : nodeCHMemory) { + ScheduleEntry scheduleEntry; + scheduleEntry.setNodeAddress(it.nodeAddress); + scheduleEntry.setTDMAdelay(it.TDMAdelay); + schedulePkt->insertSchedule(scheduleEntry); + } + udpPacket->insertAtBack(schedulePkt); + + auto scheduleReq = udpPacket->addTag(); + scheduleReq->setDestAddress(Ipv4Address(255, 255, 255, 255)); + scheduleReq->setSrcAddress(selfAddr); + udpPacket->addTag()->setInterfaceId( + wirelessInterface->getInterfaceId()); + udpPacket->addTag()->setProtocol(&Protocol::manet); + udpPacket->addTag()->setProtocol(&Protocol::ipv4); + + send(udpPacket, "ipOut"); +} + +// Sends data to CH node +void Leach::sendDataToCH(Ipv4Address nodeAddr, Ipv4Address CHAddr, + double TDMAslot) { + Packet *udpPacket = new Packet("LeachDataPkt"); + + auto udpHeader = makeShared(); + udpHeader->setSourcePort(LEACH_UDP_PORT); + udpHeader->setDestinationPort(LEACH_UDP_PORT); + udpHeader->setCrcMode(CRC_DISABLED); + udpPacket->insertAtFront(udpHeader); + + auto leachData = makeShared(); + leachData->setPacketType(DATA); + + leachData->setChunkLength(b(128)); + double temperature = (double) rand() / RAND_MAX; + double humidity = (double) rand() / RAND_MAX; + leachData->setTemperature(temperature); + leachData->setHumidity(humidity); + leachData->setSrcAddress(nodeAddr); + udpPacket->insertAtBack(leachData); + + auto addressReq = udpPacket->addTag(); + + addressReq->setDestAddress(getIdealCH(nodeAddr, CHAddr)); + addressReq->setSrcAddress(nodeAddr); + udpPacket->addTag()->setInterfaceId( + wirelessInterface->getInterfaceId()); + udpPacket->addTag()->setProtocol(&Protocol::manet); + udpPacket->addTag()->setProtocol(&Protocol::ipv4); + + sendDelayed(udpPacket, TDMAslot, "ipOut"); +} + +// CH sends data to BS +void Leach::sendDataToBS(Ipv4Address CHAddr) { + Packet *udpPacket = new Packet("LeachBsPkt"); + + auto udpHeader = makeShared(); + udpHeader->setSourcePort(LEACH_UDP_PORT); + udpHeader->setDestinationPort(LEACH_UDP_PORT); + udpHeader->setCrcMode(CRC_DISABLED); + udpPacket->insertAtFront(udpHeader); + + auto bsPkt = makeShared(); + bsPkt->setPacketType(BS); + bsPkt->setChunkLength(b(128)); + bsPkt->setCHAddr(CHAddr); + udpPacket->insertAtBack(bsPkt); + + + auto addressReq = udpPacket->addTag(); + addressReq->setDestAddress(Ipv4Address(10, 0, 0, 1)); + addressReq->setSrcAddress(CHAddr); + udpPacket->addTag()->setInterfaceId( + wirelessInterface->getInterfaceId()); + udpPacket->addTag()->setProtocol(&Protocol::manet); + udpPacket->addTag()->setProtocol(&Protocol::ipv4); + + sendDelayed(udpPacket, TDMADelayCounter, "ipOut"); + setLeachState(nch); // Set state for GUI visualization +} + +void Leach::sendUdpPacket(Packet *packet) { + send(packet, "ipOut"); +} + +// Selects the ideal CH based on RSSI signal +Ipv4Address Leach::getIdealCH(Ipv4Address nodeAddr, Ipv4Address CHAddr) { + Ipv4Address tempIdealCHAddr = CHAddr; + double tempRxPower = 0.0; + if (nodeMemory.size() > 0) { + for (auto &it : nodeMemory) { + if (it.nodeAddr == nodeAddr) { + if (it.energy > tempRxPower) { + tempRxPower = it.energy; + tempIdealCHAddr = it.CHAddr; + continue; + } + } else { + continue; + } + } + } + return tempIdealCHAddr; +} + +void Leach::refreshDisplay() const { + const char *icon; + switch (leachState) { + case nch: + icon = ""; + break; + case ch: + icon = "status/green"; + break; + default: + throw cRuntimeError("Unknown LEACH status"); + } + auto &displayString = getDisplayString(); + if (*icon) { + displayString.setTagArg("i2", 0, icon); + host->getDisplayString().setTagArg("i2", 0, icon); + } else { + displayString.removeTag("i2"); + host->getDisplayString().removeTag("i2"); + } +} +} /* namespace leach */ +} /* namespace inet */ diff --git a/src/inet/routing/leach/Leach.h b/src/inet/routing/leach/Leach.h new file mode 100644 index 00000000000..9f42594bf6d --- /dev/null +++ b/src/inet/routing/leach/Leach.h @@ -0,0 +1,131 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#ifndef INET_ROUTING_LEACH_LEACH_H_ +#define INET_ROUTING_LEACH_LEACH_H_ + +#include +#include + +#include "inet/common/INETDefs.h" +#include "inet/routing/leach/LeachDefs.h" +#include "inet/common/packet/Packet.h" +#include "inet/networklayer/contract/IInterfaceTable.h" +#include "inet/networklayer/contract/ipv4/Ipv4Address.h" +#include "inet/networklayer/ipv4/IIpv4RoutingTable.h" +#include "inet/networklayer/ipv4/Ipv4Header_m.h" +#include "inet/networklayer/ipv4/Ipv4InterfaceData.h" +#include "inet/networklayer/ipv4/Ipv4RoutingTable.h" +#include "inet/routing/base/RoutingProtocolBase.h" +#include "inet/routing/leach/LeackPkts_m.h" +#include "inet/mobility/contract/IMobility.h" +#include "inet/common/geometry/common/Coord.h" +#include "inet/mobility/base/StationaryMobilityBase.h" +#include "inet/power/contract/ICcEnergyStorage.h" +#include "inet/common/lifecycle/LifecycleController.h" +#include "inet/transportlayer/udp/UdpHeader_m.h" + +using namespace std; + +namespace inet { +namespace leach { + +class INET_API Leach: public RoutingProtocolBase { + +private: + NetworkInterface *wirelessInterface = nullptr; + unsigned int sequencenumber = 0; + cModule *host = nullptr; + Ipv4Address idealCH; + cMessage *event = nullptr; + int round = 0; + ModuleRefByPar interfaceTable; + const char *interfaces = nullptr; + +protected: + simtime_t dataPktSendDelay; + simtime_t CHPktSendDelay; + simtime_t roundDuration; + + double clusterHeadRatio = 0.0; + int roundDurationVariance = 0; + + // object for storing CH data per node in vector array + struct nodeMemoryObject { + Ipv4Address nodeAddr; + Ipv4Address CHAddr; + double energy; + }; + + struct TDMAScheduleEntry { + Ipv4Address nodeAddress; + double TDMAdelay; + }; + + vector nodeMemory; // Localized Non CH node memory with CH data + vector nodeCHMemory; // Localized CH memory to store NCH acknowledgements + vector extractedTDMASchedule; // Localized NCH node memory for extracted TDMA slot data + bool wasCH; + +public: + Leach(); + virtual ~Leach(); + + enum LeachState { + nch, ch + }; // written in lower caps as it conflicts with enum in LeachPkts.msg file + + LeachState leachState; + double TDMADelayCounter; + + virtual int numInitStages() const override { + return NUM_INIT_STAGES; + } + virtual void initialize(int stage) override; + virtual void handleMessageWhenUp(cMessage *msg) override; + virtual void handleMessageWhenDown(cMessage *msg) override; + + void handleSelfMessage(cMessage *msg); + void processMessage(cMessage *msg); + void configureInterfaces(); + + // lifecycle + virtual void handleStartOperation(LifecycleOperation *operation) override { + start(); + } + virtual void handleStopOperation(LifecycleOperation *operation) override; + virtual void handleCrashOperation(LifecycleOperation *operation) override; + void start(); + void stop(); + virtual void refreshDisplay() const override; + enum SelfMsgKinds { + SELF = 1, DATA2CH, DATA2BS + }; + + double generateThresholdValue(int subInterval); + + void broadcastCtrlToNCH(); + void sendDataToCH(Ipv4Address nodeAddr, Ipv4Address CHAddr, + double TDMAslot); + void sendDataToBS(Ipv4Address CHAddr); + void sendAckToCH(Ipv4Address nodeAddr, Ipv4Address CHAddr); + void sendSchToNCH(Ipv4Address selfAddr); + + void sendUdpPacket(Packet *packet); + + void addToNodeMemory(Ipv4Address nodeAddr, Ipv4Address CHAddr, + double energy); + void addToNodeCHMemory(Ipv4Address NCHAddr); + bool isCHAddedInMemory(Ipv4Address CHAddr); + bool isNCHAddedInCHMemory(Ipv4Address NCHAddr); + void generateTDMASchedule(); + + virtual void setLeachState(LeachState ls); + Ipv4Address getIdealCH(Ipv4Address nodeAddr, Ipv4Address CHAddr); +}; + +} /* namespace leach */ +} /* namespace inet */ + +#endif /* INET_ROUTING_LEACH_LEACH_H_ */ diff --git a/src/inet/routing/leach/Leach.ned b/src/inet/routing/leach/Leach.ned new file mode 100644 index 00000000000..cddf3828c01 --- /dev/null +++ b/src/inet/routing/leach/Leach.ned @@ -0,0 +1,39 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +package inet.routing.leach; + +import inet.routing.contract.IManetRouting; + +// +// This module provides Low-Energy Adaptive Clustering Hierarchy (LEACH) +// routing protocol for sensor nodes. +// LEACH is a hierachical adhoc routing protocol for Wireless Sensor Networks. +// This implementation is designed to use a a single wireless interface and run on +// the IEEE 802.15.4 standard for MAC and Physical layers. +// Therefore the standard TDMA scheduling system has been implemented +// with delayed time slots due to the use of CSMA in the 802.15.4 standard. +// +// For more information on the algorithm, see the LEACH paper +// https://ieeexplore.ieee.org/document/926982 +// +simple Leach like IManetRouting +{ + parameters: + // properties + @class("leach::Leach"); + @display("i=block/routing"); + + // context parameters + string interfaceTableModule; + + // LEACH parameter group + string interfaces = default("*"); // Only single wireless interface is required + volatile double startupDelay @unit(s) = default(uniform(0s, 1s)); + double clusterHeadRatio @unit(ratio) = default(0.05ratio); // Determines ratio of cluster heads in network, which is used for threshold function + int roundDurationVariance = default(10); + gates: + input ipIn; + output ipOut; +} diff --git a/src/inet/routing/leach/LeachBS.cc b/src/inet/routing/leach/LeachBS.cc new file mode 100644 index 00000000000..cb5b437a27f --- /dev/null +++ b/src/inet/routing/leach/LeachBS.cc @@ -0,0 +1,101 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#include "inet/common/IProtocolRegistrationListener.h" +#include "inet/common/ModuleAccess.h" +#include "inet/common/ProtocolTag_m.h" +#include "inet/linklayer/common/InterfaceTag_m.h" +#include "inet/networklayer/common/L3AddressTag_m.h" +#include "inet/physicallayer/wireless/common/contract/packetlevel/SignalTag_m.h" +#include "inet/routing/leach/LeachBS.h" +#include "inet/routing/leach/Leach.h" + +using namespace std; + +namespace inet { +namespace leach { + +Define_Module(LeachBS); + +LeachBS::LeachBS() { + +} + +LeachBS::~LeachBS() { + // TODO Auto-generated destructor stub +} + +void LeachBS::initialize(int stage) { + RoutingProtocolBase::initialize(stage); + + //reads from omnetpp.ini + if (stage == INITSTAGE_LOCAL) { + host = getContainingNode(this); + interfaceTable.reference(this, "interfaceTableModule", true); + interfaces = par("interfaces"); + + bsPktReceived = 0; + + } else if (stage == INITSTAGE_ROUTING_PROTOCOLS) { + registerProtocol(Protocol::manet, gate("ipOut"), gate("ipIn")); + } +} + +void LeachBS::start() { + /* Search the 802154 interface */ + configureInterfaces(); + +} + +void LeachBS::stop() { + +} + +void LeachBS::configureInterfaces() { + cPatternMatcher interfaceMatcher(interfaces, false, true, false); + int numInterfaces = interfaceTable->getNumInterfaces(); + for (int i = 0; i < numInterfaces; i++) { + NetworkInterface *networkInterface = interfaceTable->getInterface(i); + if (networkInterface->isMulticast() + && interfaceMatcher.matches( + networkInterface->getInterfaceName())) { + wirelessInterface = networkInterface; + } + } +} + +void LeachBS::handleMessageWhenUp(cMessage *msg) { + Ipv4Address nodeAddr = + (wirelessInterface->getProtocolData()->getIPAddress()); + // if node is sending message + if (msg->isSelfMessage()) { + delete msg; + } + // if node is receiving message + else if (check_and_cast(msg)->getTag()->getProtocol() + == &Protocol::manet) { + auto receivedCtrlPkt = dynamic_cast(msg); + receivedCtrlPkt->popAtFront(); + Packet *receivedPkt = check_and_cast(msg); + auto &leachControlPkt = receivedCtrlPkt->peekAtFront(); + auto packetType = leachControlPkt->getPacketType(); + + // filter packet based on type and run specific functions + if (msg->arrivedOn("ipIn")) { + if (packetType == BS) { + bsPktReceived += 1; + } else { + delete msg; + } + } else { + throw cRuntimeError("Message arrived on unknown gate %s", + msg->getArrivalGate()->getName()); + } + } else { + throw cRuntimeError("Message not supported %s", msg->getName()); + } +} + +} /* namespace leach */ +} /* namespace inet */ diff --git a/src/inet/routing/leach/LeachBS.h b/src/inet/routing/leach/LeachBS.h new file mode 100644 index 00000000000..f6e6680aac3 --- /dev/null +++ b/src/inet/routing/leach/LeachBS.h @@ -0,0 +1,62 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#ifndef INET_ROUTING_LEACH_LEACHBS_H_ +#define INET_ROUTING_LEACH_LEACHBS_H_ + +#include "inet/common/INETDefs.h" +#include "inet/common/packet/Packet.h" +#include "inet/networklayer/contract/IInterfaceTable.h" +#include "inet/networklayer/contract/ipv4/Ipv4Address.h" +#include "inet/networklayer/ipv4/IIpv4RoutingTable.h" +#include "inet/networklayer/ipv4/Ipv4Header_m.h" +#include "inet/networklayer/ipv4/Ipv4InterfaceData.h" +#include "inet/networklayer/ipv4/Ipv4RoutingTable.h" +#include "inet/routing/base/RoutingProtocolBase.h" +#include "inet/routing/leach/LeackPkts_m.h" +#include "inet/routing/leach/Leach.h" + +namespace inet { +namespace leach { + +// Base Station of network which acts as data sink +class INET_API LeachBS: public RoutingProtocolBase { +private: + int bsPktReceived; // number of packets received at BS + +public: + LeachBS(); + virtual ~LeachBS(); + + int interfaceId = -1; + NetworkInterface *wirelessInterface = nullptr; + cModule *host = nullptr; + ModuleRefByPar interfaceTable; + const char *interfaces = nullptr; + +protected: + virtual int numInitStages() const override { + return NUM_INIT_STAGES; + } + virtual void initialize(int stage) override; + virtual void handleMessageWhenUp(cMessage *msg) override; + void configureInterfaces(); + + virtual void handleStartOperation(LifecycleOperation *operation) override { + start(); + } + virtual void handleStopOperation(LifecycleOperation *operation) override { + stop(); + } + virtual void handleCrashOperation(LifecycleOperation *operation) override { + stop(); + } + void start(); + void stop(); +}; + +} /* namespace leach */ +} /* namespace inet */ + +#endif /* INET_ROUTING_LEACH_LEACHBS_H_ */ diff --git a/src/inet/routing/leach/LeachBS.ned b/src/inet/routing/leach/LeachBS.ned new file mode 100644 index 00000000000..c96c2629b9d --- /dev/null +++ b/src/inet/routing/leach/LeachBS.ned @@ -0,0 +1,34 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +package inet.routing.leach; + +import inet.routing.contract.IManetRouting; + +// +// This module provides Low-Energy Adaptive Clustering Hierarchy (LEACH) +// routing protocol for the data sink/base station. +// This implementation is designed to use a a single wireless interface and run on +// the IEEE 802.15.4 standard for MAC and Physical layers. +// This module simply receives data from the sensor nodes. +// +// For more information on the algorithm, see the LEACH paper +// https://ieeexplore.ieee.org/document/926982 +// +simple LeachBS like IManetRouting +{ + parameters: + // properties + @class("leach::LeachBS"); + @display("i=block/routing"); + + // context parameters + string interfaceTableModule; + + // Leach base station parameter group + string interfaces = default("*"); // Only single wireless interface is required + gates: + input ipIn; + output ipOut; +} diff --git a/src/inet/routing/leach/LeachDefs.h b/src/inet/routing/leach/LeachDefs.h new file mode 100644 index 00000000000..8cb96b0d740 --- /dev/null +++ b/src/inet/routing/leach/LeachDefs.h @@ -0,0 +1,18 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#ifndef INET_ROUTING_LEACH_LEACHDEFS_H_ +#define INET_ROUTING_LEACH_LEACHDEFS_H_ + +#include "inet/common/INETDefs.h" + +#define LEACH_UDP_PORT 269 + +namespace inet { + +} // namespace inet + + + +#endif /* INET_ROUTING_LEACH_LEACHDEFS_H_ */ diff --git a/src/inet/routing/leach/LeackPkts.msg b/src/inet/routing/leach/LeackPkts.msg new file mode 100644 index 00000000000..e6771e3da27 --- /dev/null +++ b/src/inet/routing/leach/LeackPkts.msg @@ -0,0 +1,52 @@ +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +import inet.common.INETDefs; +import inet.common.packet.chunk.Chunk; +import inet.networklayer.contract.ipv4.Ipv4Address; + +namespace inet::leach; + +enum LeachPktType { + CH = 1; + ACK = 2; + SCH = 3; + DATA = 4; + BS = 5; +} + +class ScheduleEntry extends cObject { + Ipv4Address nodeAddress; + double TDMAdelay; +} + +// Base packet including all fields used across other packet variants +class LeachControlPkt extends FieldsChunk { + LeachPktType packetType = static_cast(-1); + Ipv4Address srcAddress; + string fingerprint; + + ScheduleEntry schedule[]; +} + +// Data packet including fields for mock data +class LeachDataPkt extends LeachControlPkt { + double temperature; + double humidity; +} + +// Packet sent to BS from CH +class LeachBSPkt extends LeachControlPkt { + Ipv4Address CHAddr; +} + +// CH broadcast reception acknowledgement from NCH nodes +class LeachAckPkt extends LeachControlPkt { + +} + +// Packet with TDMA schedule from CH +class LeachSchedulePkt extends LeachControlPkt { + +} diff --git a/tests/fingerprint/examples.csv b/tests/fingerprint/examples.csv index 198e3cf73a0..c4b996bdf68 100644 --- a/tests/fingerprint/examples.csv +++ b/tests/fingerprint/examples.csv @@ -334,6 +334,10 @@ /examples/manetrouting/dsdv/, -f omnetpp.ini -c MultiIPv4 -r 0, 10s, 4d24-d5b6/tplx;e9e8-7d0b/~tNl;e9f0-b256/~tND;e86f-d3fa/tyf, PASS, wireless adhoc Ipv4 /examples/manetrouting/dsdv/, -f omnetpp.ini -c DynamicIPv4 -r 0, 22s, b5fe-a1b2/tplx;3e2c-1eee/~tNl;eecc-7593/~tND;90d2-3ffa/tyf, PASS, wireless adhoc Ipv4 +/examples/manetrouting/leach/,-f omnetpp.ini -r 0, 100s, d028-7203/tplx,PASS,wireless adhoc Ipv4 +/examples/manetrouting/leach/,-f omnetpp.ini -c LeachPower -r 0, 100s, d028-7203/tplx, PASS,wireless adhoc Ipv4 +/examples/manetrouting/leach/,-f omnetpp.ini -c LeachPathLoss -r 0, 100s, 76ca-cca8/tplx, PASS,wireless adhoc Ipv4 + # /examples/manetrouting/dymo/, -f omnetpp.ini -c _IPv4 -r 0 # abstract-config /examples/manetrouting/dymo/, -f omnetpp.ini -c IPv4 -r 0, 10s, 1a85-cb5d/tplx;dfe8-11b9/~tNl;483b-544e/tyf, PASS, wireless adhoc Ipv4 # /examples/manetrouting/dymo/, -f omnetpp.ini -c _IPv6 -r 0 # abstract-config diff --git a/tests/module/LeachSimpleTest.test b/tests/module/LeachSimpleTest.test new file mode 100644 index 00000000000..3a908c29cbf --- /dev/null +++ b/tests/module/LeachSimpleTest.test @@ -0,0 +1,107 @@ +%description: +This example tests a simple run of the LEACH routing protocol +on IEEE 802.15.4 standard with 100 nodes +%#-------------------------------------------------------------------------------------------------------------- +%file: test.ned + +import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator; +import inet.node.contract.INetworkNode; +import inet.node.inet.SensorNode; +import inet.physicallayer.wireless.common.contract.packetlevel.IRadioMedium; +import inet.visualizer.contract.IIntegratedVisualizer; +import inet.environment.common.PhysicalEnvironment; + +network SimpleNet +{ + parameters: + int numNodes; + @display("bgb=200.8119,200.0099;bgg=100,1,grey95"); + @figure[title](type=label; pos=0,-1; anchor=sw; color=darkblue); + + submodules: + configurator: Ipv4NetworkConfigurator { + @display("p=512.39996,181.17"); + } + radioMedium: like IRadioMedium { + @display("p=512.39996,289.13998"); + } + physicalEnvironment: PhysicalEnvironment { + @display("p=512.39996,441.02997"); + } + host[numNodes]: like INetworkNode { + @display("i=misc/sensor2"); + } + baseStation: like INetworkNode { + @display("p=50,50;i=misc/sensorgateway"); + } +} + +%#-------------------------------------------------------------------------------------------------------------- +%inifile: omnetpp.ini + +[General] +network = Leach + +num-rngs = 2 +rng-class = omnetpp::cMersenneTwister +seed-0-mt= 4900 # used for node layout generation +seed-1-mt = 7 # used for threshold comparison + +**.arp.typename = "GlobalArp" + +*.radioMedium.typename = "Ieee802154NarrowbandScalarRadioMedium" +*.radioMedium.backgroundNoise.power = -100dBm +*.radioMedium.mediumLimitCache.centerFrequency = 2GHz + +*.host*.hasStatus = true +*.visualizer.energyStorageVisualizer.displayEnergyStorages = true + +*.configurator.config = xmldoc ("address.xml") + +*.baseStation.typename = "LeachBS" +*.host*.typename = "LeachNode" +*.host*.LEACHnode.clusterHeadPercentage = 0.05 +*.host*.LEACHnode.numNodes = 100 # set number of nodes to be injected into LEACH module + +*.numNodes = 100 #100 +*.host*.mobility.typename = "StationaryMobility" +*.host*.mobility.rng-0 = 0 # random number generator mapping + +*.host[*].mobility.initFromDisplayString = false + +**.constraintAreaMinX = 1m +**.constraintAreaMaxX = 100m +**.constraintAreaMinY = 1m +**.constraintAreaMaxY = 100m + +*.host*.wlan[0].typename = "Ieee802154NarrowbandInterface" +*.host*.wlan[0].radio.typename = "ApskScalarRadio" +*.host*.wlan[0].radio.centerFrequency = 2.5GHz # based on TI CC2520 +*.host*.wlan[0].radio.bandwidth = 2MHz +*.host*.wlan[0].radio.transmitter.power = 60.5mW # determines communication range - based on CC2520 +*.host*.wlan[0].radio.transmitter.preambleDuration = 192us # based on TI CC2520 +*.host*.wlan[0].radio.transmitter.headerLength = 6B # based on TI CC2520 +*.host*.wlan[0].radio.receiver.sensitivity = -110dBm +*.host*.wlan[0].radio.receiver.energyDetection = -110dBm +*.host*.wlan[0].radio.receiver.snirThreshold = 4dB +*.host*.wlan[0].radio.displayCommunicationRange = true + + +*.baseStation.wlan[0].typename = "Ieee802154NarrowbandInterface" +*.baseStation.wlan[0].radio.typename = "ApskScalarRadio" +*.baseStation.wlan[0].radio.centerFrequency = 2.5GHz +*.baseStation.wlan[0].radio.bandwidth = 2MHz +*.baseStation.wlan[0].radio.transmitter.power = 60.5mW +*.baseStation.wlan[0].radio.transmitter.preambleDuration = 192us +*.baseStation.wlan[0].radio.transmitter.headerLength = 6B +*.baseStation.wlan[0].radio.receiver.sensitivity = -110dBm +*.baseStation.wlan[0].radio.receiver.energyDetection = -110dBm +*.baseStation.wlan[0].radio.receiver.snirThreshold = 4dB +*.baseStation.wlan[0].radio.displayCommunicationRange = true + +*.host*.**.bitrate = 250kbps # based on TI CC2520 +*.baseStation.**.bitrate = 250kbps + +%#-------------------------------------------------------------------------------------------------------------- +%file-exists: results/General-#0.sca +