• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "nexus_core.hpp"
30 #include "nexus_node.hpp"
31 
32 namespace ot {
33 namespace Nexus {
34 
35 Core *Core::sCore = nullptr;
36 
Core(void)37 Core::Core(void)
38     : mNow(0)
39     , mCurNodeId(0)
40     , mPendingAction(false)
41 {
42     VerifyOrQuit(sCore == nullptr);
43     sCore = this;
44 
45     mNextAlarmTime = mNow.GetDistantFuture();
46 }
47 
~Core(void)48 Core::~Core(void) { sCore = nullptr; }
49 
CreateNode(void)50 Node &Core::CreateNode(void)
51 {
52     Node *node;
53 
54     node = Node::Allocate();
55     VerifyOrQuit(node != nullptr);
56 
57     node->GetInstance().SetId(mCurNodeId++);
58 
59     mNodes.Push(*node);
60 
61     node->GetInstance().AfterInit();
62 
63     return *node;
64 }
65 
UpdateNextAlarmTime(const Alarm & aAlarm)66 void Core::UpdateNextAlarmTime(const Alarm &aAlarm)
67 {
68     if (aAlarm.mScheduled)
69     {
70         mNextAlarmTime = Min(mNextAlarmTime, Max(mNow, aAlarm.mAlarmTime));
71     }
72 }
73 
AdvanceTime(uint32_t aDuration)74 void Core::AdvanceTime(uint32_t aDuration)
75 {
76     TimeMilli targetTime = mNow + aDuration;
77 
78     while (mPendingAction || (mNextAlarmTime <= targetTime))
79     {
80         mNextAlarmTime = mNow.GetDistantFuture();
81         mPendingAction = false;
82 
83         for (Node &node : mNodes)
84         {
85             Process(node);
86             UpdateNextAlarmTime(node.mAlarm);
87         }
88 
89         if (!mPendingAction)
90         {
91             mNow = Min(mNextAlarmTime, targetTime);
92         }
93     }
94 
95     mNow = targetTime;
96 }
97 
Process(Node & aNode)98 void Core::Process(Node &aNode)
99 {
100     otTaskletsProcess(&aNode.GetInstance());
101 
102     ProcessRadio(aNode);
103 
104     if (aNode.mAlarm.ShouldTrigger(mNow))
105     {
106         otPlatAlarmMilliFired(&aNode.GetInstance());
107     }
108 }
109 
ProcessRadio(Node & aNode)110 void Core::ProcessRadio(Node &aNode)
111 {
112     Mac::Address dstAddr;
113     uint16_t     dstPanId;
114     bool         ackRequested;
115     AckMode      ackMode = kNoAck;
116 
117     VerifyOrExit(aNode.mRadio.mState == Radio::kStateTransmit);
118 
119     if (aNode.mRadio.mTxFrame.GetDstAddr(dstAddr) != kErrorNone)
120     {
121         dstAddr.SetNone();
122     }
123 
124     if (aNode.mRadio.mTxFrame.GetDstPanId(dstPanId) != kErrorNone)
125     {
126         dstPanId = Mac::kPanIdBroadcast;
127     }
128 
129     ackRequested = aNode.mRadio.mTxFrame.GetAckRequest();
130 
131     otPlatRadioTxStarted(&aNode.GetInstance(), &aNode.mRadio.mTxFrame);
132 
133     for (Node &rxNode : mNodes)
134     {
135         bool matchesDst;
136 
137         if ((&rxNode == &aNode) || !rxNode.mRadio.CanReceiveOnChannel(aNode.mRadio.mTxFrame.GetChannel()))
138         {
139             continue;
140         }
141 
142         matchesDst = rxNode.mRadio.Matches(dstAddr, dstPanId);
143 
144         if (matchesDst || rxNode.mRadio.mPromiscuous)
145         {
146             // `rxNode` should receive this frame.
147 
148             Radio::Frame rxFrame(aNode.mRadio.mTxFrame);
149 
150             rxFrame.mInfo.mRxInfo.mTimestamp = (mNow.GetValue() * 1000u);
151             rxFrame.mInfo.mRxInfo.mRssi      = kDefaultRxRssi;
152             rxFrame.mInfo.mRxInfo.mLqi       = 0;
153 
154             if (matchesDst && !dstAddr.IsNone() && !dstAddr.IsBroadcast() && ackRequested)
155             {
156                 Mac::Address srcAddr;
157 
158                 ackMode = kSendAckNoFramePending;
159 
160                 if ((aNode.mRadio.mTxFrame.GetSrcAddr(srcAddr) == kErrorNone) &&
161                     rxNode.mRadio.HasFramePendingFor(srcAddr))
162                 {
163                     ackMode                                      = kSendAckFramePending;
164                     rxFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
165                 }
166             }
167 
168             otPlatRadioReceiveDone(&rxNode.GetInstance(), &rxFrame, kErrorNone);
169         }
170 
171         if (ackMode != kNoAck)
172         {
173             // No need to go through rest of `mNodes`
174             // if already acked by a node.
175             break;
176         }
177     }
178 
179     aNode.mRadio.mChannel = aNode.mRadio.mTxFrame.mChannel;
180     aNode.mRadio.mState   = Radio::kStateReceive;
181 
182     if (ackMode != kNoAck)
183     {
184         Mac::TxFrame ackFrame;
185         uint8_t      ackPsdu[Mac::Frame::kImmAckLength];
186 
187         ClearAllBytes(ackFrame);
188         ackFrame.mPsdu = ackPsdu;
189 
190         ackFrame.GenerateImmAck(
191             static_cast<const Mac::RxFrame &>(static_cast<const Mac::Frame &>(aNode.mRadio.mTxFrame)),
192             (ackMode == kSendAckFramePending));
193 
194         otPlatRadioTxDone(&aNode.GetInstance(), &aNode.mRadio.mTxFrame, &ackFrame, kErrorNone);
195     }
196     else
197     {
198         otPlatRadioTxDone(&aNode.GetInstance(), &aNode.mRadio.mTxFrame, nullptr,
199                           ackRequested ? kErrorNoAck : kErrorNone);
200     }
201 
202 exit:
203     return;
204 }
205 
206 } // namespace Nexus
207 } // namespace ot
208