zigbee: Add basic APS layer support
This commit is contained in:
@@ -3,6 +3,9 @@ build_lib(
|
||||
SOURCE_FILES
|
||||
helper/zigbee-helper.cc
|
||||
helper/zigbee-stack-container.cc
|
||||
model/zigbee-aps-header.cc
|
||||
model/zigbee-aps-tables.cc
|
||||
model/zigbee-aps.cc
|
||||
model/zigbee-nwk-fields.cc
|
||||
model/zigbee-nwk.cc
|
||||
model/zigbee-stack.cc
|
||||
@@ -12,6 +15,9 @@ build_lib(
|
||||
HEADER_FILES
|
||||
helper/zigbee-helper.h
|
||||
helper/zigbee-stack-container.h
|
||||
model/zigbee-aps-header.h
|
||||
model/zigbee-aps-tables.h
|
||||
model/zigbee-aps.h
|
||||
model/zigbee-nwk-fields.h
|
||||
model/zigbee-nwk.h
|
||||
model/zigbee-stack.h
|
||||
@@ -20,4 +26,5 @@ build_lib(
|
||||
model/zigbee-nwk-tables.h
|
||||
LIBRARIES_TO_LINK ${liblr-wpan}
|
||||
TEST_SOURCES test/zigbee-rreq-test.cc
|
||||
test/zigbee-aps-data-test.cc
|
||||
)
|
||||
|
||||
Binary file not shown.
@@ -35,28 +35,42 @@ This is the case of ``NetDevices`` such as the ``LrWpanNetDevice``.
|
||||
While other technologies like 6loWPAN can interact with the underlying MAC layer through general-purpose ``NetDevice`` interfaces, Zigbee has specific requirements that necessitate certain features from a lr-wpan MAC.
|
||||
Consequently, the |ns3| Zigbee implementation directly accesses the aggregated ``LrWpanMacBase`` and interfaces with it accordingly.
|
||||
|
||||
The current scope of the project includes **only the NWK layer in the Zigbee stack**. However, the project can be later extended
|
||||
to support higher layers like the Application Sublayer (APS) and the Zigbee Cluster Library (ZCL).
|
||||
The current scope of the project includes **only the NWK layer and the APS layer in the Zigbee stack**. However, the project can be later extended
|
||||
to support higher layers like the application framework (AF) or services like the Zigbee Cluster Library (ZCL).
|
||||
|
||||
|
||||
Scope and Limitations
|
||||
---------------------
|
||||
|
||||
- MacInterfaceTable is not supported (Multiple interface support).
|
||||
The NWK has the following limitations:
|
||||
|
||||
- The NWK MacInterfaceTable NIB is not supported (Multiple MAC interfaces support).
|
||||
- Security handling is not supported.
|
||||
- Source routing and Tree routing are not implemented.
|
||||
- Zigbee Stack profile 0x01 (used for tree routing and distributed address assignment) is not supported.
|
||||
- A few NIB attributes setting and NWK constants are not supported by the |ns3| attribute system.
|
||||
- Traces are not implemented yet.
|
||||
- Trace sources are not implemented yet.
|
||||
- Data broadcast do not support retries or passive acknowledgment.
|
||||
- Data broadcast to low power routers is not supported as the underlying lr-wpan netdevice has no concept of energy consumption.
|
||||
- Address duplication detection is not supported.
|
||||
- Beacon mode is not througly tested.
|
||||
- The following Zigbee layers are not supported yet:
|
||||
- Zigbee Application Support Sub-Layer (APS)
|
||||
- Zigbee Cluster Library (ZCL)
|
||||
- Zigbee Device Object (ZDO)
|
||||
- Application Framework (AF)
|
||||
- 16-bit address resolution from a IEEE address at NWK layer is not supported.
|
||||
|
||||
|
||||
The APS has the following limitations:
|
||||
|
||||
- No groupcasting support (Similar to multicast)
|
||||
- No fragmentation support
|
||||
- No duplicates detection
|
||||
- No acknowledged transmissions
|
||||
- No extenended address (64-bit) destinations supported
|
||||
- No trace sources
|
||||
|
||||
The following Zigbee layers or services are not supported yet:
|
||||
|
||||
- Zigbee Cluster Library (ZCL)
|
||||
- Zigbee Device Object (ZDO)
|
||||
- Application Framework (AF)
|
||||
|
||||
To see a list of |ns3| Zigbee undergoing development efforts check issue `#1165 <https://gitlab.com/nsnam/ns-3-dev/-/issues/1165>`_
|
||||
|
||||
@@ -298,6 +312,31 @@ Alternatively, a Mesh route discovery can be performed along a data transmission
|
||||
Important: The process described above assumes that devices have already joined the network.
|
||||
A route discovery request issued before a device is part of the network (join process) will result in failure.
|
||||
|
||||
The application support sub-layer (APS)
|
||||
---------------------------------------
|
||||
|
||||
As its name suggests, this intermediate layer exists between the Network (NWK) layer and the Application Framework (AF).
|
||||
It provides services to both the Zigbee Device Object (ZDO) and the AF.
|
||||
The APS layer introduces abstract concepts such as **EndPoints**, **Clusters**, and **Profiles**; however, it does not assign specific meanings to these concepts.
|
||||
Instead, it simply adds this information to the transmitted frames.
|
||||
|
||||
Effective management of **EndPoints**, **Clusters**, and **Profile IDs** requires the use of the Zigbee Cluster Library (ZCL) and the ZDO, which are not currently supported by this implementation.
|
||||
This implementation offers only the most basic functions of the APS, allowing data transmission using known 16-bit address destinations.
|
||||
Features such as groupcasting, transmission to IEEE addresses (64-bit address destinations), fragmentation, duplication detection, and security are not currently supported but are under development.
|
||||
|
||||
By default, the APS layer is integrated within the Zigbee stack.
|
||||
However, users can choose to work solely with the NWK layer.
|
||||
To do this, they must disable the APS by using the `SetNwkLayerOnly()` function in the Zigbee helper.
|
||||
|
||||
The APS layer can transmit data that includes information regarding source and destination endpoints, but it cannot initiate network formation or network joining procedures.
|
||||
Typically, the ZDO manages these processes; however, since we currently do not have the ZDO, users must directly interact with the NWK layer’s network formation and joining primitives to trigger these options.
|
||||
|
||||
The following is a list of APS primitives are included:
|
||||
|
||||
- APSDE-DATA (Request, Confirm, Indication) <------ Only Address mode 0x02 (16-bit address and destination endpoint present) supported.
|
||||
- APSME-BIND (Request, Confirm) <----Included but inconsequential without group table support
|
||||
- APSME-UNBIND (Request, Confirm) <----Included but inconsequential without group table support
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
@@ -329,7 +368,10 @@ is used to establish a Zigbee stack on top of these devices::
|
||||
|
||||
// Install a zigbee stack on a set of devices using the helper
|
||||
ZigbeeHelper zigbee;
|
||||
zigbee.SetNwkLayerOnly(); // Activate if you wish to have only the NWK layer in the stack
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbee.Install(lrwpanDevices);
|
||||
// ... ...
|
||||
// Call to NWK primitives contained in the NWK layer in the Zigbee stack.
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
@@ -375,11 +417,12 @@ All the examples listed here shows scenarios in which a quasi-layer implementati
|
||||
* ``zigbee-association-join.cc``: An example showing the NWK layer join process of 3 devices in a zigbee network (MAC association).
|
||||
* ``zigbee-nwk-routing.cc``: Shows a simple topology of 5 router devices sequentially joining a network. Data transmission and route discovery (MESH routing) are also shown in this example
|
||||
* ``zigbee-nwk-routing-grid.cc``: Shows a complex grid topology of 50 router devices sequentially joining a network. Route discovery (MANY-TO-ONE routing) is also shown in this example.
|
||||
* ``zigbee-aps-data.cc``: Demonstrates the usage of the APS layer to transmit data.
|
||||
|
||||
The following unit test have been developed to ensure the correct behavior of the module:
|
||||
|
||||
* ``zigbee-rreq-test``: Test some situations in which RREQ messages should be retried during a route discovery process.
|
||||
|
||||
* ``zigbee-aps-data-test``: Test the APS data transmission
|
||||
|
||||
Validation
|
||||
----------
|
||||
|
||||
@@ -3,6 +3,7 @@ set(base_examples
|
||||
zigbee-nwk-association-join
|
||||
zigbee-nwk-routing
|
||||
zigbee-nwk-routing-grid
|
||||
zigbee-aps-data
|
||||
)
|
||||
|
||||
foreach(
|
||||
|
||||
442
src/zigbee/examples/zigbee-aps-data.cc
Normal file
442
src/zigbee/examples/zigbee-aps-data.cc
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mesh routing example with APS layer data transmission in a simple topology.
|
||||
*
|
||||
* This example use a Zigbee stack formed by NWK and APS layers.
|
||||
* The APS layer is used to transmit data, the creation of the necessary routes is
|
||||
* handle automatically by the NWK layer. There is no ZDO, therefore we need to manually
|
||||
* use the NWK to form the network and establish the router devices.
|
||||
*
|
||||
*
|
||||
* Network Extended PAN id: 0X000000000000CA:FE (based on the PAN coordinator address)
|
||||
*
|
||||
* Devices Addresses:
|
||||
*
|
||||
* [Coordinator] ZC (dev0 | Node 0): [00:00:00:00:00:00:CA:FE] [00:00]
|
||||
* [Router 1] ZR1 (dev1 | Node 1): [00:00:00:00:00:00:00:01] [short addr assigned by ZC]
|
||||
* [Router 2] ZR2 (dev2 | Node 2): [00:00:00:00:00:00:00:02] [short addr assigned by ZR1]
|
||||
* [Router 3] ZR3 (dev3 | Node 3): [00:00:00:00:00:00:00:03] [short addr assigned by ZR2]
|
||||
* [Router 4] ZR4 (dev4 | Node 4): [00:00:00:00:00:00:00:04] [short addr assigned by ZR1]
|
||||
*
|
||||
* Topology:
|
||||
*
|
||||
* ZC--------ZR1------------ZR2----------ZR3
|
||||
* |
|
||||
* |
|
||||
* ZR4
|
||||
*/
|
||||
|
||||
#include "ns3/constant-position-mobility-model.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/lr-wpan-module.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/single-model-spectrum-channel.h"
|
||||
#include "ns3/zigbee-module.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
using namespace ns3::lrwpan;
|
||||
using namespace ns3::zigbee;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ZigbeeRouting");
|
||||
|
||||
ZigbeeStackContainer zigbeeStacks;
|
||||
|
||||
static void
|
||||
TraceRoute(Mac16Address src, Mac16Address dst)
|
||||
{
|
||||
std::cout << "\nTime " << Simulator::Now().As(Time::S) << " | "
|
||||
<< "Traceroute to destination [" << dst << "]:\n";
|
||||
Mac16Address target = src;
|
||||
uint32_t count = 1;
|
||||
while (target != Mac16Address("FF:FF") && target != dst)
|
||||
{
|
||||
Ptr<ZigbeeStack> zstack;
|
||||
|
||||
for (auto i = zigbeeStacks.Begin(); i != zigbeeStacks.End(); i++)
|
||||
{
|
||||
zstack = *i;
|
||||
if (zstack->GetNwk()->GetNetworkAddress() == target)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool neighbor = false;
|
||||
target = zstack->GetNwk()->FindRoute(dst, neighbor);
|
||||
if (target == Mac16Address("FF:FF"))
|
||||
{
|
||||
std::cout << count << ". Node " << zstack->GetNode()->GetId() << " ["
|
||||
<< zstack->GetNwk()->GetNetworkAddress() << " | "
|
||||
<< zstack->GetNwk()->GetIeeeAddress() << "]: "
|
||||
<< " Destination Unreachable\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << count << ". Node " << zstack->GetNode()->GetId() << " ["
|
||||
<< zstack->GetNwk()->GetNetworkAddress() << " | "
|
||||
<< zstack->GetNwk()->GetIeeeAddress() << "]: "
|
||||
<< "NextHop [" << target << "] ";
|
||||
if (neighbor)
|
||||
{
|
||||
std::cout << "(*Neighbor)\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "\n";
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
static void
|
||||
ApsDataIndication(Ptr<ZigbeeStack> stack, ApsdeDataIndicationParams params, Ptr<Packet> p)
|
||||
{
|
||||
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
|
||||
<< "ApsdeDataIndication: Received packet of size " << p->GetSize()
|
||||
<< " for destination EndPoint " << params.m_dstEndPoint << "\n";
|
||||
}
|
||||
|
||||
static void
|
||||
NwkNetworkFormationConfirm(Ptr<ZigbeeStack> stack, NlmeNetworkFormationConfirmParams params)
|
||||
{
|
||||
std::cout << "NlmeNetworkFormationConfirmStatus = " << params.m_status << "\n";
|
||||
}
|
||||
|
||||
static void
|
||||
NwkNetworkDiscoveryConfirm(Ptr<ZigbeeStack> stack, NlmeNetworkDiscoveryConfirmParams params)
|
||||
{
|
||||
// See Zigbee Specification r22.1.0, 3.6.1.4.1
|
||||
// This method implements a simplistic version of the method implemented
|
||||
// in a zigbee APL layer. In this layer a candidate Extended PAN Id must
|
||||
// be selected and a NLME-JOIN.request must be issued.
|
||||
|
||||
if (params.m_status == NwkStatus::SUCCESS)
|
||||
{
|
||||
std::cout << " Network discovery confirm Received. Networks found ("
|
||||
<< params.m_netDescList.size() << "):\n";
|
||||
|
||||
for (const auto& netDescriptor : params.m_netDescList)
|
||||
{
|
||||
std::cout << " ExtPanID: 0x" << std::hex << netDescriptor.m_extPanId << "\n"
|
||||
<< std::dec << " CH: " << static_cast<uint32_t>(netDescriptor.m_logCh)
|
||||
<< "\n"
|
||||
<< std::hex << " Pan ID: 0x" << netDescriptor.m_panId << "\n"
|
||||
<< " Stack profile: " << std::dec
|
||||
<< static_cast<uint32_t>(netDescriptor.m_stackProfile) << "\n"
|
||||
<< "--------------------\n";
|
||||
}
|
||||
|
||||
NlmeJoinRequestParams joinParams;
|
||||
|
||||
zigbee::CapabilityInformation capaInfo;
|
||||
capaInfo.SetDeviceType(ROUTER);
|
||||
capaInfo.SetAllocateAddrOn(true);
|
||||
|
||||
joinParams.m_rejoinNetwork = zigbee::JoiningMethod::ASSOCIATION;
|
||||
joinParams.m_capabilityInfo = capaInfo.GetCapability();
|
||||
joinParams.m_extendedPanId = params.m_netDescList[0].m_extPanId;
|
||||
|
||||
Simulator::ScheduleNow(&ZigbeeNwk::NlmeJoinRequest, stack->GetNwk(), joinParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG("Unable to discover networks | status: " << params.m_status);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
NwkJoinConfirm(Ptr<ZigbeeStack> stack, NlmeJoinConfirmParams params)
|
||||
{
|
||||
if (params.m_status == NwkStatus::SUCCESS)
|
||||
{
|
||||
std::cout << Simulator::Now().As(Time::S) << " Node " << stack->GetNode()->GetId() << " | "
|
||||
<< " The device joined the network SUCCESSFULLY with short address " << std::hex
|
||||
<< params.m_networkAddress << " on the Extended PAN Id: " << std::hex
|
||||
<< params.m_extendedPanId << "\n"
|
||||
<< std::dec;
|
||||
|
||||
// 3 - After dev 1 is associated, it should be started as a router
|
||||
// (i.e. it becomes able to accept request from other devices to join the network)
|
||||
NlmeStartRouterRequestParams startRouterParams;
|
||||
Simulator::ScheduleNow(&ZigbeeNwk::NlmeStartRouterRequest,
|
||||
stack->GetNwk(),
|
||||
startRouterParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " The device FAILED to join the network with status " << params.m_status
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
NwkRouteDiscoveryConfirm(Ptr<ZigbeeStack> stack, NlmeRouteDiscoveryConfirmParams params)
|
||||
{
|
||||
std::cout << "NlmeRouteDiscoveryConfirmStatus = " << params.m_status << "\n";
|
||||
}
|
||||
|
||||
static void
|
||||
SendData(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst)
|
||||
{
|
||||
// Send data from a device with stackSrc to device with stackDst.
|
||||
|
||||
// We do not know what network address will be assigned after the JOIN procedure
|
||||
// but we can request the network address from stackDst (the destination device) when
|
||||
// we intend to send data. If a route do not exist, we will search for a route
|
||||
// before transmitting data (Mesh routing).
|
||||
|
||||
Ptr<Packet> p = Create<Packet>(5);
|
||||
// Src and Dst Endpoints must not be 0, because this is reserved for the ZDO.
|
||||
// Other Endpoint numbers can help to differentiate between different applications
|
||||
// running in the same node (similar to the concept of a port in TCP/IP).
|
||||
// Likewise, because we currently do not have ZDO or ZCL or AF, clusterId
|
||||
// and profileId numbers are non-sensical.
|
||||
ApsdeDataRequestParams dataReqParams;
|
||||
ZigbeeApsTxOptions txOptions;
|
||||
dataReqParams.m_useAlias = false;
|
||||
// Default, use 16 bit address destination (No option), equivalent to 0x00
|
||||
dataReqParams.m_txOptions = txOptions.GetTxOptions();
|
||||
dataReqParams.m_srcEndPoint = 3;
|
||||
dataReqParams.m_clusterId = 5; // Arbitrary value
|
||||
dataReqParams.m_profileId = 2; // Arbitrary value
|
||||
|
||||
dataReqParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
|
||||
dataReqParams.m_dstAddr16 = stackDst->GetNwk()->GetNetworkAddress();
|
||||
dataReqParams.m_dstEndPoint = 4;
|
||||
|
||||
Simulator::ScheduleNow(&ZigbeeAps::ApsdeDataRequest, stackSrc->GetAps(), dataReqParams, p);
|
||||
|
||||
// Give a few seconds to allow the creation of the route and
|
||||
// then print the route trace and tables from the source
|
||||
Simulator::Schedule(Seconds(3),
|
||||
&TraceRoute,
|
||||
stackSrc->GetNwk()->GetNetworkAddress(),
|
||||
stackDst->GetNwk()->GetNetworkAddress());
|
||||
|
||||
Ptr<OutputStreamWrapper> stream = Create<OutputStreamWrapper>(&std::cout);
|
||||
Simulator::Schedule(Seconds(4), &ZigbeeNwk::PrintNeighborTable, stackSrc->GetNwk(), stream);
|
||||
|
||||
Simulator::Schedule(Seconds(4), &ZigbeeNwk::PrintRoutingTable, stackSrc->GetNwk(), stream);
|
||||
|
||||
Simulator::Schedule(Seconds(4),
|
||||
&ZigbeeNwk::PrintRouteDiscoveryTable,
|
||||
stackSrc->GetNwk(),
|
||||
stream);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
LogComponentEnableAll(LogLevel(LOG_PREFIX_TIME | LOG_PREFIX_FUNC | LOG_PREFIX_NODE));
|
||||
// Enable logs for further details
|
||||
// LogComponentEnable("ZigbeeNwk", LOG_LEVEL_DEBUG);
|
||||
|
||||
RngSeedManager::SetSeed(3);
|
||||
RngSeedManager::SetRun(4);
|
||||
|
||||
NodeContainer nodes;
|
||||
nodes.Create(5);
|
||||
|
||||
//// Configure MAC
|
||||
|
||||
LrWpanHelper lrWpanHelper;
|
||||
NetDeviceContainer lrwpanDevices = lrWpanHelper.Install(nodes);
|
||||
Ptr<LrWpanNetDevice> dev0 = lrwpanDevices.Get(0)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev1 = lrwpanDevices.Get(1)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev2 = lrwpanDevices.Get(2)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev3 = lrwpanDevices.Get(3)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev4 = lrwpanDevices.Get(4)->GetObject<LrWpanNetDevice>();
|
||||
|
||||
// Device must ALWAYS have IEEE Address (Extended address) assigned.
|
||||
// Network address (short address) are assigned by the the JOIN mechanism
|
||||
dev0->GetMac()->SetExtendedAddress("00:00:00:00:00:00:CA:FE");
|
||||
dev1->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:01");
|
||||
dev2->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:02");
|
||||
dev3->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:03");
|
||||
dev4->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:04");
|
||||
|
||||
Ptr<SingleModelSpectrumChannel> channel = CreateObject<SingleModelSpectrumChannel>();
|
||||
Ptr<LogDistancePropagationLossModel> propModel =
|
||||
CreateObject<LogDistancePropagationLossModel>();
|
||||
|
||||
Ptr<ConstantSpeedPropagationDelayModel> delayModel =
|
||||
CreateObject<ConstantSpeedPropagationDelayModel>();
|
||||
|
||||
channel->AddPropagationLossModel(propModel);
|
||||
channel->SetPropagationDelayModel(delayModel);
|
||||
|
||||
dev0->SetChannel(channel);
|
||||
dev1->SetChannel(channel);
|
||||
dev2->SetChannel(channel);
|
||||
dev3->SetChannel(channel);
|
||||
dev4->SetChannel(channel);
|
||||
|
||||
// Configure the Zigbee stack, by default both the NWK and the APS are present
|
||||
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack1 = zigbeeStackContainer.Get(1)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack2 = zigbeeStackContainer.Get(2)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack3 = zigbeeStackContainer.Get(3)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack4 = zigbeeStackContainer.Get(4)->GetObject<ZigbeeStack>();
|
||||
|
||||
// Add the stacks to a container to later on print routes.
|
||||
zigbeeStacks.Add(zstack0);
|
||||
zigbeeStacks.Add(zstack1);
|
||||
zigbeeStacks.Add(zstack2);
|
||||
zigbeeStacks.Add(zstack3);
|
||||
zigbeeStacks.Add(zstack4);
|
||||
|
||||
// Assign streams to the zigbee stacks to obtain
|
||||
// reprodusable results from random events occurring inside the stack.
|
||||
zstack0->GetNwk()->AssignStreams(0);
|
||||
zstack1->GetNwk()->AssignStreams(10);
|
||||
zstack2->GetNwk()->AssignStreams(20);
|
||||
zstack3->GetNwk()->AssignStreams(30);
|
||||
zstack4->GetNwk()->AssignStreams(40);
|
||||
|
||||
//// Configure Nodes Mobility
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev0Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev0Mobility->SetPosition(Vector(0, 0, 0));
|
||||
dev0->GetPhy()->SetMobility(dev0Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev1Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev1Mobility->SetPosition(Vector(90, 0, 0));
|
||||
dev1->GetPhy()->SetMobility(dev1Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev2Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev2Mobility->SetPosition(Vector(170, 0, 0));
|
||||
dev2->GetPhy()->SetMobility(dev2Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev3Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev3Mobility->SetPosition(Vector(250, 0, 0));
|
||||
dev3->GetPhy()->SetMobility(dev3Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev4Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev4Mobility->SetPosition(Vector(90, 50, 0));
|
||||
dev4->GetPhy()->SetMobility(dev4Mobility);
|
||||
|
||||
// NWK callbacks hooks
|
||||
// These hooks are usually directly connected to the ZDO.
|
||||
// In this case, there is no ZDO, therefore, we connect the event outputs
|
||||
// of all devices directly to our static functions in this example.
|
||||
|
||||
zstack0->GetNwk()->SetNlmeNetworkFormationConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkFormationConfirm, zstack0));
|
||||
zstack0->GetNwk()->SetNlmeRouteDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkRouteDiscoveryConfirm, zstack0));
|
||||
|
||||
zstack1->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, zstack1));
|
||||
zstack2->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, zstack2));
|
||||
zstack3->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, zstack3));
|
||||
zstack4->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, zstack4));
|
||||
|
||||
zstack1->GetNwk()->SetNlmeJoinConfirmCallback(MakeBoundCallback(&NwkJoinConfirm, zstack1));
|
||||
zstack2->GetNwk()->SetNlmeJoinConfirmCallback(MakeBoundCallback(&NwkJoinConfirm, zstack2));
|
||||
zstack3->GetNwk()->SetNlmeJoinConfirmCallback(MakeBoundCallback(&NwkJoinConfirm, zstack3));
|
||||
zstack4->GetNwk()->SetNlmeJoinConfirmCallback(MakeBoundCallback(&NwkJoinConfirm, zstack4));
|
||||
|
||||
// APS callback hooks
|
||||
|
||||
zstack0->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, zstack0));
|
||||
zstack1->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, zstack1));
|
||||
zstack2->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, zstack2));
|
||||
zstack3->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, zstack3));
|
||||
zstack4->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, zstack4));
|
||||
|
||||
// 1 - Initiate the Zigbee coordinator, start the network
|
||||
// ALL_CHANNELS = 0x07FFF800 (Channels 11~26)
|
||||
NlmeNetworkFormationRequestParams netFormParams;
|
||||
netFormParams.m_scanChannelList.channelPageCount = 1;
|
||||
netFormParams.m_scanChannelList.channelsField[0] = ALL_CHANNELS;
|
||||
netFormParams.m_scanDuration = 0;
|
||||
netFormParams.m_superFrameOrder = 15;
|
||||
netFormParams.m_beaconOrder = 15;
|
||||
|
||||
Simulator::ScheduleWithContext(zstack0->GetNode()->GetId(),
|
||||
Seconds(1),
|
||||
&ZigbeeNwk::NlmeNetworkFormationRequest,
|
||||
zstack0->GetNwk(),
|
||||
netFormParams);
|
||||
|
||||
// 2- Schedule devices sequentially find and join the network.
|
||||
// After this procedure, each device make a NLME-START-ROUTER.request to become a router
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams;
|
||||
netDiscParams.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams.m_scanChannelList.channelsField[0] = 0x00007800; // BitMap: Channels 11~14
|
||||
netDiscParams.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack1->GetNode()->GetId(),
|
||||
Seconds(3),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack1->GetNwk(),
|
||||
netDiscParams);
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams2;
|
||||
netDiscParams2.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams2.m_scanChannelList.channelsField[0] = 0x00007800; // BitMap: Channels 11~14
|
||||
netDiscParams2.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack2->GetNode()->GetId(),
|
||||
Seconds(4),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack2->GetNwk(),
|
||||
netDiscParams2);
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams3;
|
||||
netDiscParams2.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams2.m_scanChannelList.channelsField[0] = 0x00007800; // BitMap: Channels 11~14
|
||||
netDiscParams2.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack3->GetNode()->GetId(),
|
||||
Seconds(5),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack3->GetNwk(),
|
||||
netDiscParams3);
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams4;
|
||||
netDiscParams4.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams4.m_scanChannelList.channelsField[0] = 0x00007800; // BitMap: Channels 11~14
|
||||
netDiscParams4.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack4->GetNode()->GetId(),
|
||||
Seconds(6),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack4->GetNwk(),
|
||||
netDiscParams4);
|
||||
|
||||
// 5- Find Route and Send data (Call to APS layer)
|
||||
|
||||
Simulator::Schedule(Seconds(8), &SendData, zstack0, zstack3);
|
||||
|
||||
Simulator::Stop(Seconds(20));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
@@ -160,10 +160,11 @@ main(int argc, char* argv[])
|
||||
dev1->SetChannel(channel);
|
||||
dev2->SetChannel(channel);
|
||||
|
||||
//// Configure NWK
|
||||
//// Configure the Zigbee Stack and use only the NWK layer
|
||||
|
||||
ZigbeeHelper zigbee;
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbee.Install(lrwpanDevices);
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
zigbeeHelper.SetNwkLayerOnly();
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack1 = zigbeeStackContainer.Get(1)->GetObject<ZigbeeStack>();
|
||||
|
||||
@@ -120,10 +120,11 @@ main(int argc, char* argv[])
|
||||
dev1->SetChannel(channel);
|
||||
dev2->SetChannel(channel);
|
||||
|
||||
//// Configure NWK
|
||||
//// Configure the Zigbee Stack and use only the NWK layer
|
||||
|
||||
ZigbeeHelper zigbee;
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbee.Install(lrwpanDevices);
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
zigbeeHelper.SetNwkLayerOnly();
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack1 = zigbeeStackContainer.Get(1)->GetObject<ZigbeeStack>();
|
||||
|
||||
@@ -279,6 +279,7 @@ main(int argc, char* argv[])
|
||||
lrWpanHelper.SetExtendedAddresses(lrwpanDevices);
|
||||
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
zigbeeHelper.SetNwkLayerOnly();
|
||||
zigbeeStacks = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
// NWK callbacks hooks
|
||||
|
||||
@@ -275,10 +275,11 @@ main(int argc, char* argv[])
|
||||
dev3->SetChannel(channel);
|
||||
dev4->SetChannel(channel);
|
||||
|
||||
//// Configure NWK
|
||||
// Configure the Zigbee stack and use only the NWK layer.
|
||||
|
||||
ZigbeeHelper zigbee;
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbee.Install(lrwpanDevices);
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
zigbeeHelper.SetNwkLayerOnly();
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack1 = zigbeeStackContainer.Get(1)->GetObject<ZigbeeStack>();
|
||||
|
||||
@@ -24,6 +24,7 @@ ZigbeeHelper::ZigbeeHelper()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_stackFactory.SetTypeId("ns3::zigbee::ZigbeeStack");
|
||||
m_nwkLayerOnly = false;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -49,6 +50,12 @@ ZigbeeHelper::Install(const NetDeviceContainer c)
|
||||
NS_LOG_LOGIC("Installing Zigbee on node " << device->GetNode()->GetId());
|
||||
|
||||
Ptr<zigbee::ZigbeeStack> zigbeeStack = m_stackFactory.Create<zigbee::ZigbeeStack>();
|
||||
|
||||
if (m_nwkLayerOnly)
|
||||
{
|
||||
zigbeeStack->SetOnlyNwkLayer();
|
||||
}
|
||||
|
||||
zigbeeStackContainer.Add(zigbeeStack);
|
||||
device->GetNode()->AggregateObject(zigbeeStack);
|
||||
zigbeeStack->SetNetDevice(device);
|
||||
@@ -56,4 +63,10 @@ ZigbeeHelper::Install(const NetDeviceContainer c)
|
||||
return zigbeeStackContainer;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeHelper::SetNwkLayerOnly()
|
||||
{
|
||||
m_nwkLayerOnly = true;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ns3/net-device-container.h"
|
||||
#include "ns3/object-factory.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace ns3
|
||||
@@ -63,6 +64,12 @@ class ZigbeeHelper
|
||||
*/
|
||||
zigbee::ZigbeeStackContainer Install(NetDeviceContainer c);
|
||||
|
||||
/**
|
||||
* If this is set, the helper will only create Zigbee stacks that contain
|
||||
* only the NWK layer
|
||||
*/
|
||||
void SetNwkLayerOnly();
|
||||
|
||||
/**
|
||||
* Assign a fixed random variable stream number to the random variables
|
||||
* used by this model. Return the number of streams (possibly zero) that
|
||||
@@ -78,6 +85,7 @@ class ZigbeeHelper
|
||||
|
||||
private:
|
||||
ObjectFactory m_stackFactory; //!< Zigbee stack object factory.
|
||||
bool m_nwkLayerOnly; //!< Flag indicating that only the NWK layer is present
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
366
src/zigbee/model/zigbee-aps-header.cc
Normal file
366
src/zigbee/model/zigbee-aps-header.cc
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#include "zigbee-aps-header.h"
|
||||
|
||||
#include "ns3/address-utils.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
ZigbeeApsHeader::ZigbeeApsHeader()
|
||||
{
|
||||
m_frameType = ApsFrameType::APS_DATA;
|
||||
m_deliveryMode = ApsDeliveryMode::APS_UCST;
|
||||
m_ackFormat = false;
|
||||
m_security = false;
|
||||
m_ackRequest = false;
|
||||
m_extHeaderPresent = false;
|
||||
}
|
||||
|
||||
ZigbeeApsHeader::~ZigbeeApsHeader()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetFrameType(enum ApsFrameType type)
|
||||
{
|
||||
m_frameType = type;
|
||||
}
|
||||
|
||||
ApsFrameType
|
||||
ZigbeeApsHeader::GetFrameType() const
|
||||
{
|
||||
return m_frameType;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetDeliveryMode(enum ApsDeliveryMode mode)
|
||||
{
|
||||
m_deliveryMode = mode;
|
||||
}
|
||||
|
||||
ApsDeliveryMode
|
||||
ZigbeeApsHeader::GetDeliveryMode() const
|
||||
{
|
||||
return m_deliveryMode;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetSecurity(bool enabled)
|
||||
{
|
||||
m_security = enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsHeader::IsSecurityEnabled() const
|
||||
{
|
||||
return m_security;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetAckRequest(bool ack)
|
||||
{
|
||||
m_ackRequest = ack;
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsHeader::IsAckRequested() const
|
||||
{
|
||||
return m_ackRequest;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetExtHeaderPresent(bool present)
|
||||
{
|
||||
m_extHeaderPresent = present;
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsHeader::IsExtHeaderPresent() const
|
||||
{
|
||||
return m_extHeaderPresent;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetDstEndpoint(uint8_t dst)
|
||||
{
|
||||
m_dstEndpoint = dst;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ZigbeeApsHeader::GetDstEndpoint() const
|
||||
{
|
||||
return m_dstEndpoint;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetClusterId(uint16_t clusterId)
|
||||
{
|
||||
m_clusterId = clusterId;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ZigbeeApsHeader::GetClusterId() const
|
||||
{
|
||||
return m_clusterId;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetProfileId(uint16_t profileId)
|
||||
{
|
||||
m_profileId = profileId;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ZigbeeApsHeader::GetProfileId() const
|
||||
{
|
||||
return m_profileId;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetSrcEndpoint(uint8_t src)
|
||||
{
|
||||
m_srcEndpoint = src;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ZigbeeApsHeader::GetSrcEndpoint() const
|
||||
{
|
||||
return m_srcEndpoint;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::SetApsCounter(uint8_t counter)
|
||||
{
|
||||
m_apsCounter = counter;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ZigbeeApsHeader::GetApsCounter() const
|
||||
{
|
||||
return m_apsCounter;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::Serialize(Buffer::Iterator start) const
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
|
||||
// Frame control field
|
||||
uint8_t frameControl = (m_frameType & 0x03) | ((m_deliveryMode & 0x03) << 2) |
|
||||
((m_ackFormat ? 1 : 0) << 4) | ((m_security ? 1 : 0) << 5) |
|
||||
((m_ackRequest ? 1 : 0) << 6) | ((m_extHeaderPresent ? 1 : 0) << 7);
|
||||
|
||||
i.WriteU8(frameControl);
|
||||
|
||||
// Addressing fields
|
||||
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_UCST || m_deliveryMode == ApsDeliveryMode::APS_BCST)
|
||||
{
|
||||
i.WriteU8(m_dstEndpoint);
|
||||
}
|
||||
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_GROUP_ADDRESSING)
|
||||
{
|
||||
i.WriteHtolsbU16(m_groupAddress);
|
||||
}
|
||||
|
||||
if (m_frameType == ApsFrameType::APS_DATA || m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
i.WriteHtolsbU16(m_clusterId);
|
||||
i.WriteHtolsbU16(m_profileId);
|
||||
}
|
||||
|
||||
if (m_frameType == ApsFrameType::APS_DATA)
|
||||
{
|
||||
i.WriteU8(m_srcEndpoint);
|
||||
}
|
||||
|
||||
i.WriteU8(m_apsCounter);
|
||||
|
||||
// Extended Header
|
||||
|
||||
if (m_extHeaderPresent)
|
||||
{
|
||||
// Extended Frame control field
|
||||
uint8_t extFrameControl = (m_fragmentation & 0x03);
|
||||
i.WriteU8(extFrameControl);
|
||||
|
||||
// Block control
|
||||
if (m_fragmentation != ApsFragmentation::NOT_FRAGMENTED)
|
||||
{
|
||||
i.WriteU8(m_blockNumber);
|
||||
}
|
||||
// ACK Bitfield
|
||||
if (m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
i.WriteU8(m_ackBitfield);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ZigbeeApsHeader::Deserialize(Buffer::Iterator start)
|
||||
{
|
||||
Buffer::Iterator i = start;
|
||||
|
||||
uint8_t frameControl = i.ReadU8();
|
||||
m_frameType = static_cast<ApsFrameType>(frameControl & 0x03);
|
||||
m_deliveryMode = static_cast<ApsDeliveryMode>((frameControl >> 2) & 0x03);
|
||||
m_ackFormat = (frameControl >> 4) & 0x01;
|
||||
m_security = (frameControl >> 5) & 0x01;
|
||||
m_ackRequest = (frameControl >> 6) & 0x01;
|
||||
m_extHeaderPresent = (frameControl >> 7) & 0x01;
|
||||
|
||||
// Addressing fields
|
||||
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_UCST || m_deliveryMode == ApsDeliveryMode::APS_BCST)
|
||||
{
|
||||
m_dstEndpoint = i.ReadU8();
|
||||
}
|
||||
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_GROUP_ADDRESSING)
|
||||
{
|
||||
m_groupAddress = i.ReadLsbtohU16();
|
||||
}
|
||||
|
||||
if (m_frameType == ApsFrameType::APS_DATA || m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
m_clusterId = i.ReadLsbtohU16();
|
||||
m_profileId = i.ReadLsbtohU16();
|
||||
}
|
||||
|
||||
if (m_frameType == ApsFrameType::APS_DATA)
|
||||
{
|
||||
m_srcEndpoint = i.ReadU8();
|
||||
}
|
||||
|
||||
m_apsCounter = i.ReadU8();
|
||||
|
||||
// Extended Header
|
||||
|
||||
if (m_extHeaderPresent)
|
||||
{
|
||||
// Extended Frame control field
|
||||
uint8_t extFrameControl = i.ReadU8();
|
||||
m_fragmentation = static_cast<ApsFragmentation>(extFrameControl & 0x03);
|
||||
|
||||
// Block control
|
||||
if (m_fragmentation != ApsFragmentation::NOT_FRAGMENTED)
|
||||
{
|
||||
m_blockNumber = i.ReadU8();
|
||||
}
|
||||
// ACK Bitfield
|
||||
if (m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
m_ackBitfield = i.ReadU8();
|
||||
}
|
||||
}
|
||||
|
||||
return i.GetDistanceFrom(start);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ZigbeeApsHeader::GetSerializedSize() const
|
||||
{
|
||||
uint8_t totalSize;
|
||||
// See Zigbee Specification r22.1.0
|
||||
|
||||
// Fixed field:
|
||||
// Frame Control (1) + APS Counter (1)
|
||||
totalSize = 2;
|
||||
|
||||
// Variable Fields:
|
||||
// Destination EndPoint field (1) (Section 2.2.5.1.2)
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_UCST || m_deliveryMode == ApsDeliveryMode::APS_BCST)
|
||||
{
|
||||
totalSize += 1;
|
||||
}
|
||||
|
||||
// Group Address field (2) (Section 2.2.5.1.3)
|
||||
if (m_deliveryMode == ApsDeliveryMode::APS_GROUP_ADDRESSING)
|
||||
{
|
||||
totalSize += 2;
|
||||
}
|
||||
|
||||
// Cluster identifier field and Profile identifier field (4)
|
||||
// (Sections 2.2.5.1.4 and 2.2.5.15)
|
||||
if (m_frameType == ApsFrameType::APS_DATA || m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
totalSize += 4;
|
||||
}
|
||||
|
||||
// Source Endpoint field (1) (Section 2.2.5.1.6)
|
||||
if (m_frameType == ApsFrameType::APS_DATA)
|
||||
{
|
||||
totalSize += 1;
|
||||
}
|
||||
|
||||
// Extended header sub-frame (variable)
|
||||
if (m_extHeaderPresent)
|
||||
{
|
||||
// Extended Frame control field (1)
|
||||
totalSize += 1;
|
||||
|
||||
// Block control (1)
|
||||
if (m_fragmentation != ApsFragmentation::NOT_FRAGMENTED)
|
||||
{
|
||||
totalSize += 1;
|
||||
}
|
||||
// ACK Bitfield
|
||||
if (m_frameType == ApsFrameType::APS_ACK)
|
||||
{
|
||||
totalSize += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
TypeId
|
||||
ZigbeeApsHeader::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId("ns3::zigbee::ZigbeeApsHeader")
|
||||
.SetParent<Header>()
|
||||
.SetGroupName("Zigbee")
|
||||
.AddConstructor<ZigbeeApsHeader>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
ZigbeeApsHeader::GetInstanceTypeId() const
|
||||
{
|
||||
return GetTypeId();
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsHeader::Print(std::ostream& os) const
|
||||
{
|
||||
// TODO:
|
||||
/* os << "\nAPS Frame Control = " << std::hex << std::showbase << static_cast<uint32_t>(
|
||||
(m_frameType & 0x03) |
|
||||
((m_deliveryMode & 0x03) << 2) |
|
||||
((m_ackFormat ? 1 : 0) << 4) |
|
||||
((m_security ? 1 : 0) << 5) |
|
||||
((m_ackRequest ? 1 : 0) << 6) |
|
||||
((m_extHeader ? 1 : 0) << 7));
|
||||
|
||||
os << " | Dst EP = " << static_cast<uint32_t>(m_dstEndpoint)
|
||||
<< " | Src EP = " << static_cast<uint32_t>(m_srcEndpoint)
|
||||
<< " | Cluster ID = " << m_clusterId
|
||||
<< " | Profile ID = " << m_profileId
|
||||
<< " | Counter = " << static_cast<uint32_t>(m_counter);
|
||||
os << "\n";*/
|
||||
}
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
264
src/zigbee/model/zigbee-aps-header.h
Normal file
264
src/zigbee/model/zigbee-aps-header.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#ifndef ZIGBEE_APS_HEADER_H
|
||||
#define ZIGBEE_APS_HEADER_H
|
||||
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/mac16-address.h"
|
||||
#include "ns3/mac64-address.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Values of the Frame Type Sub-Field.
|
||||
* Zigbee Specification r22.1.0, Table 2-20
|
||||
*/
|
||||
enum ApsFrameType : uint8_t
|
||||
{
|
||||
APS_DATA = 0x00,
|
||||
APS_COMMAND = 0x01,
|
||||
APS_ACK = 0x02,
|
||||
APS_INTERPAN_APS = 0x03
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Values of the Delivery Mode Sub-Field.
|
||||
* Zigbee Specification r22.1.0, Table 2-21
|
||||
*/
|
||||
enum ApsDeliveryMode : uint8_t
|
||||
{
|
||||
APS_UCST = 0x00,
|
||||
APS_BCST = 0x02,
|
||||
APS_GROUP_ADDRESSING = 0x03
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Table 2-22 Values of the Fragmentation Sub-Field
|
||||
* Zigbee Specification r22.1.0, Table 2-22
|
||||
*/
|
||||
enum ApsFragmentation : uint8_t
|
||||
{
|
||||
NOT_FRAGMENTED = 0x00,
|
||||
FIRST_FRAGMENT = 0x01,
|
||||
OTHER_FRAGMENT = 0x02
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Defines the APS header use by data transfer and commands issued from
|
||||
* the APS layer. Zigbee Specification r22.1.0, Section 2.2.5.1.
|
||||
*
|
||||
*/
|
||||
class ZigbeeApsHeader : public Header
|
||||
{
|
||||
public:
|
||||
ZigbeeApsHeader();
|
||||
~ZigbeeApsHeader() override;
|
||||
|
||||
/**
|
||||
* Set the Frame type defined in the APS layer
|
||||
*
|
||||
* @param frameType The frame type to set on the header
|
||||
*/
|
||||
void SetFrameType(enum ApsFrameType frameType);
|
||||
|
||||
/**
|
||||
* Get the frame time present in the header
|
||||
*
|
||||
* @return ApsFrameType
|
||||
*/
|
||||
ApsFrameType GetFrameType() const;
|
||||
|
||||
/**
|
||||
* Defines the mode in which this frame should be transmitted.
|
||||
*
|
||||
* @param mode The delivery mode to set on the APS header
|
||||
*/
|
||||
void SetDeliveryMode(enum ApsDeliveryMode mode);
|
||||
|
||||
/**
|
||||
* Get the transmission mode set on the header.
|
||||
*
|
||||
* @return ApsDeliveryMode The delivery mode of the header
|
||||
*/
|
||||
ApsDeliveryMode GetDeliveryMode() const;
|
||||
|
||||
/**
|
||||
* Set whether or not security should be used to transmit
|
||||
* the frame.
|
||||
*
|
||||
* @param enabled True if security should be used
|
||||
*/
|
||||
void SetSecurity(bool enabled);
|
||||
|
||||
/**
|
||||
* Returns whether or not security is enabled for the present frame.alignas
|
||||
*
|
||||
* @return True if security is enabled for the frame.
|
||||
*/
|
||||
bool IsSecurityEnabled() const;
|
||||
|
||||
/**
|
||||
* Set the acknowledment flag in the APS header.
|
||||
*
|
||||
* @param request True if the frame should be acknowledged
|
||||
*/
|
||||
void SetAckRequest(bool request);
|
||||
|
||||
/**
|
||||
* Indicates if the present frame requires acknowledgment.
|
||||
*
|
||||
* @return True if the frame requires acknowledgment
|
||||
*/
|
||||
bool IsAckRequested() const;
|
||||
|
||||
/**
|
||||
* Enables or disables the usage of the extended header.
|
||||
* Only used when fragmentation is used.
|
||||
*
|
||||
* @param present True if the extended header (fragmentation) is present.
|
||||
*/
|
||||
void SetExtHeaderPresent(bool present);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the extended header is present in the frame.
|
||||
* @return True if the extended header is present.
|
||||
*/
|
||||
bool IsExtHeaderPresent() const;
|
||||
|
||||
/**
|
||||
* Set the Bitmap representing the framecontrol portion of the APS header.
|
||||
*
|
||||
* @param frameControl The bitmap representing the framecontrol portion.
|
||||
*/
|
||||
void SetFrameControl(uint8_t frameControl);
|
||||
|
||||
/**
|
||||
* Get the frame control portion (bitmap) of the APS header.
|
||||
*
|
||||
* @return The frame control portion of the APS header.
|
||||
*/
|
||||
uint8_t GetFrameControl() const;
|
||||
|
||||
/**
|
||||
* Set the destination endpoint in the APS header.
|
||||
*
|
||||
* @param endpoint The destination endpoint.
|
||||
*/
|
||||
void SetDstEndpoint(uint8_t endpoint);
|
||||
|
||||
/**
|
||||
* Get the destination endpoint in the APS header.
|
||||
*
|
||||
* @return The destination endpoint.
|
||||
*/
|
||||
uint8_t GetDstEndpoint() const;
|
||||
|
||||
/**
|
||||
* Set the cluster id in the APS header.
|
||||
*
|
||||
* @param clusterId The cluster id
|
||||
*/
|
||||
void SetClusterId(uint16_t clusterId);
|
||||
|
||||
/**
|
||||
* Get the cluster id in the APS header.
|
||||
* @return The cluster id.
|
||||
*/
|
||||
uint16_t GetClusterId() const;
|
||||
|
||||
/**
|
||||
* Set the profile ID in the APS header.
|
||||
*
|
||||
* @param profileId The profile ID.
|
||||
*/
|
||||
void SetProfileId(uint16_t profileId);
|
||||
|
||||
/**
|
||||
* Get the profile ID in the APS header.
|
||||
* @return The profile ID.
|
||||
*/
|
||||
uint16_t GetProfileId() const;
|
||||
|
||||
/**
|
||||
* Set the source endpoint in the APS header.
|
||||
*
|
||||
* @param endpoint The source endpoint.
|
||||
*/
|
||||
void SetSrcEndpoint(uint8_t endpoint);
|
||||
|
||||
/**
|
||||
* Get the source endpoint in the APS header.
|
||||
* @return The source endpoint.
|
||||
*/
|
||||
uint8_t GetSrcEndpoint() const;
|
||||
|
||||
/**
|
||||
* Set the value of the APS counter in the APS header.
|
||||
* @param counter The APS counter value.
|
||||
*/
|
||||
void SetApsCounter(uint8_t counter);
|
||||
|
||||
/**
|
||||
* Get the APS counter value present in the APS header.
|
||||
* @return The APS counter value.
|
||||
*/
|
||||
uint8_t GetApsCounter() const;
|
||||
|
||||
/**
|
||||
* @brief Get the type ID.
|
||||
* @return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
TypeId GetInstanceTypeId() const override;
|
||||
|
||||
void Serialize(Buffer::Iterator start) const override;
|
||||
uint32_t Deserialize(Buffer::Iterator start) override;
|
||||
uint32_t GetSerializedSize() const override;
|
||||
void Print(std::ostream& os) const override;
|
||||
|
||||
private:
|
||||
// Frame Control field bits
|
||||
ApsFrameType m_frameType; //!< Frame control field: Frame type
|
||||
ApsDeliveryMode m_deliveryMode; //!< Frame control field: Delivery mode
|
||||
bool m_ackFormat; //!< Frame control field: Acknowledgment format
|
||||
bool m_security; //!< Frame control field: Security
|
||||
bool m_ackRequest; //!< Frame control field: Acknowledge requested
|
||||
bool m_extHeaderPresent; //!< Frame control field: Extended header present
|
||||
|
||||
// Addressing fields
|
||||
uint8_t m_dstEndpoint; //!< Addressing field: Destination endpoint.
|
||||
uint16_t m_groupAddress; //!< Addressing field: Group or 16-bit address.
|
||||
uint16_t m_clusterId; //!< Addressing field: Cluster ID.
|
||||
uint16_t m_profileId; //!< Addressing field: Profile ID.
|
||||
uint8_t m_srcEndpoint; //!< Addressing field: Source endpoint.
|
||||
|
||||
uint8_t m_apsCounter; //!< APS counter field
|
||||
|
||||
// Extended header fields
|
||||
ApsFragmentation m_fragmentation; //!< Extended header field: Fragmentation block type
|
||||
uint8_t m_blockNumber; //!< Extended header field: Block number
|
||||
uint8_t m_ackBitfield; //!< Extended header field: Acknowledgement bit field
|
||||
};
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
|
||||
#endif // ZIGBEE_APS_HEADER_H
|
||||
278
src/zigbee/model/zigbee-aps-tables.cc
Normal file
278
src/zigbee/model/zigbee-aps-tables.cc
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#include "zigbee-aps-tables.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ZigbeeApsTables");
|
||||
|
||||
/***********************************************************
|
||||
* Source Binding Entry
|
||||
***********************************************************/
|
||||
|
||||
SrcBindingEntry::SrcBindingEntry()
|
||||
{
|
||||
}
|
||||
|
||||
SrcBindingEntry::SrcBindingEntry(Mac64Address address, uint8_t endPoint, uint16_t clusterId)
|
||||
{
|
||||
m_srcAddr = address;
|
||||
m_srcEndPoint = endPoint;
|
||||
m_clusterId = clusterId;
|
||||
}
|
||||
|
||||
SrcBindingEntry::~SrcBindingEntry()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SrcBindingEntry::SetSrcAddress(Mac64Address address)
|
||||
{
|
||||
m_srcAddr = address;
|
||||
}
|
||||
|
||||
void
|
||||
SrcBindingEntry::SetSrcEndPoint(uint8_t endPoint)
|
||||
{
|
||||
m_srcEndPoint = endPoint;
|
||||
}
|
||||
|
||||
void
|
||||
SrcBindingEntry::SetClusterId(uint16_t clusterId)
|
||||
{
|
||||
m_clusterId = clusterId;
|
||||
}
|
||||
|
||||
Mac64Address
|
||||
SrcBindingEntry::GetSrcAddress() const
|
||||
{
|
||||
return m_srcAddr;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
SrcBindingEntry::GetSrcEndPoint() const
|
||||
{
|
||||
return m_srcEndPoint;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
SrcBindingEntry::GetClusterId() const
|
||||
{
|
||||
return m_clusterId;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Destination Binding Entry
|
||||
***********************************************************/
|
||||
|
||||
DstBindingEntry::DstBindingEntry()
|
||||
{
|
||||
}
|
||||
|
||||
DstBindingEntry::~DstBindingEntry()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DstBindingEntry::SetDstAddrMode(ApsDstAddressModeBind mode)
|
||||
{
|
||||
m_dstAddrMode = mode;
|
||||
}
|
||||
|
||||
void
|
||||
DstBindingEntry::SetDstAddr16(Mac16Address address)
|
||||
{
|
||||
m_dstAddr16 = address;
|
||||
}
|
||||
|
||||
void
|
||||
DstBindingEntry::SetDstAddr64(Mac64Address address)
|
||||
{
|
||||
m_dstAddr64 = address;
|
||||
}
|
||||
|
||||
void
|
||||
DstBindingEntry::SetDstEndPoint(uint8_t endPoint)
|
||||
{
|
||||
m_dstEndPoint = endPoint;
|
||||
}
|
||||
|
||||
ApsDstAddressModeBind
|
||||
DstBindingEntry::GetDstAddrMode() const
|
||||
{
|
||||
return m_dstAddrMode;
|
||||
}
|
||||
|
||||
Mac16Address
|
||||
DstBindingEntry::GetDstAddr16() const
|
||||
{
|
||||
return m_dstAddr16;
|
||||
}
|
||||
|
||||
Mac64Address
|
||||
DstBindingEntry::GetDstAddr64() const
|
||||
{
|
||||
return m_dstAddr64;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
DstBindingEntry::GetDstEndPoint() const
|
||||
{
|
||||
return m_dstEndPoint;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Binding Table
|
||||
***********************************************************/
|
||||
|
||||
BindingTable::BindingTable()
|
||||
{
|
||||
m_maxSrcEntries = 10;
|
||||
m_maxDstEntries = 10;
|
||||
}
|
||||
|
||||
bool
|
||||
BindingTable::CompareDestinations(const DstBindingEntry& first, const DstBindingEntry& second)
|
||||
{
|
||||
if (first.GetDstAddrMode() == ApsDstAddressModeBind::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT)
|
||||
{
|
||||
// Group Addressing
|
||||
if ((first.GetDstAddr16() == second.GetDstAddr16()) &&
|
||||
(first.GetDstEndPoint() == second.GetDstEndPoint()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (first.GetDstAddrMode() == ApsDstAddressModeBind::DST_ADDR64_DST_ENDPOINT_PRESENT)
|
||||
{
|
||||
// IEEE Addressing
|
||||
if ((first.GetDstAddr64() == second.GetDstAddr64()) &&
|
||||
(first.GetDstEndPoint() == second.GetDstEndPoint()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BindingTable::CompareSources(const SrcBindingEntry& first, const SrcBindingEntry& second)
|
||||
{
|
||||
return ((first.GetSrcAddress() == second.GetSrcAddress()) &&
|
||||
(first.GetSrcEndPoint() == second.GetSrcEndPoint()) &&
|
||||
(first.GetClusterId() == second.GetClusterId()));
|
||||
}
|
||||
|
||||
BindingTableStatus
|
||||
BindingTable::Bind(const SrcBindingEntry& src, const DstBindingEntry& dst)
|
||||
{
|
||||
for (auto& entry : m_bindingTable)
|
||||
{
|
||||
if (CompareSources(src, entry.first))
|
||||
{
|
||||
// The source exist, now check if the destination exist
|
||||
for (const auto& destination : entry.second)
|
||||
{
|
||||
if (CompareDestinations(dst, destination))
|
||||
{
|
||||
NS_LOG_WARN("Entry already exist in binding table");
|
||||
return BindingTableStatus::ENTRY_EXISTS;
|
||||
}
|
||||
}
|
||||
// Add the new destination bound to the source
|
||||
if (entry.second.size() >= m_maxDstEntries)
|
||||
{
|
||||
NS_LOG_WARN("Binding Table full, max destination entries (" << m_maxDstEntries
|
||||
<< ") reached");
|
||||
return BindingTableStatus::TABLE_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.second.emplace_back(dst);
|
||||
return BindingTableStatus::BOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bindingTable.size() >= m_maxSrcEntries)
|
||||
{
|
||||
NS_LOG_WARN("Binding Table full, max source entries (" << m_maxSrcEntries << ") reached");
|
||||
return BindingTableStatus::TABLE_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New source with its first destination
|
||||
m_bindingTable.emplace_back(src, std::vector<DstBindingEntry>{dst});
|
||||
return BindingTableStatus::BOUND;
|
||||
}
|
||||
}
|
||||
|
||||
BindingTableStatus
|
||||
BindingTable::Unbind(const SrcBindingEntry& src, const DstBindingEntry& dst)
|
||||
{
|
||||
for (auto it = m_bindingTable.begin(); it != m_bindingTable.end(); ++it)
|
||||
{
|
||||
if (CompareSources(src, it->first))
|
||||
{
|
||||
// The source exists, now check if the destination exists
|
||||
auto& destinations = it->second;
|
||||
for (auto destIt = destinations.begin(); destIt != destinations.end(); ++destIt)
|
||||
{
|
||||
if (CompareDestinations(dst, *destIt))
|
||||
{
|
||||
// Destination found, remove it
|
||||
destinations.erase(destIt);
|
||||
|
||||
// If no destinations left, remove the source entry
|
||||
if (destinations.empty())
|
||||
{
|
||||
m_bindingTable.erase(it);
|
||||
}
|
||||
// Successfully unbound
|
||||
return BindingTableStatus::UNBOUND;
|
||||
}
|
||||
}
|
||||
// Destination not found
|
||||
NS_LOG_WARN("Cannot unbind, destination entry do not exist");
|
||||
return BindingTableStatus::ENTRY_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
// Source not found
|
||||
NS_LOG_WARN("Cannot unbind, source entry do not exist");
|
||||
return BindingTableStatus::ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool
|
||||
BindingTable::LookUpEntries(const SrcBindingEntry& src, std::vector<DstBindingEntry>& dstEntries)
|
||||
{
|
||||
for (auto& entry : m_bindingTable)
|
||||
{
|
||||
if (CompareSources(src, entry.first))
|
||||
{
|
||||
// The source entry exist, return all the dst entries.
|
||||
dstEntries = entry.second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
272
src/zigbee/model/zigbee-aps-tables.h
Normal file
272
src/zigbee/model/zigbee-aps-tables.h
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Author:
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#ifndef ZIGBEE_APS_TABLES_H
|
||||
#define ZIGBEE_APS_TABLES_H
|
||||
|
||||
#include "ns3/mac16-address.h"
|
||||
#include "ns3/mac64-address.h"
|
||||
#include "ns3/output-stream-wrapper.h"
|
||||
#include "ns3/timer.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* APS Destination Address Mode for Binding
|
||||
* Zigbee Specification r22.1.0, Table 2-6
|
||||
* APSME-BIND.request Parameters
|
||||
*/
|
||||
enum class ApsDstAddressModeBind : std::uint8_t
|
||||
{
|
||||
GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT = 0x01,
|
||||
DST_ADDR64_DST_ENDPOINT_PRESENT = 0x03
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* The status resulting of interactions with the binding table.
|
||||
*/
|
||||
enum class BindingTableStatus : std::uint8_t
|
||||
{
|
||||
BOUND = 0,
|
||||
UNBOUND = 1,
|
||||
TABLE_FULL = 2,
|
||||
ENTRY_EXISTS = 3,
|
||||
ENTRY_NOT_FOUND = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Binding Table entry: Source portion of the table.
|
||||
* As described in Zigbee Specification r22.1.0, Table 2-134
|
||||
*/
|
||||
class SrcBindingEntry : public SimpleRefCount<SrcBindingEntry>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The default constructor of the source binding entry.
|
||||
*/
|
||||
SrcBindingEntry();
|
||||
|
||||
/**
|
||||
* Constructor of the source binding entry.
|
||||
*
|
||||
* @param address The IEEE address to register, (typically the IEEE address of the source
|
||||
* device).
|
||||
* @param endPoint The source endpoint to register to the entry.
|
||||
* @param clusterId The cluster ID to register to the entry.
|
||||
*/
|
||||
SrcBindingEntry(Mac64Address address, uint8_t endPoint, uint16_t clusterId);
|
||||
~SrcBindingEntry();
|
||||
|
||||
/**
|
||||
* Set the source IEEE address to the entry.
|
||||
*
|
||||
* @param address The IEEE address (64-bit address) of the entry
|
||||
*/
|
||||
void SetSrcAddress(Mac64Address address);
|
||||
|
||||
/**
|
||||
* Set the source endpoint of the source binding entry.
|
||||
* @param endPoint The source endpoint to set in the entry.
|
||||
*/
|
||||
void SetSrcEndPoint(uint8_t endPoint);
|
||||
|
||||
/**
|
||||
* Set the cluster ID of the source binding entry.
|
||||
* @param clusterId The cluster ID to set in the entry.
|
||||
*/
|
||||
void SetClusterId(uint16_t clusterId);
|
||||
|
||||
/**
|
||||
* Get the IEEE address from the source binding entry.
|
||||
* @return The IEEE address in the source binding entry.
|
||||
*/
|
||||
Mac64Address GetSrcAddress() const;
|
||||
|
||||
/**
|
||||
* Get the source endpoint from the source binding entry.
|
||||
*
|
||||
* @return The source endpoint.
|
||||
*/
|
||||
uint8_t GetSrcEndPoint() const;
|
||||
|
||||
/**
|
||||
* Get the cluster ID from the source binding entry.
|
||||
* @return The cluster ID.
|
||||
*/
|
||||
uint16_t GetClusterId() const;
|
||||
|
||||
private:
|
||||
Mac64Address m_srcAddr; //!< The source IEEE address in the source entry.
|
||||
uint8_t m_srcEndPoint{0}; //!< The source endpoint in the source entry.
|
||||
uint16_t m_clusterId{0}; //!< The cluster ID in the source entry.
|
||||
};
|
||||
|
||||
/**
|
||||
* Binding Table entry: Destination portion of the table.
|
||||
* As described in Zigbee Specification r22.1.0, Table 2-134
|
||||
*/
|
||||
class DstBindingEntry : public SimpleRefCount<DstBindingEntry>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The default constructor of the destination binding entry.
|
||||
*/
|
||||
DstBindingEntry();
|
||||
~DstBindingEntry();
|
||||
|
||||
/**
|
||||
* Set the destination address mode of the destination binding entry.
|
||||
* @param mode The destination address mode to set.
|
||||
*/
|
||||
void SetDstAddrMode(ApsDstAddressModeBind mode);
|
||||
|
||||
/**
|
||||
* Set the destination 16-bit address of the destination binding entry.
|
||||
* @param address The 16-bit address of the destination binding entry.
|
||||
*/
|
||||
void SetDstAddr16(Mac16Address address);
|
||||
|
||||
/**
|
||||
* Set the destination IEEE Address (64-bit address) of the destination binding entry.
|
||||
* @param address The destination IEEE address (64-bit address) to set
|
||||
*/
|
||||
void SetDstAddr64(Mac64Address address);
|
||||
|
||||
/**
|
||||
* Set the destination endppoint to the destination binding entry.
|
||||
* @param endPoint The destination endpoint to set.
|
||||
*/
|
||||
void SetDstEndPoint(uint8_t endPoint);
|
||||
|
||||
/**
|
||||
* Get the destination address mode used by the destination entry.
|
||||
* @return The destination address mode used by the entry.
|
||||
*/
|
||||
ApsDstAddressModeBind GetDstAddrMode() const;
|
||||
|
||||
/**
|
||||
* Get the 16-bit address destination of the destination entry.
|
||||
* @return The 16-bit address of the destination entry.
|
||||
*/
|
||||
Mac16Address GetDstAddr16() const;
|
||||
|
||||
/**
|
||||
* Get the 64-bit address destination of the destination entry.
|
||||
* @return The IEEE address (64-bit address) destination
|
||||
*/
|
||||
Mac64Address GetDstAddr64() const;
|
||||
|
||||
/**
|
||||
* Get the destination endpoint of the destination entry.
|
||||
* @return The destination endpoint.
|
||||
*/
|
||||
uint8_t GetDstEndPoint() const;
|
||||
|
||||
private:
|
||||
ApsDstAddressModeBind m_dstAddrMode{
|
||||
ApsDstAddressModeBind::DST_ADDR64_DST_ENDPOINT_PRESENT}; //!< The destination address mode
|
||||
//!< used by the entry.
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address in the destination entry.
|
||||
Mac64Address
|
||||
m_dstAddr64; //!< The destination IEEE address (64-bit address) in the destination entry.
|
||||
uint8_t m_dstEndPoint{0xF0}; //!< The destination endpoint in the destination entry.
|
||||
};
|
||||
|
||||
/**
|
||||
* APS Binding Table
|
||||
* See Zigbee specification r22.1.0, Table 2-134
|
||||
* Similar to the z-boss implementation, the binding table is divided in two portions:
|
||||
* The source part and the destination part. A single source can have multiple destination
|
||||
* entries as described by the Zigbee specification. This creates a relationship one to many
|
||||
* (a source entry with multiple destination entries) which is both useful for 64 bit Address UCST
|
||||
* or 16-bit groupcast destination bindings.
|
||||
*/
|
||||
class BindingTable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The constructor of the binding table.
|
||||
*/
|
||||
BindingTable();
|
||||
|
||||
/**
|
||||
* Add an entry to the binding table.
|
||||
* In essence it binds the source entry portion to the table to one or more
|
||||
* destination portion entries (one to many).
|
||||
*
|
||||
* @param src The source entry portion of the table.
|
||||
* @param dst The destination entry portion of the table.
|
||||
* @return The resulting status of the binding attempt.
|
||||
*/
|
||||
BindingTableStatus Bind(const SrcBindingEntry& src, const DstBindingEntry& dst);
|
||||
|
||||
/**
|
||||
* Unbinds a destination entry portion of a binding table from a source entry portion.
|
||||
*
|
||||
* @param src The source entry portion of the table.
|
||||
* @param dst The destination entry portion of the table.
|
||||
* @return The resulting status of the unbinding attempt.
|
||||
*/
|
||||
BindingTableStatus Unbind(const SrcBindingEntry& src, const DstBindingEntry& dst);
|
||||
|
||||
/**
|
||||
* Look for destination entries binded to an specific source entry portion in the binding
|
||||
* table.
|
||||
*
|
||||
* @param src The source entry portion of the table to search.
|
||||
* @param dstEntries The resulting destination entries binded to the provided source entry
|
||||
* portion
|
||||
* @return True if at least one destination entry portion was retrieved.
|
||||
*/
|
||||
bool LookUpEntries(const SrcBindingEntry& src, std::vector<DstBindingEntry>& dstEntries);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Compare the equality of 2 source entries
|
||||
*
|
||||
* @param first The first source entry to compare.
|
||||
* @param second The second source entry to compare.
|
||||
* @return True if the destinations entries are identical
|
||||
*/
|
||||
bool CompareSources(const SrcBindingEntry& first, const SrcBindingEntry& second);
|
||||
|
||||
/**
|
||||
* Compare the equality of 2 destination entries
|
||||
*
|
||||
* @param first The first destination entry to compare.
|
||||
* @param second The second destination entry to compare.
|
||||
* @return True if the destinations entries are identical
|
||||
*/
|
||||
bool CompareDestinations(const DstBindingEntry& first, const DstBindingEntry& second);
|
||||
|
||||
std::vector<std::pair<SrcBindingEntry,
|
||||
std::vector<DstBindingEntry>>>
|
||||
m_bindingTable; //!< The binding table object
|
||||
uint8_t m_maxSrcEntries; //!< The maximum amount of source entries allowed in the table
|
||||
uint8_t m_maxDstEntries; //!< The maximum amount of destination entries allowed in the table
|
||||
};
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* ZIGBEE_APS_TABLES_H */
|
||||
567
src/zigbee/model/zigbee-aps.cc
Normal file
567
src/zigbee/model/zigbee-aps.cc
Normal file
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#include "zigbee-aps.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ZigbeeAps");
|
||||
NS_OBJECT_ENSURE_REGISTERED(ZigbeeAps);
|
||||
|
||||
TypeId
|
||||
ZigbeeAps::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId("ns3::zigbee::ZigbeeAps")
|
||||
.SetParent<Object>()
|
||||
.SetGroupName("Zigbee")
|
||||
.AddConstructor<ZigbeeAps>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
ZigbeeAps::ZigbeeAps()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::NotifyConstructionCompleted()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
ZigbeeAps::~ZigbeeAps()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::DoInitialize()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Object::DoInitialize();
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::DoDispose()
|
||||
{
|
||||
m_nwk = nullptr;
|
||||
// m_apsBindingTable.Dispose();
|
||||
m_apsdeDataConfirmCallback = MakeNullCallback<void, ApsdeDataConfirmParams>();
|
||||
|
||||
Object::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SetNwk(Ptr<ZigbeeNwk> nwk)
|
||||
{
|
||||
m_nwk = nwk;
|
||||
}
|
||||
|
||||
Ptr<ZigbeeNwk>
|
||||
ZigbeeAps::GetNwk() const
|
||||
{
|
||||
return m_nwk;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::ApsdeDataRequest(ApsdeDataRequestParams params, Ptr<Packet> asdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// Fill APSDE-data.confirm parameters in case we need to return an error
|
||||
ApsdeDataConfirmParams confirmParams;
|
||||
confirmParams.m_dstAddrMode = params.m_dstAddrMode;
|
||||
confirmParams.m_dstAddr16 = params.m_dstAddr16;
|
||||
confirmParams.m_dstAddr64 = params.m_dstAddr64;
|
||||
confirmParams.m_dstEndPoint = params.m_dstEndPoint;
|
||||
confirmParams.m_srcEndPoint = params.m_srcEndPoint;
|
||||
|
||||
ZigbeeApsTxOptions txOptions(params.m_txOptions);
|
||||
|
||||
if (txOptions.IsSecurityEnabled())
|
||||
{
|
||||
// TODO: Add support for security options
|
||||
if (!m_apsdeDataConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::SECURITY_FAIL;
|
||||
confirmParams.m_txTime = Simulator::Now();
|
||||
m_apsdeDataConfirmCallback(confirmParams);
|
||||
}
|
||||
NS_LOG_WARN("Security is not currently supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Fragmentation
|
||||
|
||||
// TODO: Add ACK support
|
||||
if (txOptions.IsAckRequired())
|
||||
{
|
||||
NS_ABORT_MSG("Transmission with ACK not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// See See 2.2.4.1.1
|
||||
switch (params.m_dstAddrMode)
|
||||
{
|
||||
case ApsDstAddressMode::DST_ADDR_AND_DST_ENDPOINT_NOT_PRESENT: {
|
||||
// Use BINDING TABLE to send data to one or more destinations
|
||||
// (Groupcast or IEEE address destination transmission)
|
||||
NS_ABORT_MSG("Binded destination groupcast not supported");
|
||||
// SendDataWithBindingTable(params, asdu);
|
||||
break;
|
||||
}
|
||||
case ApsDstAddressMode::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT: {
|
||||
// TODO: Add Groupcast (multicast) support
|
||||
NS_ABORT_MSG("GROUP ADDRESS (MCST) not supported");
|
||||
break;
|
||||
}
|
||||
case ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT: {
|
||||
// Regular UCST or BCST transmission with the 16 bit destination address
|
||||
SendDataUcstBcst(params, asdu);
|
||||
break;
|
||||
}
|
||||
case ApsDstAddressMode::DST_ADDR64_DST_ENDPOINT_PRESENT: {
|
||||
// TODO: Add Extended address transmission support.
|
||||
// The NWK do not accept direct extended address transmissions,
|
||||
// therefore, the APS must translate the extended address
|
||||
// to a short address using the nwkAddressMap NIB.
|
||||
if (!m_apsdeDataConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::NO_SHORT_ADDRESS;
|
||||
confirmParams.m_txTime = Simulator::Now();
|
||||
m_apsdeDataConfirmCallback(confirmParams);
|
||||
}
|
||||
NS_LOG_WARN("Extended address mode not supported");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_ABORT_MSG("Invalid Option");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SendDataWithBindingTable(ApsdeDataRequestParams params, Ptr<Packet> asdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// Fill APSDE-data.confirm parameters in case we need to return an error
|
||||
ApsdeDataConfirmParams confirmParams;
|
||||
confirmParams.m_dstAddrMode = params.m_dstAddrMode;
|
||||
confirmParams.m_dstAddr16 = params.m_dstAddr16;
|
||||
confirmParams.m_dstAddr64 = params.m_dstAddr64;
|
||||
confirmParams.m_dstEndPoint = params.m_dstEndPoint;
|
||||
confirmParams.m_srcEndPoint = params.m_srcEndPoint;
|
||||
|
||||
// APS Header
|
||||
ZigbeeApsTxOptions txOptions(params.m_txOptions);
|
||||
ZigbeeApsHeader apsHeader;
|
||||
apsHeader.SetFrameType(ApsFrameType::APS_DATA);
|
||||
apsHeader.SetSrcEndpoint(params.m_srcEndPoint);
|
||||
apsHeader.SetProfileId(params.m_profileId);
|
||||
apsHeader.SetClusterId(params.m_clusterId);
|
||||
apsHeader.SetExtHeaderPresent(false);
|
||||
apsHeader.SetDeliveryMode(ApsDeliveryMode::APS_UCST);
|
||||
|
||||
// NLDE-data.request params
|
||||
NldeDataRequestParams nwkParams;
|
||||
nwkParams.m_radius = params.m_radius;
|
||||
nwkParams.m_discoverRoute = DiscoverRouteType::ENABLE_ROUTE_DISCOVERY;
|
||||
nwkParams.m_securityEnable = txOptions.IsSecurityEnabled();
|
||||
nwkParams.m_dstAddrMode = AddressMode::UCST_BCST;
|
||||
|
||||
SrcBindingEntry srcEntry;
|
||||
std::vector<DstBindingEntry> dstEntries;
|
||||
|
||||
if (m_apsBindingTable.LookUpEntries(srcEntry, dstEntries))
|
||||
{
|
||||
for (const auto& dst : dstEntries)
|
||||
{
|
||||
if (dst.GetDstAddrMode() == ApsDstAddressModeBind::DST_ADDR64_DST_ENDPOINT_PRESENT)
|
||||
{
|
||||
// We must look into the nwkAddressMap to transform the
|
||||
// 64 bit address destination to a 16 bit destination
|
||||
NS_LOG_WARN("Bound destination found but 64bit destination not supported");
|
||||
// TODO: drop trace here
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send a UCST message to each destination
|
||||
nwkParams.m_dstAddr = dst.GetDstAddr16();
|
||||
apsHeader.SetApsCounter(m_apsCounter.GetValue());
|
||||
m_apsCounter++;
|
||||
Ptr<Packet> p = asdu->Copy();
|
||||
p->AddHeader(apsHeader);
|
||||
Simulator::ScheduleNow(&ZigbeeNwk::NldeDataRequest, m_nwk, nwkParams, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_apsdeDataConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::SUCCESS;
|
||||
confirmParams.m_txTime = Simulator::Now();
|
||||
m_apsdeDataConfirmCallback(confirmParams);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_apsdeDataConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::NO_BOUND_DEVICE;
|
||||
confirmParams.m_txTime = Simulator::Now();
|
||||
m_apsdeDataConfirmCallback(confirmParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SendDataUcstBcst(ApsdeDataRequestParams params, Ptr<Packet> asdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// Fill APSDE-data.confirm parameters in case we need to return an error
|
||||
ApsdeDataConfirmParams confirmParams;
|
||||
confirmParams.m_dstAddrMode = params.m_dstAddrMode;
|
||||
confirmParams.m_dstAddr16 = params.m_dstAddr16;
|
||||
confirmParams.m_dstAddr64 = params.m_dstAddr64;
|
||||
confirmParams.m_dstEndPoint = params.m_dstEndPoint;
|
||||
confirmParams.m_srcEndPoint = params.m_srcEndPoint;
|
||||
|
||||
// APS Header
|
||||
ZigbeeApsTxOptions txOptions(params.m_txOptions);
|
||||
ZigbeeApsHeader apsHeader;
|
||||
apsHeader.SetFrameType(ApsFrameType::APS_DATA);
|
||||
apsHeader.SetSrcEndpoint(params.m_srcEndPoint);
|
||||
apsHeader.SetProfileId(params.m_profileId);
|
||||
apsHeader.SetClusterId(params.m_clusterId);
|
||||
apsHeader.SetExtHeaderPresent(false);
|
||||
apsHeader.SetDeliveryMode(ApsDeliveryMode::APS_UCST);
|
||||
|
||||
// NLDE-data.request params
|
||||
NldeDataRequestParams nwkParams;
|
||||
nwkParams.m_radius = params.m_radius;
|
||||
nwkParams.m_discoverRoute = DiscoverRouteType::ENABLE_ROUTE_DISCOVERY;
|
||||
nwkParams.m_securityEnable = txOptions.IsSecurityEnabled();
|
||||
nwkParams.m_dstAddrMode = AddressMode::UCST_BCST;
|
||||
|
||||
if (params.m_dstAddr16 == "FF:FF" || params.m_dstAddr16 == "FF:FD" ||
|
||||
params.m_dstAddr16 == "FF:FC" || params.m_dstAddr16 == "FF:FB")
|
||||
{
|
||||
// Destination is a broadcast address
|
||||
apsHeader.SetDeliveryMode(ApsDeliveryMode::APS_BCST);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destination is a unicast address
|
||||
apsHeader.SetDeliveryMode(ApsDeliveryMode::APS_UCST);
|
||||
}
|
||||
|
||||
if (params.m_useAlias)
|
||||
{
|
||||
if (txOptions.IsAckRequired()) // 0b1 = 00000001 = 1 dec
|
||||
{
|
||||
if (!m_apsdeDataConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::NOT_SUPPORTED;
|
||||
confirmParams.m_txTime = Simulator::Now();
|
||||
m_apsdeDataConfirmCallback(confirmParams);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nwkParams.m_useAlias = params.m_useAlias;
|
||||
nwkParams.m_aliasSeqNumber = params.m_aliasSeqNumb;
|
||||
nwkParams.m_aliasSrcAddr = params.m_aliasSrcAddr;
|
||||
|
||||
apsHeader.SetApsCounter(params.m_aliasSeqNumb);
|
||||
}
|
||||
else
|
||||
{
|
||||
apsHeader.SetApsCounter(m_apsCounter.GetValue());
|
||||
m_apsCounter++;
|
||||
}
|
||||
|
||||
nwkParams.m_dstAddrMode = AddressMode::UCST_BCST;
|
||||
nwkParams.m_dstAddr = params.m_dstAddr16;
|
||||
apsHeader.SetDstEndpoint(params.m_dstEndPoint);
|
||||
|
||||
asdu->AddHeader(apsHeader);
|
||||
|
||||
Simulator::ScheduleNow(&ZigbeeNwk::NldeDataRequest, m_nwk, nwkParams, asdu);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::ApsmeBindRequest(ApsmeBindRequestParams params)
|
||||
{
|
||||
ApsmeBindConfirmParams confirmParams;
|
||||
confirmParams.m_srcAddr = params.m_srcAddr;
|
||||
confirmParams.m_srcEndPoint = params.m_srcEndPoint;
|
||||
confirmParams.m_clusterId = params.m_clusterId;
|
||||
confirmParams.m_dstAddr16 = params.m_dstAddr16;
|
||||
confirmParams.m_dstAddr64 = params.m_dstAddr64;
|
||||
confirmParams.m_dstAddrMode = params.m_dstAddrMode;
|
||||
confirmParams.m_dstEndPoint = params.m_dstEndPoint;
|
||||
|
||||
// TODO: confirm the device has joined the network
|
||||
// How? APS have no access to join information.
|
||||
|
||||
// Verify params are in valid range (2.2.4.3.1)
|
||||
if ((params.m_srcEndPoint < 0x01 || params.m_srcEndPoint > 0xfe) ||
|
||||
(params.m_dstEndPoint < 0x01))
|
||||
{
|
||||
if (!m_apsmeBindConfirmCallback.IsNull())
|
||||
{
|
||||
confirmParams.m_status = ApsStatus::ILLEGAL_REQUEST;
|
||||
m_apsmeBindConfirmCallback(confirmParams);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SrcBindingEntry srcEntry(params.m_srcAddr, params.m_srcEndPoint, params.m_clusterId);
|
||||
|
||||
DstBindingEntry dstEntry;
|
||||
|
||||
if (params.m_dstAddrMode == ApsDstAddressModeBind::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT)
|
||||
{
|
||||
// Group Addressing binding
|
||||
dstEntry.SetDstAddrMode(ApsDstAddressModeBind::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT);
|
||||
dstEntry.SetDstAddr16(params.m_dstAddr16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unicast binding
|
||||
dstEntry.SetDstAddrMode(ApsDstAddressModeBind::DST_ADDR64_DST_ENDPOINT_PRESENT);
|
||||
dstEntry.SetDstEndPoint(params.m_dstEndPoint);
|
||||
}
|
||||
|
||||
switch (m_apsBindingTable.Bind(srcEntry, dstEntry))
|
||||
{
|
||||
case BindingTableStatus::BOUND:
|
||||
confirmParams.m_status = ApsStatus::SUCCESS;
|
||||
break;
|
||||
case BindingTableStatus::ENTRY_EXISTS:
|
||||
confirmParams.m_status = ApsStatus::INVALID_BINDING;
|
||||
break;
|
||||
case BindingTableStatus::TABLE_FULL:
|
||||
confirmParams.m_status = ApsStatus::TABLE_FULL;
|
||||
break;
|
||||
default:
|
||||
NS_LOG_ERROR("Invalid binding option");
|
||||
}
|
||||
|
||||
if (!m_apsmeBindConfirmCallback.IsNull())
|
||||
{
|
||||
m_apsmeBindConfirmCallback(confirmParams);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::ApsmeUnbindRequest(ApsmeBindRequestParams params)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::NldeDataConfirm(NldeDataConfirmParams params)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::NldeDataIndication(NldeDataIndicationParams params, Ptr<Packet> nsdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
ZigbeeApsHeader apsHeader;
|
||||
nsdu->RemoveHeader(apsHeader);
|
||||
|
||||
ApsdeDataIndicationParams indicationParams;
|
||||
indicationParams.m_status = ApsStatus::SUCCESS;
|
||||
|
||||
// TODO:
|
||||
// See section 2.2.4.1.3.
|
||||
// - Handle Security
|
||||
// - Handle grouping(MCST) (Note group table shared by NWK and APS)
|
||||
// - Handle binding
|
||||
// - Handle fragmentation
|
||||
// - Detect Duplicates
|
||||
// - Handle ACK
|
||||
|
||||
// Check if packet is fragmented
|
||||
if (apsHeader.IsExtHeaderPresent())
|
||||
{
|
||||
indicationParams.m_status = ApsStatus::DEFRAG_UNSUPPORTED;
|
||||
if (!m_apsdeDataIndicationCallback.IsNull())
|
||||
{
|
||||
m_apsdeDataIndicationCallback(indicationParams, nsdu);
|
||||
}
|
||||
NS_LOG_WARN("Extended Header (Fragmentation) not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
if (apsHeader.GetFrameType() == ApsFrameType::APS_DATA)
|
||||
{
|
||||
if (apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_UCST ||
|
||||
apsHeader.GetDeliveryMode() == ApsDeliveryMode::APS_BCST)
|
||||
{
|
||||
indicationParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
|
||||
// Note: Extracting the Address directly from the NWK, creates a dependency on this NWK
|
||||
// implementation. This is not a very good design, but in practice, it is unavoidable
|
||||
// due to the descriptions in the specification.
|
||||
indicationParams.m_dstAddr16 = m_nwk->GetNetworkAddress();
|
||||
indicationParams.m_dstEndPoint = apsHeader.GetDstEndpoint();
|
||||
indicationParams.m_srcAddrMode = ApsSrcAddressMode::SRC_ADDR16_SRC_ENDPOINT_PRESENT;
|
||||
indicationParams.m_srcAddress16 = params.m_srcAddr;
|
||||
indicationParams.m_srcEndpoint = apsHeader.GetSrcEndpoint();
|
||||
indicationParams.m_profileId = apsHeader.GetProfileId();
|
||||
indicationParams.m_clusterId = apsHeader.GetClusterId();
|
||||
indicationParams.asduLength = nsdu->GetSize();
|
||||
indicationParams.m_securityStatus = ApsSecurityStatus::UNSECURED;
|
||||
indicationParams.m_linkQuality = params.m_linkQuality;
|
||||
indicationParams.m_rxTime = Simulator::Now();
|
||||
|
||||
if (!m_apsdeDataIndicationCallback.IsNull())
|
||||
{
|
||||
m_apsdeDataIndicationCallback(indicationParams, nsdu);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Group deliveryMode == (MCST)
|
||||
NS_LOG_WARN("Group delivery not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SetApsdeDataConfirmCallback(ApsdeDataConfirmCallback c)
|
||||
{
|
||||
m_apsdeDataConfirmCallback = c;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SetApsdeDataIndicationCallback(ApsdeDataIndicationCallback c)
|
||||
{
|
||||
m_apsdeDataIndicationCallback = c;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SetApsmeBindConfirmCallback(ApsmeBindConfirmCallback c)
|
||||
{
|
||||
m_apsmeBindConfirmCallback = c;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeAps::SetApsmeUnbindConfirmCallback(ApsmeUnbindConfirmCallback c)
|
||||
{
|
||||
m_apsmeUnbindConfirmCallback = c;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
// ZigbeeApsTxOptions //
|
||||
//////////////////////////
|
||||
|
||||
ZigbeeApsTxOptions::ZigbeeApsTxOptions(uint8_t value)
|
||||
: m_txOptions(value)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetSecurityEnabled(bool enable)
|
||||
{
|
||||
SetBit(0, enable);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetUseNwkKey(bool enable)
|
||||
{
|
||||
SetBit(1, enable);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetAckRequired(bool enable)
|
||||
{
|
||||
SetBit(2, enable);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetFragmentationPermitted(bool enable)
|
||||
{
|
||||
SetBit(3, enable);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetIncludeExtendedNonce(bool enable)
|
||||
{
|
||||
SetBit(4, enable);
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::IsSecurityEnabled() const
|
||||
{
|
||||
return GetBit(0);
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::IsUseNwkKey() const
|
||||
{
|
||||
return GetBit(1);
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::IsAckRequired() const
|
||||
{
|
||||
return GetBit(2);
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::IsFragmentationPermitted() const
|
||||
{
|
||||
return GetBit(3);
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::IsIncludeExtendedNonce() const
|
||||
{
|
||||
return GetBit(4);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ZigbeeApsTxOptions::GetTxOptions() const
|
||||
{
|
||||
return m_txOptions;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsTxOptions::SetBit(int pos, bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
m_txOptions |= (1 << pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_txOptions &= ~(1 << pos);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ZigbeeApsTxOptions::GetBit(int pos) const
|
||||
{
|
||||
return (m_txOptions >> pos) & 1;
|
||||
}
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
551
src/zigbee/model/zigbee-aps.h
Normal file
551
src/zigbee/model/zigbee-aps.h
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#ifndef ZIGBEE_APS_H
|
||||
#define ZIGBEE_APS_H
|
||||
|
||||
#include "zigbee-aps-header.h"
|
||||
#include "zigbee-aps-tables.h"
|
||||
#include "zigbee-nwk.h"
|
||||
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/mac16-address.h"
|
||||
#include "ns3/mac64-address.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/random-variable-stream.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
#include "ns3/traced-value.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace zigbee
|
||||
{
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* APS Destination Address Mode,
|
||||
* Zigbee Specification r22.1.0
|
||||
* Table 2-2 APSDE-DATA.request Parameters
|
||||
* See Table 2-4 APSDE-DATA.indication Parameters
|
||||
*/
|
||||
enum class ApsDstAddressMode : std::uint8_t
|
||||
{
|
||||
DST_ADDR_AND_DST_ENDPOINT_NOT_PRESENT = 0x00, //!< Destination address and destination endpoint
|
||||
//!< not present.
|
||||
GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT = 0x01, //!< Group address or 16-bit destination address
|
||||
//!< present but destination endpoint not present.
|
||||
DST_ADDR16_DST_ENDPOINT_PRESENT = 0x02, //!< 16-bit destination address and destination
|
||||
//!< endpoint present.
|
||||
DST_ADDR64_DST_ENDPOINT_PRESENT = 0x03, //!< 64-bit destination address and destination
|
||||
//!< endpoint present.
|
||||
DST_ADDR64_DST_ENDPOINT_NOT_PRESENT = 0x04 //!< 64-bit address present but destination
|
||||
//!< endpoint not present.
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* APS Source Address Mode,
|
||||
* Zigbee Specification r22.1.0
|
||||
* See Table 2-4 APSDE-DATA.indication Parameters
|
||||
*/
|
||||
enum class ApsSrcAddressMode : std::uint8_t
|
||||
{
|
||||
SRC_ADDR16_SRC_ENDPOINT_PRESENT = 0x02, //!< 16-bit source address and source endpoint present
|
||||
SRC_ADDR64_SRC_ENDPOINT_PRESENT = 0x03, //!< 64-bit source address and source endpoint present
|
||||
SRC_ADDR64_SRC_ENDPOINT_NOT_PRESENT = 0x04 //!< 64-bit source address present but source
|
||||
//!< endpoint not present
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* APS Security status
|
||||
* See Zigbee Specification r22.1.0, Table 2-4
|
||||
* APSDE-DATA.indication Parameters
|
||||
*/
|
||||
enum class ApsSecurityStatus : std::uint8_t
|
||||
{
|
||||
UNSECURED = 0x00, //!< Unsecured status
|
||||
SECURED_NWK_KEY = 0x01, //!< Use NWK secure key
|
||||
SECURED_LINK_KEY = 0x02 //!< Use link secure key
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* APS Sub-layer Status Values
|
||||
* See Zigbee Specification r22.1.0, Table 2-27
|
||||
*/
|
||||
enum class ApsStatus : std::uint8_t
|
||||
{
|
||||
SUCCESS = 0x00, //!< A request has been executed successfully.
|
||||
ASDU_TOO_LONG = 0xa0, //!< A received fragmented
|
||||
//!< frame could not be defragmented at the current time.
|
||||
DEFRAG_DEFERRED = 0xa1, //!< Defragmentation deferred.
|
||||
DEFRAG_UNSUPPORTED = 0xa2, //!< Defragmentation is not supported.
|
||||
ILLEGAL_REQUEST = 0xa3, //!< Illegal request
|
||||
INVALID_BINDING = 0xa4, //!< Invalid binding
|
||||
INVALID_GROUP = 0xa5, //!< Invalid group
|
||||
INVALID_PARAMETER = 0xa6, //!< A parameter value was invalid or out of range
|
||||
NO_ACK = 0xa7, //!< No Acknowledgment
|
||||
NO_BOUND_DEVICE = 0xa8, //!< No bound device
|
||||
NO_SHORT_ADDRESS = 0xa9, //!< No short address present
|
||||
NOT_SUPPORTED = 0xaa, //!< Not supported in APS
|
||||
SECURED_LINK_KEY = 0xab, //!< Secured link key present
|
||||
SECURED_NWK_KEY = 0xac, //!< Secured network key present
|
||||
SECURITY_FAIL = 0xad, //!< Security failed
|
||||
TABLE_FULL = 0xae, //!< Binding table or group table is full
|
||||
UNSECURED = 0xaf, //!< Unsecured
|
||||
UNSUPPORTED_ATTRIBUTE = 0xb0 //!< Unsupported attribute
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.1.1
|
||||
* APSDE-DATA.request params.
|
||||
*/
|
||||
struct ApsdeDataRequestParams
|
||||
{
|
||||
ApsDstAddressMode m_dstAddrMode{
|
||||
ApsDstAddressMode::DST_ADDR_AND_DST_ENDPOINT_NOT_PRESENT}; //!< Destination address mode.
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address
|
||||
Mac64Address m_dstAddr64; //!< The destination 64-bit address
|
||||
uint8_t m_dstEndPoint{0}; //!< The destination endpoint
|
||||
uint16_t m_profileId{0}; //!< The application profile ID
|
||||
uint16_t m_clusterId{0}; //!< The application cluster ID
|
||||
uint8_t m_srcEndPoint{0}; //!< The source endpoint
|
||||
uint32_t m_asduLength{0}; //!< The ASDU length
|
||||
uint8_t m_txOptions{0}; //!< Transmission options
|
||||
bool m_useAlias{false}; //!< Indicates if alias is used in this transmission
|
||||
Mac16Address m_aliasSrcAddr; //!< Alias source address
|
||||
uint8_t m_aliasSeqNumb{0}; //!< Alias sequence number
|
||||
uint8_t m_radius{0}; //!< Radius (Number of hops this message travels)
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.1.2
|
||||
* APSDE-DATA.confirm params.
|
||||
*/
|
||||
struct ApsdeDataConfirmParams
|
||||
{
|
||||
ApsDstAddressMode m_dstAddrMode{
|
||||
ApsDstAddressMode::DST_ADDR_AND_DST_ENDPOINT_NOT_PRESENT}; //!< Destination address mode.
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address.
|
||||
Mac64Address m_dstAddr64; //!< The destination IEEE address (64-bit address).
|
||||
uint8_t m_dstEndPoint{0}; //!< The destination endpoint.
|
||||
uint8_t m_srcEndPoint{0}; //!< The source endpoint.
|
||||
ApsStatus m_status{ApsStatus::UNSUPPORTED_ATTRIBUTE}; //!< The confirmation status.
|
||||
Time m_txTime; //!< The transmission timestamp.
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.1.3
|
||||
* APSDE-DATA.indications params.
|
||||
*/
|
||||
struct ApsdeDataIndicationParams
|
||||
{
|
||||
ApsDstAddressMode m_dstAddrMode{
|
||||
ApsDstAddressMode::DST_ADDR_AND_DST_ENDPOINT_NOT_PRESENT}; //!< The destination
|
||||
//!< address mode
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address
|
||||
Mac64Address m_dstAddr64; //!< The destination IEEE address (64-bit address)
|
||||
uint8_t m_dstEndPoint{0xF0}; //!< The destination endpoint
|
||||
ApsSrcAddressMode m_srcAddrMode{
|
||||
ApsSrcAddressMode::SRC_ADDR16_SRC_ENDPOINT_PRESENT}; //!< The
|
||||
//!< source address mode
|
||||
|
||||
Mac16Address m_srcAddress16; //!< The 16-bit address
|
||||
Mac64Address m_srcAddress64; //!< The IEEE source address (64-bit address)
|
||||
uint8_t m_srcEndpoint{0xF0}; //!< The application source endpoint
|
||||
uint16_t m_profileId{0xC0DE}; //!< The application profile ID
|
||||
uint16_t m_clusterId{0x0000}; //!< The application cluster ID
|
||||
uint8_t asduLength{0}; //!< The size of the the ASDU packet
|
||||
ApsStatus m_status{ApsStatus::SUCCESS}; //!< The data indication status
|
||||
ApsSecurityStatus m_securityStatus{ApsSecurityStatus::UNSECURED}; //!< Security status
|
||||
uint8_t m_linkQuality{0}; //!< The link quality indication value
|
||||
Time m_rxTime; //!< The reception timestamp
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Sections 2.2.4.3.1 and 2.2.4.3.3
|
||||
* APSME-BIND.request and APSME-UNBIND.request params.
|
||||
*/
|
||||
struct ApsmeBindRequestParams
|
||||
{
|
||||
Mac64Address m_srcAddr; //!< The source IEEE address (64-bit address)
|
||||
uint8_t m_srcEndPoint{0}; //!< The application source endpoint
|
||||
uint16_t m_clusterId{0}; //!< The application cluster ID
|
||||
ApsDstAddressModeBind m_dstAddrMode{
|
||||
ApsDstAddressModeBind::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT}; //!< Destination address mode.
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address
|
||||
Mac64Address m_dstAddr64; //!< The destination 64-bit address
|
||||
uint8_t m_dstEndPoint{0xF0}; //!< The application destination endpoint
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Sections 2.2.4.3.2 and 2.2.4.3.4
|
||||
* APSME-BIND.confirm and APSME-UNBIND.confirm params
|
||||
*/
|
||||
struct ApsmeBindConfirmParams
|
||||
{
|
||||
ApsStatus m_status{ApsStatus::UNSUPPORTED_ATTRIBUTE}; //!< The status of the bind request
|
||||
Mac64Address m_srcAddr; //!< The application source address
|
||||
uint8_t m_srcEndPoint{0}; //!< The application source endpoint
|
||||
uint16_t m_clusterId{0}; //!< The application cluster ID
|
||||
ApsDstAddressModeBind m_dstAddrMode{
|
||||
ApsDstAddressModeBind::GROUP_ADDR_DST_ENDPOINT_NOT_PRESENT}; //!< Destination address mode.
|
||||
Mac16Address m_dstAddr16; //!< The destination 16-bit address
|
||||
Mac64Address m_dstAddr64; //!< The destination 64-bit address
|
||||
uint8_t m_dstEndPoint{0xF0}; //!< The application destination endpoint
|
||||
};
|
||||
|
||||
//////////////////////
|
||||
// Callbacks //
|
||||
//////////////////////
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* This callback is called to confirm a successfully transmission of an ASDU.
|
||||
*/
|
||||
typedef Callback<void, ApsdeDataConfirmParams> ApsdeDataConfirmCallback;
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* This callback is called after a ASDU has successfully received and
|
||||
* APS push it to deliver it to the next higher layer (typically the application framework).
|
||||
*/
|
||||
typedef Callback<void, ApsdeDataIndicationParams, Ptr<Packet>> ApsdeDataIndicationCallback;
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* This callback is called to confirm a successfully addition of a destination
|
||||
* into the binding table.
|
||||
*/
|
||||
typedef Callback<void, ApsmeBindConfirmParams> ApsmeBindConfirmCallback;
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* This callback is called to confirm a successfully unbind request performed
|
||||
* into the binding table.
|
||||
*/
|
||||
typedef Callback<void, ApsmeBindConfirmParams> ApsmeUnbindConfirmCallback;
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Zigbee Specification r22.1.0, Section 2.2.3
|
||||
* Class that implements the Zigbee Specification Application Support Sub-layer (APS).
|
||||
*/
|
||||
class ZigbeeAps : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get the type ID.
|
||||
*
|
||||
* @return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
ZigbeeAps();
|
||||
~ZigbeeAps() override;
|
||||
|
||||
/**
|
||||
* Set the underlying NWK to use in this Zigbee APS
|
||||
*
|
||||
* @param nwk The pointer to the underlying Zigbee NWK to set to this Zigbee APS
|
||||
*/
|
||||
void SetNwk(Ptr<ZigbeeNwk> nwk);
|
||||
|
||||
/**
|
||||
* Get the underlying NWK used by the current Zigbee APS.
|
||||
*
|
||||
* @return The pointer to the underlying NWK object currently connected to the Zigbee APS.
|
||||
*/
|
||||
Ptr<ZigbeeNwk> GetNwk() const;
|
||||
|
||||
/**
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.1.1
|
||||
* APSDE-DATA.request
|
||||
* Request the transmission of data to one or more entities.
|
||||
*
|
||||
* @param params The APSDE data request params
|
||||
* @param asdu The packet to transmit
|
||||
*/
|
||||
void ApsdeDataRequest(ApsdeDataRequestParams params, Ptr<Packet> asdu);
|
||||
|
||||
/**
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.3.1
|
||||
* APSME-BIND.request
|
||||
* Bind a source entry to one or more destination entries in the binding table.
|
||||
*
|
||||
* @param params The APSDE bind request params
|
||||
*/
|
||||
void ApsmeBindRequest(ApsmeBindRequestParams params);
|
||||
|
||||
/**
|
||||
* Zigbee Specification r22.1.0, Section 2.2.4.3.3
|
||||
* APSME-BIND.request
|
||||
* Unbind a destination entry from a source entry in the binding table.
|
||||
*
|
||||
* @param params The APSDE bind request params
|
||||
*/
|
||||
void ApsmeUnbindRequest(ApsmeBindRequestParams params);
|
||||
|
||||
/**
|
||||
* Zigbee Specification r22.1.0, Section 3.2.1.2
|
||||
* NLDE-DATA.confirm
|
||||
* Used to report to the APS the transmission of data from the NWK.
|
||||
*
|
||||
* @param params The NLDE data confirm params
|
||||
*/
|
||||
void NldeDataConfirm(NldeDataConfirmParams params);
|
||||
|
||||
/**
|
||||
* Zigbee Specification r22.1.0, Section 3.2.1.3
|
||||
* NLDE-DATA.indication
|
||||
* Used to report to the APS the reception of data from the NWK.
|
||||
*
|
||||
* @param params The NLDE data indication params
|
||||
* @param nsdu The packet received
|
||||
*/
|
||||
void NldeDataIndication(NldeDataIndicationParams params, Ptr<Packet> nsdu);
|
||||
|
||||
/**
|
||||
* Set the callback as part of the interconnections between the APS and
|
||||
* the next layer or service (typically the application framework). The callback
|
||||
* implements the callback used in a APSDE-DATA.confirm
|
||||
*
|
||||
* @param c the ApsdeDataConfirm callback
|
||||
*/
|
||||
void SetApsdeDataConfirmCallback(ApsdeDataConfirmCallback c);
|
||||
|
||||
/**
|
||||
* Set the callback as part of the interconnections between the APS and
|
||||
* the next layer or service (typically the application framework). The callback
|
||||
* implements the callback used in a APSDE-DATA.indication
|
||||
*
|
||||
* @param c the ApsdeDataIndication callback
|
||||
*/
|
||||
void SetApsdeDataIndicationCallback(ApsdeDataIndicationCallback c);
|
||||
|
||||
/**
|
||||
* Set the callback as part of the interconnections between the APS and
|
||||
* the next layer or service (typically the application framework). The callback
|
||||
* implements the callback used in a APSME-BIND.confirm
|
||||
*
|
||||
* @param c the ApsmeBindConfirm callback
|
||||
*/
|
||||
void SetApsmeBindConfirmCallback(ApsmeBindConfirmCallback c);
|
||||
|
||||
/**
|
||||
* Set the callback as part of the interconnections between the APS and
|
||||
* the next layer or service (typically the application framework). The callback
|
||||
* implements the callback used in a APSDE-UNBIND.confirm
|
||||
*
|
||||
* @param c the ApsdeUnbindConfirm callback
|
||||
*/
|
||||
void SetApsmeUnbindConfirmCallback(ApsmeUnbindConfirmCallback c);
|
||||
|
||||
protected:
|
||||
void DoInitialize() override;
|
||||
void DoDispose() override;
|
||||
void NotifyConstructionCompleted() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Send a Groupcast or IEEE address destination from a list of destination in
|
||||
* the binding table.
|
||||
*
|
||||
* @param params The APSDE data request params
|
||||
* @param asdu The packet to transmit
|
||||
*/
|
||||
void SendDataWithBindingTable(ApsdeDataRequestParams params, Ptr<Packet> asdu);
|
||||
|
||||
/**
|
||||
* Send a regular UCST or BCST data transmission to a known 16-bit address destination.
|
||||
*
|
||||
* @param params The APSDE data request params
|
||||
* @param asdu The packet to transmit
|
||||
*/
|
||||
void SendDataUcstBcst(ApsdeDataRequestParams params, Ptr<Packet> asdu);
|
||||
|
||||
Ptr<ZigbeeNwk> m_nwk; //!< Pointer to the underlying NWK connected to this Zigbee APS
|
||||
SequenceNumber8 m_apsCounter; //!< The sequence number used in packet Tx with APS headers.
|
||||
BindingTable m_apsBindingTable; //!< The binding table associated to this APS layer
|
||||
|
||||
/**
|
||||
* This callback is used to to notify the results of a data transmission
|
||||
* request to the Application framework (AF) making the request.
|
||||
* See Zigbee specification r22.1.0, Section 2.2.4.1.2
|
||||
*/
|
||||
ApsdeDataConfirmCallback m_apsdeDataConfirmCallback;
|
||||
|
||||
/**
|
||||
* This callback is used to to notify the reception of data
|
||||
* to the Application framework (AF).
|
||||
* See Zigbee specification r22.1.0, Section 2.2.4.1.3
|
||||
*/
|
||||
ApsdeDataIndicationCallback m_apsdeDataIndicationCallback;
|
||||
|
||||
/**
|
||||
* This callback is used to to notify the result of a binding
|
||||
* request in the APS to the Application framework (AF).
|
||||
* See Zigbee specification r22.1.0, Section 2.2.4.3.2
|
||||
*/
|
||||
ApsmeBindConfirmCallback m_apsmeBindConfirmCallback;
|
||||
|
||||
/**
|
||||
* This callback is used to to notify the result of a unbinding
|
||||
* request in the APS to the Application framework (AF).
|
||||
* See Zigbee specification r22.1.0, Section 2.2.4.3.4
|
||||
*/
|
||||
ApsmeUnbindConfirmCallback m_apsmeUnbindConfirmCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* Helper class used to craft the transmission options bitmap used by the
|
||||
* APSDE-DATA.request.
|
||||
*/
|
||||
class ZigbeeApsTxOptions
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The constructor of the Tx options class.
|
||||
*
|
||||
* @param value The value to set in the Tx options.
|
||||
*/
|
||||
ZigbeeApsTxOptions(uint8_t value = 0);
|
||||
|
||||
/**
|
||||
* Set the security enable bit of the TX options.
|
||||
*
|
||||
* @param enable True if security is enabled.
|
||||
*/
|
||||
void SetSecurityEnabled(bool enable);
|
||||
|
||||
/**
|
||||
* Set the use network key bit of the TX options.
|
||||
*
|
||||
* @param enable True if Network key should be used.
|
||||
*/
|
||||
void SetUseNwkKey(bool enable);
|
||||
|
||||
/**
|
||||
* Set the Acknowledgement required bit of the Tx options.
|
||||
*
|
||||
* @param enable True if ACK is required.
|
||||
*/
|
||||
void SetAckRequired(bool enable);
|
||||
|
||||
/**
|
||||
* Set the fragmentation bit of the Tx options
|
||||
*
|
||||
* @param enable True if fragmentation is allowed in the transmission.
|
||||
*/
|
||||
void SetFragmentationPermitted(bool enable);
|
||||
|
||||
/**
|
||||
* Set the include extended nonce bit of the Tx options
|
||||
*
|
||||
* @param enable True if the frame should include the extended nonce
|
||||
*/
|
||||
void SetIncludeExtendedNonce(bool enable);
|
||||
|
||||
/**
|
||||
* Show if the security enable bit of the Tx options is present.
|
||||
*
|
||||
* @return True if the bit is active
|
||||
*/
|
||||
bool IsSecurityEnabled() const;
|
||||
|
||||
/**
|
||||
* Show if the use network key bit of the Tx options is present.
|
||||
*
|
||||
* @return True if the bit is active
|
||||
*/
|
||||
bool IsUseNwkKey() const;
|
||||
|
||||
/**
|
||||
* Show if the ACK bit of the Tx options is present.
|
||||
*
|
||||
* @return True if the bit is active
|
||||
*/
|
||||
bool IsAckRequired() const;
|
||||
|
||||
/**
|
||||
* Show if the fragmentation permitted bit of the Tx options is present.
|
||||
*
|
||||
* @return True if the bit is active
|
||||
*/
|
||||
bool IsFragmentationPermitted() const;
|
||||
|
||||
/**
|
||||
* Show if the include extended nonce bit of the Tx options is present.
|
||||
*
|
||||
* @return True if the bit is active
|
||||
*/
|
||||
bool IsIncludeExtendedNonce() const;
|
||||
|
||||
/**
|
||||
* Get the complete bitmap containing the Tx options
|
||||
*
|
||||
* @return The Tx options bitmap.
|
||||
*/
|
||||
uint8_t GetTxOptions() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set a bit value into a position in the uint8_t representint the Tx options.
|
||||
*
|
||||
* @param pos Position to shift
|
||||
* @param value Value to set
|
||||
*/
|
||||
void SetBit(int pos, bool value);
|
||||
|
||||
/**
|
||||
* Get the value of the bit at the position indicated.
|
||||
*
|
||||
* @param pos The position in the uint8_t Tx options
|
||||
* @return True if the bit value was obtained
|
||||
*/
|
||||
bool GetBit(int pos) const;
|
||||
|
||||
uint8_t m_txOptions; //!< the bitmap representing the Tx options
|
||||
};
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* ZIGBEE_APS_H */
|
||||
@@ -8,8 +8,8 @@
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#ifndef ZIGBEE_TABLES_H
|
||||
#define ZIGBEE_TABLES_H
|
||||
#ifndef ZIGBEE_NWK_TABLES_H
|
||||
#define ZIGBEE_NWK_TABLES_H
|
||||
|
||||
#include "zigbee-nwk-fields.h"
|
||||
|
||||
@@ -1324,4 +1324,4 @@ class BroadcastTransactionTable
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* ZIGBEE_TABLES_H */
|
||||
#endif /* ZIGBEE_NWK_TABLES_H */
|
||||
|
||||
@@ -297,7 +297,7 @@ struct NldeDataConfirmParams
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup lr-wpan
|
||||
* @ingroup zigbee
|
||||
*
|
||||
* NLDE-DATA.indication params. See Zigbee Specification 3.2.1.3.1
|
||||
*/
|
||||
|
||||
@@ -40,8 +40,9 @@ ZigbeeStack::ZigbeeStack()
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
m_nwk = CreateObject<zigbee::ZigbeeNwk>();
|
||||
// TODO: Create APS layer here.
|
||||
// m_aps = CreateObject<zigbee::ZigbeeAps> ();
|
||||
m_aps = CreateObject<zigbee::ZigbeeAps>();
|
||||
|
||||
m_nwkOnly = false;
|
||||
}
|
||||
|
||||
ZigbeeStack::~ZigbeeStack()
|
||||
@@ -56,6 +57,7 @@ ZigbeeStack::DoDispose()
|
||||
|
||||
m_netDevice = nullptr;
|
||||
m_node = nullptr;
|
||||
m_aps = nullptr;
|
||||
m_nwk = nullptr;
|
||||
m_mac = nullptr;
|
||||
Object::DoDispose();
|
||||
@@ -66,18 +68,21 @@ ZigbeeStack::DoInitialize()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
AggregateObject(m_nwk);
|
||||
// AggregateObject(m_aps);
|
||||
|
||||
NS_ABORT_MSG_UNLESS(m_netDevice,
|
||||
"Invalid NetDevice found when attempting to install ZigbeeStack");
|
||||
|
||||
// Make sure the NetDevice is previously initialized
|
||||
// before using ZigbeeStack
|
||||
// before using ZigbeeStack (PHY and MAC are initialized)
|
||||
m_netDevice->Initialize();
|
||||
|
||||
m_mac = m_netDevice->GetObject<lrwpan::LrWpanMacBase>();
|
||||
NS_ABORT_MSG_UNLESS(m_mac,
|
||||
"No valid LrWpanMacBase found in this NetDevice, cannot use ZigbeeStack");
|
||||
"Invalid LrWpanMacBase found in this NetDevice, cannot use ZigbeeStack");
|
||||
|
||||
m_nwk->Initialize();
|
||||
AggregateObject(m_nwk);
|
||||
|
||||
// Set NWK callback hooks with the MAC
|
||||
m_nwk->SetMac(m_mac);
|
||||
@@ -97,14 +102,20 @@ ZigbeeStack::DoInitialize()
|
||||
m_mac->SetMlmeAssociateConfirmCallback(MakeCallback(&ZigbeeNwk::MlmeAssociateConfirm, m_nwk));
|
||||
// TODO: complete other callback hooks with the MAC
|
||||
|
||||
if (!m_nwkOnly)
|
||||
{
|
||||
// Set APS callback hooks with NWK (i.e., NLDE primitives only)
|
||||
m_nwk->SetNldeDataConfirmCallback(MakeCallback(&ZigbeeAps::NldeDataConfirm, m_aps));
|
||||
m_nwk->SetNldeDataIndicationCallback(MakeCallback(&ZigbeeAps::NldeDataIndication, m_aps));
|
||||
|
||||
m_aps->Initialize();
|
||||
m_aps->SetNwk(m_nwk);
|
||||
AggregateObject(m_aps);
|
||||
}
|
||||
|
||||
// Obtain Extended address as soon as NWK is set to begin operations
|
||||
m_mac->MlmeGetRequest(MacPibAttributeIdentifier::macExtendedAddress);
|
||||
|
||||
// TODO: Set APS callback hooks with NWK when support for APS layer is added.
|
||||
// For example:
|
||||
// m_aps->SetNwk (m_nwk);
|
||||
// m_nwk->SetNldeDataIndicationCallback (MakeCallback (&ZigbeeAps::NldeDataIndication, m_aps));
|
||||
|
||||
Object::DoInitialize();
|
||||
}
|
||||
|
||||
@@ -134,6 +145,12 @@ ZigbeeStack::SetNetDevice(Ptr<NetDevice> netDevice)
|
||||
m_node = m_netDevice->GetNode();
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeStack::SetOnlyNwkLayer()
|
||||
{
|
||||
m_nwkOnly = true;
|
||||
}
|
||||
|
||||
Ptr<zigbee::ZigbeeNwk>
|
||||
ZigbeeStack::GetNwk() const
|
||||
{
|
||||
@@ -148,5 +165,19 @@ ZigbeeStack::SetNwk(Ptr<zigbee::ZigbeeNwk> nwk)
|
||||
m_nwk = nwk;
|
||||
}
|
||||
|
||||
Ptr<zigbee::ZigbeeAps>
|
||||
ZigbeeStack::GetAps() const
|
||||
{
|
||||
return m_aps;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeStack::SetAps(Ptr<zigbee::ZigbeeAps> aps)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ABORT_MSG_IF(ZigbeeStack::IsInitialized(), "APS layer cannot be set after initialization");
|
||||
m_aps = aps;
|
||||
}
|
||||
|
||||
} // namespace zigbee
|
||||
} // namespace ns3
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef ZIGBEE_STACK_H
|
||||
#define ZIGBEE_STACK_H
|
||||
|
||||
#include "zigbee-aps.h"
|
||||
#include "zigbee-nwk.h"
|
||||
|
||||
#include "ns3/lr-wpan-mac-base.h"
|
||||
@@ -28,6 +29,7 @@ namespace zigbee
|
||||
{
|
||||
|
||||
class ZigbeeNwk;
|
||||
class ZigbeeAps;
|
||||
|
||||
/**
|
||||
* @ingroup zigbee
|
||||
@@ -84,6 +86,20 @@ class ZigbeeStack : public Object
|
||||
*/
|
||||
void SetNwk(Ptr<ZigbeeNwk> nwk);
|
||||
|
||||
/**
|
||||
* Get the APS layer used by this ZigbeeStack.
|
||||
*
|
||||
* @return the APS object
|
||||
*/
|
||||
Ptr<ZigbeeAps> GetAps() const;
|
||||
|
||||
/**
|
||||
* Set the APS layer used by this ZigbeeStack.
|
||||
*
|
||||
* @param aps The APS layer object
|
||||
*/
|
||||
void SetAps(Ptr<ZigbeeAps> aps);
|
||||
|
||||
/**
|
||||
* Returns a smart pointer to the underlying NetDevice.
|
||||
*
|
||||
@@ -100,6 +116,11 @@ class ZigbeeStack : public Object
|
||||
*/
|
||||
void SetNetDevice(Ptr<NetDevice> netDevice);
|
||||
|
||||
/**
|
||||
* Inticates to the Zigbee stack that only the NWK layer should be present.
|
||||
*/
|
||||
void SetOnlyNwkLayer();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Dispose of the Objects used by the ZigbeeStack
|
||||
@@ -114,8 +135,10 @@ class ZigbeeStack : public Object
|
||||
private:
|
||||
Ptr<lrwpan::LrWpanMacBase> m_mac; //!< The underlying LrWpan MAC connected to this Zigbee Stack.
|
||||
Ptr<ZigbeeNwk> m_nwk; //!< The Zigbee Network layer.
|
||||
Ptr<ZigbeeAps> m_aps; //!< The Zigbee Application Support Sub-layer
|
||||
Ptr<Node> m_node; //!< The node associated with this NetDevice.
|
||||
Ptr<NetDevice> m_netDevice; //!< Smart pointer to the underlying NetDevice.
|
||||
bool m_nwkOnly; //!< Indicates that only the NWK layer is present in the Zigbee stack
|
||||
};
|
||||
|
||||
} // namespace zigbee
|
||||
|
||||
330
src/zigbee/test/zigbee-aps-data-test.cc
Normal file
330
src/zigbee/test/zigbee-aps-data-test.cc
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Tokushima University, Tokushima, Japan
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Author:
|
||||
* Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
|
||||
*/
|
||||
|
||||
#include "ns3/constant-position-mobility-model.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/lr-wpan-module.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/propagation-delay-model.h"
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/rng-seed-manager.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/single-model-spectrum-channel.h"
|
||||
#include "ns3/zigbee-module.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
using namespace ns3::lrwpan;
|
||||
using namespace ns3::zigbee;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("zigbee-aps-data-test");
|
||||
|
||||
/**
|
||||
* @ingroup zigbee-test
|
||||
* @ingroup tests
|
||||
*
|
||||
* Zigbee RREQ transmission retries test case
|
||||
*/
|
||||
class ZigbeeApsDataTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
ZigbeeApsDataTestCase();
|
||||
~ZigbeeApsDataTestCase() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Callback for APSDE-DATA.indication
|
||||
* This callback is called when a data packet is received by the APS layer.
|
||||
*
|
||||
* @param testcase The ZigbeeApsDataTestCase instance
|
||||
* @param stack The Zigbee stack that received the data
|
||||
* @param params The parameters of the APSDE-DATA.indication
|
||||
* @param asdu The received packet
|
||||
*/
|
||||
static void ApsDataIndication(ZigbeeApsDataTestCase* testcase,
|
||||
Ptr<ZigbeeStack> stack,
|
||||
ApsdeDataIndicationParams params,
|
||||
Ptr<Packet> asdu);
|
||||
|
||||
/**
|
||||
* Callback for NLME-NETWORK-DISCOVERY.confirm
|
||||
* This callback is called when a network discovery has been performed.
|
||||
*
|
||||
* @param testcase The ZigbeeApsDataTestCase instance
|
||||
* @param stack The Zigbee stack that received the confirmation
|
||||
* @param params The parameters of the NLME-NETWORK-DISCOVERY.confirm
|
||||
*/
|
||||
static void NwkNetworkDiscoveryConfirm(ZigbeeApsDataTestCase* testcase,
|
||||
Ptr<ZigbeeStack> stack,
|
||||
NlmeNetworkDiscoveryConfirmParams params);
|
||||
|
||||
/**
|
||||
* Send data to a unicast destination.
|
||||
* This function sends a data packet from stackSrc to stackDst.
|
||||
*
|
||||
* @param stackSrc The source Zigbee stack
|
||||
* @param stackDst The destination Zigbee stack
|
||||
*/
|
||||
static void SendDataUcstDst(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst);
|
||||
|
||||
void DoRun() override;
|
||||
|
||||
uint16_t m_dstEndpoint; //!< The destination endpoint
|
||||
};
|
||||
|
||||
ZigbeeApsDataTestCase::ZigbeeApsDataTestCase()
|
||||
: TestCase("Zigbee: APS layer data test")
|
||||
{
|
||||
m_dstEndpoint = 0;
|
||||
}
|
||||
|
||||
ZigbeeApsDataTestCase::~ZigbeeApsDataTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsDataTestCase::ApsDataIndication(ZigbeeApsDataTestCase* testcase,
|
||||
Ptr<ZigbeeStack> stack,
|
||||
ApsdeDataIndicationParams params,
|
||||
Ptr<Packet> asdu)
|
||||
{
|
||||
testcase->m_dstEndpoint = params.m_dstEndPoint;
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsDataTestCase::NwkNetworkDiscoveryConfirm(ZigbeeApsDataTestCase* testcase,
|
||||
Ptr<ZigbeeStack> stack,
|
||||
NlmeNetworkDiscoveryConfirmParams params)
|
||||
{
|
||||
if (params.m_status == NwkStatus::SUCCESS)
|
||||
{
|
||||
NlmeJoinRequestParams joinParams;
|
||||
|
||||
zigbee::CapabilityInformation capaInfo;
|
||||
capaInfo.SetDeviceType(MacDeviceType::ENDDEVICE);
|
||||
capaInfo.SetAllocateAddrOn(true);
|
||||
|
||||
joinParams.m_rejoinNetwork = JoiningMethod::ASSOCIATION;
|
||||
joinParams.m_capabilityInfo = capaInfo.GetCapability();
|
||||
joinParams.m_extendedPanId = params.m_netDescList[0].m_extPanId;
|
||||
|
||||
Simulator::ScheduleNow(&ZigbeeNwk::NlmeJoinRequest, stack->GetNwk(), joinParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG("Unable to discover networks | status: " << params.m_status);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsDataTestCase::SendDataUcstDst(Ptr<ZigbeeStack> stackSrc, Ptr<ZigbeeStack> stackDst)
|
||||
{
|
||||
// UCST transmission to a single 16-bit address destination
|
||||
// Data is transmitted from device stackSrc to device stackDst.
|
||||
|
||||
Ptr<Packet> p = Create<Packet>(5);
|
||||
|
||||
// Because we currently do not have ZDO or ZCL or AF, clusterId
|
||||
// and profileId numbers are non-sensical.
|
||||
ApsdeDataRequestParams dataReqParams;
|
||||
// creates a BitMap with transmission options
|
||||
// Default, use 16 bit address destination (No option), equivalent to bitmap 0x00
|
||||
ZigbeeApsTxOptions txOptions;
|
||||
dataReqParams.m_txOptions = txOptions.GetTxOptions();
|
||||
dataReqParams.m_useAlias = false;
|
||||
dataReqParams.m_srcEndPoint = 3;
|
||||
dataReqParams.m_clusterId = 5; // Arbitrary value
|
||||
dataReqParams.m_profileId = 2; // Arbitrary value
|
||||
dataReqParams.m_dstAddrMode = ApsDstAddressMode::DST_ADDR16_DST_ENDPOINT_PRESENT;
|
||||
dataReqParams.m_dstAddr16 = stackDst->GetNwk()->GetNetworkAddress();
|
||||
dataReqParams.m_dstEndPoint = 4;
|
||||
|
||||
Simulator::ScheduleNow(&ZigbeeAps::ApsdeDataRequest, stackSrc->GetAps(), dataReqParams, p);
|
||||
}
|
||||
|
||||
void
|
||||
ZigbeeApsDataTestCase::DoRun()
|
||||
{
|
||||
// Transmit data using the APS layer.
|
||||
|
||||
// Zigbee Coordinator --------------> Zigbee EndDevice(destination endpoint:4)
|
||||
|
||||
// This test transmit a single packet to an enddevice with endpoint 4.
|
||||
// The data transmission is done using the mode DST_ADDR16_DST_ENDPOINT_PRESENT (Mode 0x02).
|
||||
// No fragmentations or Acknowledge is used
|
||||
// Verification that the devices have join the network is performed
|
||||
// (i.e., All devices have valid network addresses).
|
||||
|
||||
RngSeedManager::SetSeed(3);
|
||||
RngSeedManager::SetRun(4);
|
||||
|
||||
NodeContainer nodes;
|
||||
nodes.Create(3);
|
||||
|
||||
//// Add the PHY and MAC, configure the channel
|
||||
|
||||
LrWpanHelper lrWpanHelper;
|
||||
NetDeviceContainer lrwpanDevices = lrWpanHelper.Install(nodes);
|
||||
Ptr<LrWpanNetDevice> dev0 = lrwpanDevices.Get(0)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev1 = lrwpanDevices.Get(1)->GetObject<LrWpanNetDevice>();
|
||||
Ptr<LrWpanNetDevice> dev2 = lrwpanDevices.Get(2)->GetObject<LrWpanNetDevice>();
|
||||
|
||||
dev0->GetMac()->SetExtendedAddress("00:00:00:00:00:00:CA:FE");
|
||||
dev1->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:01");
|
||||
dev2->GetMac()->SetExtendedAddress("00:00:00:00:00:00:00:02");
|
||||
|
||||
Ptr<SingleModelSpectrumChannel> channel = CreateObject<SingleModelSpectrumChannel>();
|
||||
Ptr<LogDistancePropagationLossModel> propModel =
|
||||
CreateObject<LogDistancePropagationLossModel>();
|
||||
|
||||
Ptr<ConstantSpeedPropagationDelayModel> delayModel =
|
||||
CreateObject<ConstantSpeedPropagationDelayModel>();
|
||||
|
||||
channel->AddPropagationLossModel(propModel);
|
||||
channel->SetPropagationDelayModel(delayModel);
|
||||
|
||||
dev0->SetChannel(channel);
|
||||
dev1->SetChannel(channel);
|
||||
dev2->SetChannel(channel);
|
||||
|
||||
// Add Zigbee stack with NWK and APS
|
||||
|
||||
ZigbeeHelper zigbeeHelper;
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbeeHelper.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack1 = zigbeeStackContainer.Get(1)->GetObject<ZigbeeStack>();
|
||||
Ptr<ZigbeeStack> zstack2 = zigbeeStackContainer.Get(2)->GetObject<ZigbeeStack>();
|
||||
|
||||
// reprodusable results from random events occurring inside the stack.
|
||||
zstack0->GetNwk()->AssignStreams(0);
|
||||
zstack1->GetNwk()->AssignStreams(10);
|
||||
zstack2->GetNwk()->AssignStreams(20);
|
||||
|
||||
//// Configure Nodes Mobility
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev0Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev0Mobility->SetPosition(Vector(0, 0, 0));
|
||||
dev0->GetPhy()->SetMobility(dev0Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev1Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev1Mobility->SetPosition(Vector(50, 0, 0));
|
||||
dev1->GetPhy()->SetMobility(dev1Mobility);
|
||||
|
||||
Ptr<ConstantPositionMobilityModel> dev2Mobility = CreateObject<ConstantPositionMobilityModel>();
|
||||
dev2Mobility->SetPosition(Vector(0, 50, 0));
|
||||
dev2->GetPhy()->SetMobility(dev2Mobility);
|
||||
|
||||
// Configure APS hooks
|
||||
zstack1->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, this, zstack1));
|
||||
|
||||
zstack2->GetAps()->SetApsdeDataIndicationCallback(
|
||||
MakeBoundCallback(&ApsDataIndication, this, zstack2));
|
||||
|
||||
// Configure NWK hooks
|
||||
// We do not have ZDO, we are required to use the NWK
|
||||
// directly to perform association.
|
||||
zstack1->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, this, zstack1));
|
||||
zstack2->GetNwk()->SetNlmeNetworkDiscoveryConfirmCallback(
|
||||
MakeBoundCallback(&NwkNetworkDiscoveryConfirm, this, zstack2));
|
||||
|
||||
// Configure NWK hooks (for managing Network Joining)
|
||||
|
||||
// 1 - Initiate the Zigbee coordinator on a channel
|
||||
NlmeNetworkFormationRequestParams netFormParams;
|
||||
netFormParams.m_scanChannelList.channelPageCount = 1;
|
||||
netFormParams.m_scanChannelList.channelsField[0] = 0x00001800; // BitMap: channel 11 and 12
|
||||
netFormParams.m_scanDuration = 0;
|
||||
netFormParams.m_superFrameOrder = 15;
|
||||
netFormParams.m_beaconOrder = 15;
|
||||
|
||||
Simulator::ScheduleWithContext(zstack0->GetNode()->GetId(),
|
||||
Seconds(1),
|
||||
&ZigbeeNwk::NlmeNetworkFormationRequest,
|
||||
zstack0->GetNwk(),
|
||||
netFormParams);
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams;
|
||||
netDiscParams.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams.m_scanChannelList.channelsField[0] = 0x00000800; // BitMap: Channels 11
|
||||
netDiscParams.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack1->GetNode()->GetId(),
|
||||
Seconds(2),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack1->GetNwk(),
|
||||
netDiscParams);
|
||||
|
||||
NlmeNetworkDiscoveryRequestParams netDiscParams2;
|
||||
netDiscParams.m_scanChannelList.channelPageCount = 1;
|
||||
netDiscParams.m_scanChannelList.channelsField[0] = 0x00000800; // BitMap: Channels 11~14
|
||||
netDiscParams.m_scanDuration = 2;
|
||||
Simulator::ScheduleWithContext(zstack2->GetNode()->GetId(),
|
||||
Seconds(3),
|
||||
&ZigbeeNwk::NlmeNetworkDiscoveryRequest,
|
||||
zstack2->GetNwk(),
|
||||
netDiscParams2);
|
||||
|
||||
// Send data to a single UCST destination (16-bit address)
|
||||
// The destination address is unknown until compilation, we extract
|
||||
// it from the stack directly.
|
||||
Simulator::Schedule(Seconds(4), &SendDataUcstDst, zstack0, zstack2);
|
||||
|
||||
Simulator::Run();
|
||||
|
||||
// Check that devices actually joined the network and have different 16-bit addresses.
|
||||
|
||||
NS_TEST_EXPECT_MSG_NE(zstack1->GetNwk()->GetNetworkAddress(),
|
||||
Mac16Address("FF:FF"),
|
||||
"The dev 1 was unable to join the network");
|
||||
|
||||
NS_TEST_EXPECT_MSG_NE(zstack2->GetNwk()->GetNetworkAddress(),
|
||||
Mac16Address("FF:FF"),
|
||||
"The dev 1 was unable to join the network");
|
||||
|
||||
NS_TEST_EXPECT_MSG_NE(zstack0->GetNwk()->GetNetworkAddress(),
|
||||
zstack1->GetNwk()->GetNetworkAddress(),
|
||||
"Error, devices 0 and 1 have the same 16 bit MAC address");
|
||||
|
||||
NS_TEST_EXPECT_MSG_NE(zstack1->GetNwk()->GetNetworkAddress(),
|
||||
zstack2->GetNwk()->GetNetworkAddress(),
|
||||
"Error, devices 1 and 2 have the same 16 bit MAC address");
|
||||
|
||||
// Check that the packet was received to the correct preconfigured destination endpoint.
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_dstEndpoint,
|
||||
4,
|
||||
"Packet was not received in the correct destination endpoint");
|
||||
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup zigbee-test
|
||||
* @ingroup tests
|
||||
*
|
||||
* Zigbee APS Data TestSuite
|
||||
*/
|
||||
class ZigbeeApsDataTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
ZigbeeApsDataTestSuite();
|
||||
};
|
||||
|
||||
ZigbeeApsDataTestSuite::ZigbeeApsDataTestSuite()
|
||||
: TestSuite("zigbee-aps-data-test", Type::UNIT)
|
||||
{
|
||||
AddTestCase(new ZigbeeApsDataTestCase, TestCase::Duration::QUICK);
|
||||
}
|
||||
|
||||
static ZigbeeApsDataTestSuite zigbeeApsDataTestSuite; //!< Static variable for test initialization
|
||||
@@ -238,6 +238,7 @@ ZigbeeRreqRetryTestCase::DoRun()
|
||||
//// Configure NWK
|
||||
|
||||
ZigbeeHelper zigbee;
|
||||
zigbee.SetNwkLayerOnly();
|
||||
ZigbeeStackContainer zigbeeStackContainer = zigbee.Install(lrwpanDevices);
|
||||
|
||||
Ptr<ZigbeeStack> zstack0 = zigbeeStackContainer.Get(0)->GetObject<ZigbeeStack>();
|
||||
|
||||
Reference in New Issue
Block a user