DESERT 3.5.1
Loading...
Searching...
No Matches
uwtokenbus.cpp
Go to the documentation of this file.
1//
2// Copyright (c) 2021 Regents of the SIGNET lab, University of Padova.
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
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution.
13// 3. Neither the name of the University of Padova (SIGNET lab) nor the
14// names of its contributors may be used to endorse or promote products
15// derived from this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
39#include "uwtokenbus.h"
40#include "uwtokenbus_hdr.h"
41#include <iostream>
42#include <mac.h>
43#include <uwcbr-module.h>
44#include <tclcl.h>
45
46extern packet_t PT_UWTOKENBUS;
47
48//define a macro to print debug messages
49#define DEBUG(level,text) {if (debug >= level) {std::cout << NOW << " UwTokenBus(" << node_id << "): " << text << std::endl;}}
50
54static class UwTokenBusModuleClass : public TclClass
55{
56
57public:
62 : TclClass("Module/UW/TOKENBUS")
63 {
64 }
69 TclObject *
70 create(int argc, const char *const * argv)
71 {
72 return (new UwTokenBus());
73 }
74
76
78{
79 ((UwTokenBus *)module)->expireBusIdle();
80}
81
83{
84 ((UwTokenBus *)module)->expireTokenPass();
85}
86
87//initializing static variables
90int UwTokenBus::count_bus_idle_exp = -1; //start from -1 because initRing will do an increment on startup
91
92//default constructor
94 : MMac(),
96 n_nodes(0),
101 token_rx_time(0),
104 got_token(false),
105 slot_time(0),
108 token_pass_timer(this),
109 bus_idle_timer(this),
113 debug(100),
114 drop_old_(0),
116{
117 bind("n_nodes_", (int *)&n_nodes);
118 bind("slot_time_", (double *)&slot_time);
119 bind("queue_size_", (int *)&max_queue_size);
120 bind("debug_tb", (int *)&debug);
121 bind("debug_", (int *)&debug_);
122 bind("max_token_hold_time_", (double *)&max_token_hold_time);
123 bind("min_token_hold_time_", (double *)&min_token_hold_time);
124 bind("drop_old_", (int *)&drop_old_);
125 bind("checkPriority_", (int *)&checkPriority);
126 bind("mac2phy_delay_", (double *)&mac2phy_delay_);
127
128 if (slot_time < 0)
129 {
130 DEBUG(1," UwTokenBus() not valid slot_time_ < 0!! set to 1 by default ")
131 slot_time = 1;
132 }
133 if (n_nodes < 0)
134 {
135 DEBUG(1," UwTokenBus() not valid token_pass_timeout_ < 0!! set to 1 by default ")
137 }
138 if (max_queue_size < 0)
139 {
140 DEBUG(1," UwTokenBus() not valid queue_size_ < 0!! set to 1000 by default ")
141 max_queue_size = 1000;
142 }
143 if (max_token_hold_time < 0)
144 {
145 DEBUG(1," UwTokenBus() not valid max_token_hold_time_ < 0!! set to 10 by default ")
147 }
148 if (min_token_hold_time < 0)
149 {
150 DEBUG(1," UwTokenBus() not valid min_token_hold_time_ < 0!! set to 1 by default ")
152 }
153 if (drop_old_ == 1 && checkPriority == 1)
154 {
155 DEBUG(1," UwTokenBus() drop_old_ and checkPriority cannot be set both to 1!! "
156 << "checkPriority set to 0 by default ")
157 checkPriority = 0;
158 }
159 if (mac2phy_delay_ <= 0)
160 {
161 DEBUG(1,"mac2phy_delay_ < 0!! set to 1e-9 by default")
162 mac2phy_delay_ = 1e-9;
163 }
164
167 initRing();
168}
169
173
175 DEBUG(4," TOKEN PASS timer expired" )
176 got_token = true;
179}
180
182 DEBUG(1," BUS IDLE timer expired" )
183 got_token = true;
184 token_rx_time = NOW;
188 txData();
189}
190
191
193 last_token_id_owned = int(-n_nodes + node_id); //just to have the first tokenID round starting at 0 instead of n_nodes
195}
196
198{
199 incrUpperDataRx();
200 DEBUG(10, " recv packet from upperLayer: " << p << " queue size: " << buffer.size()+1)
201 bool is_cbr = (((hdr_cmn*)HDR_CMN(p))->ptype() == PT_UWCBR);
202 initPkt(p);
203 if (buffer.size() < (size_t) max_queue_size)
204 {
205 if (is_cbr && checkPriority)
206 {
207 hdr_uwcbr *uwcbrh = HDR_UWCBR(p);
208 if (uwcbrh->priority() == 0)
209 {
210 buffer.push_back(p);
211 }
212 else
213 {
214 buffer.push_front(p);
215 }
216 }
217 else buffer.push_back(p);
218 }
219 else
220 {
221 incrDiscardedPktsTx();
222 DEBUG(1," recvFromUpperLayers() dropping pkt due to buffer full ")
223 if (drop_old_)
224 {
225 Packet *p_old = buffer.front();
226 buffer.pop_front();
227 Packet::free(p_old);
228 buffer.push_back(p);
229 }
230 else if (is_cbr && checkPriority)
231 {
232 hdr_uwcbr *uwcbrh = HDR_UWCBR(p);
233 if (uwcbrh->priority() == 1)
234 {
235 Packet *p_old = buffer.back();
236 buffer.pop_back();
237 Packet::free(p_old);
238 buffer.push_front(p);
239 }
240 }
241 else
242 {Packet::free(p);}
243 }
244 if (got_token)
245 txData();
246}
247
248int UwTokenBus::normId(int id) const
249{
250 if (id > TOKENIDMAX)
251 return ((id % TOKENIDMAX) + (TOKENIDMAX % n_nodes));
252 else
253 return id;
254}
255
256int UwTokenBus::nextId(int id) const
257{
258 if (id + 1 > TOKENIDMAX) //OVERFLOW
259 return (id % n_nodes) + 1;
260 return id + 1;
261}
262
263int UwTokenBus::nextIdOwned(int id) const
264{
265 if (id + n_nodes > TOKENIDMAX) //OVERFLOW
266 return node_id;
267 else
268 return id + n_nodes;
269}
270
272{
273 if (got_token && rtx_status == IDLE)
274 {
275 if (buffer.size() > 0)
276 {
277 Packet *p = buffer.front();
278 if (NOW - token_rx_time + Mac2PhyTxDuration(p) < max_token_hold_time) //if true I have time to send this packet
279 {
280 DEBUG(10," sending a data packet from queue: " << p)
281 token_pass_timer.force_cancel();
282 buffer.pop_front();
283 incrDataPktsTx();
284 (HDR_TOKENBUS(p)->tokenId()) = last_token_id_owned;
286 }
287 else
288 {// max token hold timeout is expired
289 DEBUG(3, " UwTokenBus ID " << node_id
290 << " max token hold timeout expired with " << buffer.size()
291 << " packets still in queue")
294 }
295 }
296 else {
297 if (NOW - token_rx_time >= min_token_hold_time) {
300 }
301 else
303 }
304 }
305 else
306 {
307 if (!got_token)
308 DEBUG(4," Waiting the token to start tx")
309 else if(rtx_status == TRANSMITTING)
310 DEBUG(4," Wait earlier packet expires to send the current one")
311 else if(rtx_status == RECEIVING)
312 DEBUG(1," txData() called while in RX status ")
313 }
314}
315
317{
319 DEBUG(1," called Mac2PhyStartTx() while already transmitting ")
320 if (rtx_status == RECEIVING)
321 DEBUG(1," called Mac2PhyStartTx() while receiving ")
322 bus_idle_timer.force_cancel(); //will resched in Phy2MacEndTx
324 hdr_cmn *ch = HDR_CMN(p);
325 hdr_mac *mach = HDR_MAC(p);
326 hdr_tokenbus *tbh = HDR_TOKENBUS(p);
328 DEBUG(10, " start tx of pkt " << p << " of type " << ch->ptype() << " size: " << ch->size() << " tx duration: " << Mac2PhyTxDuration(p)
329 << " tokenid: " << last_token_id_heard << " to mac: " << mach->macDA());
330 MMac::Mac2PhyStartTx(p);
331}
332
333void UwTokenBus::Phy2MacEndTx(const Packet *p)
334{
335 //DEBUG(4, " ended tx of pkt: " << p)
338 if (got_token)
339 txData();
340}
341
342void UwTokenBus::Phy2MacStartRx(const Packet *p)
343{
344 //DEBUG(4," Phy2MacStartRx() packet: " << p)
346 DEBUG(1," Phy2MacStartRx() while in TX status")
347 else if (rtx_status == RECEIVING)
348 DEBUG(1," Phy2MacStartRx() while already in RX status")
349 else if (rtx_status == IDLE)
351}
352
353bool UwTokenBus::validToken(Packet *p) const
354{
355 hdr_tokenbus *tbh = HDR_TOKENBUS(p);
356 int id = tbh->tokenId();
357 if (id >= last_token_id_heard
358 || (id <= n_nodes && (last_token_id_heard + n_nodes > TOKENIDMAX))) //UINT16 OVERFLOW
359 return true;
360 else
361 DEBUG(1," received a token with invalid token id: " << id)
362 return false;
363}
364
366{
367 hdr_cmn *ch = HDR_CMN(p);
368 hdr_mac *mach = HDR_MAC(p);
369 int dest_mac = mach->macDA();
370 hdr_tokenbus *tbh = HDR_TOKENBUS(p);
371 int pkt_token_id = tbh->tokenId();
372 int pkt_node_id = (pkt_token_id % n_nodes); //find which node the token is meant to
373
375 {
377
378 if (ch->error())
379 {
380 /* in case of errors I assume the token_id in the header might be corrupted
381 * so I won't consider it for rescheduling the timers
382 */
383 DEBUG(1," Phy2MacEndRx() dropping corrupted pkt ")
384 incrErrorPktsRx();
385 Packet::free(p);
386 }
387 else
388 {
389 if (validToken(p))
390 {
391 token_pass_timer.force_cancel();
392 bus_idle_timer.force_cancel();
393 last_token_id_heard = pkt_token_id;
394
395 if (pkt_node_id == node_id)
396 {
397 got_token = true;
398 last_token_id_owned = pkt_token_id;
399 token_rx_time = NOW;
401 DEBUG(3," Received the token ")
402 txData();
403 }
404 else if (pkt_node_id < node_id)
405 { //pkt from previous node in the ring
406 bus_idle_timer.resched((3 * (node_id - pkt_node_id + 1) * bus_idle_timeout));
407 }
408 else //consider ring turnaround
409 bus_idle_timer.resched((3 * (n_nodes - pkt_node_id + node_id + 1) * bus_idle_timeout));
410 }
411 else {
412 DEBUG(1," received a pkt with invalid token id ")
413 }
414
415 if (ch->ptype() == PT_UWTOKENBUS)
416 {
417 Packet::free(p);
418 incrCtrlPktsRx();
419 }
420 else if ((dest_mac != addr) && (dest_mac != BCAST_ADDR))
421 {
422 Packet::free(p);
423 incrXDataPktsRx();
424 }
425 else
426 {
427 sendUp(p);
428 incrDataPktsRx();
429 }
430 }
431 }
432 else
433 {
434 DEBUG(1," discard packet rx while tx; pkt token_id : " << pkt_token_id << " macSA: " << mach->macSA() << " macDA: " << mach->macDA())
435 Packet::free(p); //assume the packet got corrupted in collision with tx packet
436 }
437}
438
439void UwTokenBus::initPkt(Packet *p)
440{
441 hdr_cmn *ch = HDR_CMN(p);
442 hdr_tokenbus *tbh = HDR_TOKENBUS(p);
443 (ch->size()) += tbh->getSize();
444}
445
446void UwTokenBus::sendToken(int token_id)
447{
448 if(!got_token) {
449 DEBUG(1," attempt to send token without owning it; tokenid: " << token_id)
450 return;
451 }
452 //build the token packet
453 Packet *p = Packet::alloc();
454 hdr_cmn *ch = HDR_CMN(p);
455 hdr_mac *mach = HDR_MAC(p);
456 hdr_tokenbus *tbh = HDR_TOKENBUS(p);
457 (ch->size()) += tbh->getSize();
458 ch->ptype() = PT_UWTOKENBUS;
459 mach->set(MF_CONTROL, addr, BCAST_ADDR);
460 mach->macDA() = BCAST_ADDR;
461 tbh->tokenId() = token_id;
462 got_token = false;
463 DEBUG(3," pass TOKEN to node: " << (token_id % n_nodes) << " with tokenid: " << token_id)
464 incrCtrlPktsTx();
466}
467
468
469int UwTokenBus::command(int argc, const char *const *argv)
470{
471 Tcl &tcl = Tcl::instance();
472 if (argc == 2)
473 {
474 if (strcasecmp(argv[1], "get_buffer_size") == 0)
475 {
476 tcl.resultf("%d", buffer.size());
477 return TCL_OK;
478 }
479 else if (strcasecmp(argv[1], "get_count_token_resend") == 0)
480 {
481 tcl.resultf("%d", count_token_resend);
482 return TCL_OK;
483 }
484 else if (strcasecmp(argv[1], "get_count_token_regen") == 0)
485 {
486 tcl.resultf("%d", count_token_regen);
487 return TCL_OK;
488 }
489 else if (strcasecmp(argv[1], "get_count_token_invalid") == 0)
490 {
491 tcl.resultf("%d", count_token_invalid);
492 return TCL_OK;
493 }
494 else if (strcasecmp(argv[1], "get_bus_idle_exp") == 0)
495 {
496 tcl.resultf("%d", count_bus_idle_exp);
497 return TCL_OK;
498 }
499 else if (strcasecmp(argv[1], "get_token_pass_exp") == 0)
500 {
501 tcl.resultf("%d", count_token_pass_exp);
502 return TCL_OK;
503 }
504 }
505 else if (argc == 3)
506 {
507 if (strcasecmp(argv[1], "set_slot_time") == 0)
508 {
509 slot_time = atof(argv[2]);
510 return TCL_OK;
511 }
512 else if (strcasecmp(argv[1], "set_token_pass_timeout") == 0)
513 {
514 token_pass_timeout = atof(argv[2]);
515 return TCL_OK;
516 }
517 else if (strcasecmp(argv[1], "set_bus_idle_timeout") == 0)
518 {
519 bus_idle_timeout = atof(argv[2]);
520 return TCL_OK;
521 }
522 else if (strcasecmp(argv[1], "setMacAddr") == 0)
523 {
524 addr = atoi(argv[2]);
525 DEBUG(4, " MAC address: " << addr)
526 return TCL_OK;
527 }
528 }
529 return MMac::command(argc, argv);
530}
Class that represent the binding of the protocol with tcl.
UwTokenBusModuleClass()
Constructor of the UwTokenBusModule class.
TclObject * create(int argc, const char *const *argv)
Creates the TCL object needed for the tcl language interpretation.
virtual void expire(Event *e)
Method call when the timer expire.
virtual void expire(Event *e)
Method call when the timer expire.
Class that represents a TokenBus Node.
Definition uwtokenbus.h:52
UWTokenBus_STATUS rtx_status
Definition uwtokenbus.h:239
int count_token_invalid
node count of invalid received token
Definition uwtokenbus.h:254
double token_pass_timeout
timeout for the namesake timer for token retransmission attempt, should be 2*slot_time+min_token_hold...
Definition uwtokenbus.h:242
double min_token_hold_time
if the node has en empty queue when it receive the token, it waits this time before passing the token
Definition uwtokenbus.h:235
virtual void initRing()
Initialize the network and generates the first token.
virtual void expireBusIdle()
called when bus_idle_timer expires
int debug
Debug variable: 0 for no info.
Definition uwtokenbus.h:256
double slot_time
max travel time between any pair of nodes, used as time unit for some of the timers timeouts
Definition uwtokenbus.h:241
virtual void Phy2MacEndTx(const Packet *p) override
Method called when the Mac Layer finish to transmit a Packet.
virtual int nextIdOwned(int id) const
static int count_token_pass_exp
count token pass timer expirations
Definition uwtokenbus.h:263
virtual ~UwTokenBus()
Destructor of the TokenBus class.
TimerBusIdle bus_idle_timer
token_pass_timer is scheduled when a node pass the token, it's cancelled when activity from the follo...
Definition uwtokenbus.h:247
int n_nodes
number of nodes in the ring
Definition uwtokenbus.h:230
virtual int normId(int id) const
virtual void recvFromUpperLayers(Packet *p) override
Receive the packet from the upper layer (e.g.
virtual void Mac2PhyStartTx(Packet *p)
Method called when the Mac Layer start to transmit a Packet.
virtual int nextId(int id) const
static int count_nodes
counter of the instantiated nodes, used for assigning node ids in default contructor
Definition uwtokenbus.h:262
virtual int command(int argc, const char *const *argv) override
TCL command interpreter.
double bus_idle_timeout
base timeout for the namesake timer should be (slot_time+max_token_hold_time)
Definition uwtokenbus.h:243
double token_rx_time
time of token reception
Definition uwtokenbus.h:236
virtual void Phy2MacStartRx(const Packet *p) override
Method called when the Phy Layer start to receive a Packet.
std::deque< Packet * > buffer
outgoing packets dequeue
Definition uwtokenbus.h:238
TimerTokenPass token_pass_timer
Definition uwtokenbus.h:244
int last_token_id_heard
last token id heard on the bus
Definition uwtokenbus.h:231
int count_token_regen
node count of token regeneration
Definition uwtokenbus.h:253
int drop_old_
flag to set the drop packet policy in case of buffer overflow: if 0 (default) drops the new packet,...
Definition uwtokenbus.h:257
bool got_token
set if node is currently holding the token
Definition uwtokenbus.h:240
virtual void Phy2MacEndRx(Packet *p) override
Method called when the Phy Layer finish to receive a Packet.
int last_token_id_owned
last token id owned
Definition uwtokenbus.h:232
int max_queue_size
max packets in the queue
Definition uwtokenbus.h:237
virtual void initPkt(Packet *p)
Method called to add the MAC header size.
virtual void sendToken(int next_id)
Passes the token to the next node.
int node_id
id of the node (0 to n_nodes-1)
Definition uwtokenbus.h:229
int checkPriority
flag to set to 1 if UWCBR module uses packets with priority, set to 0 otherwise.
Definition uwtokenbus.h:259
virtual void txData()
Starts transmitting the packets from the queue.
int count_token_resend
bus_idle_timer is rescheduled everytime a new token_id is heard on the bus: the first time node n hea...
Definition uwtokenbus.h:252
virtual bool validToken(Packet *p) const
Assert if the received token id is valid, i.e it follows the monotonic progression taking in account ...
virtual void expireTokenPass()
called when token_pass_timer expires
static int count_bus_idle_exp
count bus idle timer expirations
Definition uwtokenbus.h:264
UwTokenBus()
Default constructor of the TokenBus class.
double max_token_hold_time
max token holding time
Definition uwtokenbus.h:234
Header of the token bus protocol.
size_t getSize() const
Returns the size of this header.
tokenid_t & tokenId()
Returns a reference to the token_id variable.
hdr_uwcbr describes UWCBR packets.
char & priority()
Reference to the priority_ variable.
Provides the UWCBR packets header description and the definition of the class UWCBR.
#define HDR_UWCBR(p)
UwTokenBusModuleClass class_module_uwtokenbus
#define DEBUG(level, text)
Provides the definition of the class UwTokenBus.
Common structures and variables in the protocol.
#define HDR_TOKENBUS(p)
alias defined to access the TOKEN BUS HEADER
constexpr size_t TOKENIDMAX