TTEthernet Model for INET Framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
TTEOutput.cc
Go to the documentation of this file.
1 #include "TTEOutput.h"
2 
3 #include <algorithm>
4 
5 #include <Buffer.h>
6 #include <RCBuffer.h>
7 #include <PCFrame_m.h>
8 #include <TTEScheduler.h>
9 #include <TTBufferEmpty_m.h>
10 
11 #include <HelperFunctions.h>
12 
13 using namespace TTEthernetModel;
14 
16 
17 simsignal_t TTEOutput::ttQueueLengthSignal = SIMSIGNAL_NULL;
18 simsignal_t TTEOutput::beQueueLengthSignal = SIMSIGNAL_NULL;
19 simsignal_t TTEOutput::pcfQueueLengthSignal = SIMSIGNAL_NULL;
20 
22 {
23  framesRequested = 0;
24  ttBuffersPos = 0;
25 
26  ttQueue.setName("TT Messages");
27  for (unsigned int i = 0; i < NUM_RC_PRIORITIES; i++)
28  {
29  char strBuf[64];
30  snprintf(strBuf,64,"RC Priority %d Messages", i);
31  rcQueue[i].setName(strBuf);
32  }
33  beQueue.setName("BE Messages");
34  pcfQueue.setName("PCF Messages");
35 }
36 
38 {
39  ttQueue.clear();
40  for (unsigned int i = 0; i < NUM_RC_PRIORITIES; i++)
41  {
42  rcQueue[i].clear();
43  }
44  beQueue.clear();
45  pcfQueue.clear();
46 }
47 
49 {
50  cGate *physOutGate = getParentModule()->getSubmodule("mac")->gate("phys$o");
51  outChannel = physOutGate->findTransmissionChannel();
52 
53  ttQueueLengthSignal = registerSignal("ttQueueLength");
54  beQueueLengthSignal = registerSignal("beQueueLength");
55  pcfQueueLengthSignal = registerSignal("pcfQueueLength");
56 }
57 
58 void TTEOutput::addListener(IPassiveQueueListener *listener){
59  std::list<IPassiveQueueListener*>::iterator it = find(listeners.begin(), listeners.end(), listener);
60  if (it == listeners.end())
61  listeners.push_back(listener);
62 }
63 void TTEOutput::removeListener(IPassiveQueueListener *listener){
64  std::list<IPassiveQueueListener*>::iterator it = find(listeners.begin(), listeners.end(), listener);
65  if (it != listeners.end())
66  listeners.erase(it);
67 }
68 
70 {
71  for (std::list<IPassiveQueueListener*>::iterator it = listeners.begin(); it != listeners.end(); ++it)
72  (*it)->packetEnqueued(this);
73 }
74 
75 void TTEOutput::handleMessage(cMessage *msg)
76 {
77  if (msg->arrivedOn("PCFin"))
78  {
79  if (framesRequested)
80  {
82  PCFrame *pcf = dynamic_cast<PCFrame*>(msg);
83  if(pcf){
85  }
86  send(msg, gateBaseId("out"));
87 
88  }
89  else
90  {
91  pcfQueue.insert(msg);
93  emit(pcfQueueLengthSignal, pcfQueue.length());
94  }
95  }
96  else if (msg->arrivedOn("TTin"))
97  {
98  if(ttBuffers.size()>0){
99  ttBuffersPos = ((ttBuffersPos + 1) % ttBuffers.size());
100  }
101 
102  //If we have an empty message allow other frame to be sent
103  if (dynamic_cast<TTBufferEmpty *> (msg))
104  {
105  if (framesRequested)
106  {
107  framesRequested--;
108  requestPacket();
109  }
110  delete msg;
111  }
112  //Else send frame
113  else
114  {
115  if (framesRequested)
116  {
117  framesRequested--;
118  send(msg, gateBaseId("out"));
119  }
120  else
121  {
122  EV << "There might be a configuration issue (TTBuffer not registered in Output module), or shuffling was enabled for a TTBuffer or a TTFrame was delayed by a PCF" << endl;
123  ttQueue.insert(msg);
124  notifyListeners();
125  emit(ttQueueLengthSignal, ttQueue.length());
126  }
127  }
128  }
129  else if (msg->arrivedOn("RCin"))
130  {
131  if (framesRequested && isTransmissionAllowed((EtherFrame*) msg))
132  {
133  framesRequested--;
134 
135  //Reset Bag
136  RCBuffer *rcBuffer = dynamic_cast<RCBuffer*> (msg->getSenderModule());
137  if (rcBuffer)
138  rcBuffer->resetBag();
139  PCFrame *pcf = dynamic_cast<PCFrame*> (msg);
140  if(pcf){
141  setTransparentClock(pcf);
142  }
143  send(msg, gateBaseId("out"));
144  }
145  else
146  {
147  int priority = msg->getSenderModule()->par("priority").longValue();
148  if (priority > 0 && priority < NUM_RC_PRIORITIES)
149  {
150  rcQueue[priority].insert(msg);
151  notifyListeners();
152  }
153  else
154  {
155  rcQueue[0].insert(msg);
156  notifyListeners();
157  ev << "Priority missing!" << endl;
158  }
159  }
160  }
161  //Frames arrived on in are best-effort frames
162  else if (msg->arrivedOn("in"))
163  {
164  // If there are framesRequested the MAC layer is currently idle
165  if (framesRequested && isTransmissionAllowed((EtherFrame*) msg))
166  {
167  framesRequested--;
168  send(msg, gateBaseId("out"));
169  }
170  else
171  {
172  beQueue.insert(msg);
173  notifyListeners();
174  emit(beQueueLengthSignal, beQueue.length());
175  }
176  }
177 }
178 
180 {
181  Enter_Method("registerTTBuffer(%s)", ttBuffer->getName());
182  uint32_t sendWindowStart = ttBuffer->par("sendWindowStart");
183  for (std::vector<TTBuffer*>::iterator buffer = ttBuffers.begin(); buffer != ttBuffers.end();)
184  {
185  uint32_t buf_sendWindowStart = (*buffer)->par("sendWindowStart").longValue();
186  if (buffer == ttBuffers.end() || buf_sendWindowStart > sendWindowStart)
187  {
188  ttBuffers.insert(buffer, ttBuffer);
189  //Now doublecheck that the schedule is not overlapping for this port
190  for (std::vector<TTBuffer*>::iterator buffer2 = ttBuffers.begin(); buffer2 != ttBuffers.end();)
191  {
192  Buffer *tmpBuffer = *buffer2;
193  ++buffer2;
194  if (buffer2 != ttBuffers.end() && (tmpBuffer->par("sendWindowEnd").longValue() > (*buffer2)->par(
195  "sendWindowStart").longValue()))
196  {
197  opp_error("Port cannot be scheduled due to overlapping schedules: %s (End: %d) and %s (Start: %d)", tmpBuffer->getName(),
198  tmpBuffer->par("sendWindowEnd").longValue(),
199  (*buffer2)->getName(),
200  (*buffer2)->par("sendWindowStart").longValue());
201  }
202  }
203  return;
204  }
205  ++buffer;
206  }
207  //This should only happen if buffer was empty
208  ttBuffers.push_back(ttBuffer);
209 }
210 
211 void TTEOutput::handleParameterChange(const char* parname){
212  ttBuffers.clear();
213  if(ev.isGUI()){
214  //TODO check why this does not work
215  //getDisplayString().setTagArg("i2", 0, "");
216  //getDisplayString().setTagArg("tt", 0, "");
217  }
218  std::string ttBuffersString = par("tt_buffers").stdstringValue();
219  std::vector<std::string> ttBufferPaths;
220  split(ttBuffersString,',',ttBufferPaths);
221  for(std::vector<std::string>::iterator ttBufferPath = ttBufferPaths.begin();
222  ttBufferPath!=ttBufferPaths.end();ttBufferPath++){
223  cModule* module = simulation.getModuleByPath((*ttBufferPath).c_str());
224  if(module){
225  TTBuffer *ttBuffer = dynamic_cast<TTBuffer*> (module);
226  if(ttBuffer){
227  registerTTBuffer(ttBuffer);
228  }
229  }
230  else{
231  if(ev.isGUI()){
232  ev<<"Configuration problem: Module "<<(*ttBufferPath)<<" could not be resolved or is no TT-Buffer!"<<endl;
233  getDisplayString().setTagArg("i2", 0, "status/excl3");
234  getDisplayString().setTagArg("tt", 0, "WARNING: Configuration Problem outgoing TT-Buffer!");
235  }
236  }
237  }
238 }
239 
241 {
242  Enter_Method("requestPacket()");
243  //Feed the MAC layer with the next frame
244  framesRequested++;
245 
246  //TTFrames
247  if (!ttQueue.isEmpty())
248  {
249  framesRequested--;
250  cMessage *msg = (cMessage*) ttQueue.pop();
251  emit(ttQueueLengthSignal, ttQueue.length());
252 
253  //TODO Update buffers:
254  if(ttBuffers.size()>0){
255  ttBuffersPos = (ttBuffersPos + 1) % ttBuffers.size();
256  }
257 
258  send(msg, gateBaseId("out"));
259  return;
260  }
261  //RCFrames
262  for (unsigned int i = 0; i < NUM_RC_PRIORITIES; i++)
263  {
264  if (!rcQueue[i].isEmpty() && isTransmissionAllowed((EtherFrame*) rcQueue[i].front()))
265  {
266  framesRequested--;
267  EtherFrame *message = (EtherFrame*) rcQueue[i].pop();
268  //Reset Bag
269  RCBuffer *rcBuffer = dynamic_cast<RCBuffer*> (message->getSenderModule());
270  if (rcBuffer)
271  rcBuffer->resetBag();
272 
273  PCFrame *pcf = dynamic_cast<PCFrame*> (message);
274  if(pcf){
275  setTransparentClock(pcf);
276  }
277  send(message, gateBaseId("out"));
278  return;
279  }
280  }
281  //BEFrames
282  if (!beQueue.isEmpty() && isTransmissionAllowed((EtherFrame*) beQueue.front()))
283  {
284  framesRequested--;
285  cMessage* message = (cMessage*) beQueue.pop();
286  send(message, gateBaseId("out"));
287  emit(beQueueLengthSignal, beQueue.length());
288  return;
289  }
290 }
291 
292 bool TTEOutput::isTransmissionAllowed(EtherFrame *message)
293 {
294  if (!outChannel)
295  {
296  return false;
297  }
298  //If there are no ttBuffers everything is fine
299  if (ttBuffers.size() == 0)
300  {
301  return true;
302  }
303  TTEScheduler *scheduler = (TTEScheduler*) getParentModule()->getParentModule()->getSubmodule("tteScheduler");
304  //SimTime sendTime = (message->getBitLength()+INTERFRAME_GAP_BITS)/txRate;
305  SimTime sendTime = outChannel->calculateDuration(message);
306  //Don't know if that is right, but it works!
307  sendTime += (INTERFRAME_GAP_BITS + ((PREAMBLE_BYTES + SFD_BYTES) * 8)) / outChannel->getNominalDatarate();
308  unsigned long sendTicks = ceil((sendTime / scheduler->par("tick")).dbl());
309  unsigned long startTicks = ttBuffers[ttBuffersPos]->par("sendWindowStart").longValue();
310  unsigned long endTicks = ttBuffers[ttBuffersPos]->par("sendWindowEnd").longValue();
311 
312  //Send Window Start is in next cycle
313  if (scheduler->getTicks() > startTicks)
314  {
315  long cycleTicks = scheduler->par("cycle_ticks").longValue();
316  startTicks += cycleTicks;
317  endTicks += cycleTicks;
318  }
319  //Send Window End is in next cycle
320  else if (scheduler->getTicks() > endTicks)
321  {
322  endTicks += scheduler->par("cycle_ticks").longValue();
323  }
324 
325  //TODO: Perhaps more complex calculations needed?
326  if ((scheduler->getTicks() + sendTicks) >= startTicks)
327  {
328  ev << "transmission not allowed!" << endl;
329  return false;
330  }
331  return true;
332 }
333 
335  unsigned long transparentClock = pcf->getTransparent_clock();
336 
337  //Add static delay for this port
338  transparentClock+=secondsToTransparentClock(getParentModule()->par("static_tx_delay").doubleValue());
339 
340  //Add dynamic delay for the device
341  cArray parlist = pcf->getParList();
342  unsigned long start = -1;
343  for(int i=0;i<parlist.size();i++){
344  cMsgPar *parameter = dynamic_cast<cMsgPar*>(parlist.get(i));
345  if(parameter){
346  if(strncmp(parameter->getName(),"received_total",15)==0 || strncmp(parameter->getName(),"created_total",15)==0){
347  start = parameter->longValue();
348  }
349  }
350  }
351  if(start >= 0){
352  TTEScheduler* scheduler = ((TTEScheduler*)getParentModule()->getParentModule()->getSubmodule("tteScheduler"));
353  transparentClock+=ticksToTransparentClock((scheduler->getTotalTicks()-start),scheduler->par("tick").doubleValue());
354  }
355 
356  //Set new transparent clock
357  pcf->setTransparent_clock(transparentClock);
358 }
359 
361 {
362  return framesRequested;
363 }
364 
366 {
367  bool empty = true;
368  empty &= ttQueue.isEmpty();
369  for (unsigned int i = 0; i < NUM_RC_PRIORITIES; i++)
370  {
371  empty &= rcQueue[i].isEmpty();
372  }
373  empty &= beQueue.isEmpty();
374  return empty;
375 }
377 {
378  beQueue.clear();
379  for (unsigned int i = 0; i < NUM_RC_PRIORITIES; i++)
380  {
381  rcQueue[i].clear();
382  }
383  ttQueue.clear();
384  framesRequested = 0;
385 }
386