knx
ETS configurable knx-stack
network_layer_coupler.cpp
Go to the documentation of this file.
2 #include "data_link_layer.h"
3 #include "device_object.h"
4 #include "router_object.h"
5 #include "tpdu.h"
6 #include "cemi_frame.h"
7 #include "bits.h"
8 
10  TransportLayer& layer) :
11  NetworkLayer(deviceObj, layer),
12  _netLayerEntities { {*this, kPrimaryIfIndex}, {*this, kSecondaryIfIndex} }
13 {
14  _currentAddress = deviceObj.individualAddress();
15  evaluateCouplerType();
16 }
17 
19 {
20  return _netLayerEntities[0];
21 }
22 
24 {
25  return _netLayerEntities[1];
26 }
27 
29 {
30  _rtObjPrimary = &rtObj;
31  _rtObjSecondary = nullptr;
32 }
33 
35 {
36  _rtObjPrimary = &rtObjPrimary;
37 }
38 
40 {
41  _rtObjSecondary = &rtObjSecondary;
42 }
43 
44 void NetworkLayerCoupler::evaluateCouplerType()
45 {
46  // Check coupler mode
47  if ((_deviceObj.individualAddress() & 0x00FF) == 0x00)
48  {
49  // Device is a router
50  // Check if line coupler or backbone coupler
51  if ((_deviceObj.individualAddress() & 0x0F00) == 0x0)
52  {
53  // Device is a backbone coupler -> individual address: x.0.0
54  _couplerType = BackboneCoupler;
55  }
56  else
57  {
58  // Device is a line coupler -> individual address: x.y.0
59  _couplerType = LineCoupler;
60  }
61  }
62  else
63  {
64  // Device is not a router, check if TP1 bridge or TP1 repeater
65  /*
66  if (PID_L2_COUPLER_TYPE.BIT0 == 0)
67  {
68  //then Device is TP1 Bridge
69  couplerType = TP1Bridge;
70  }
71  else
72  {
73  // Device is TP1 Repeater
74  couplerType = TP1Repeater;
75  }
76  */
77  }
78 }
79 
80 bool NetworkLayerCoupler::isGroupAddressInFilterTable(uint16_t groupAddress)
81 {
82  if (_rtObjSecondary == nullptr)
83  return (_rtObjPrimary != nullptr) ? _rtObjPrimary->isGroupAddressInFilterTable(groupAddress) : false;
84  else
85  {
86  return _rtObjSecondary->isGroupAddressInFilterTable(groupAddress);
87  }
88 }
89 
90 bool NetworkLayerCoupler::isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex)
91 {
92  uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
93  uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible.
94  Property* prop_lcgrpconfig;
95  Property* prop_lcconfig;
96 
97  if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP)
98  {
99  prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG);
100  prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG);
101  }
102  else // direction Sec -> Prim ( e.g. TP -> IP)
103  {
104  prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG);
105  prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG);
106  }
107 
108  if (prop_lcgrpconfig)
109  prop_lcgrpconfig->read(lcgrpconfig);
110 
111  if (prop_lcconfig)
112  prop_lcconfig->read(lcconfig);
113 
114 
115  if (groupAddress < 0x7000) // Main group 0-13
116  {
117  // PID_SUB_LCGRPCONFIG Bit 0-1
118  switch (lcgrpconfig & LCGRPCONFIG::GROUP_6FFF)
119  {
121  //printHex("1drop frame to 0x", (uint8_t*)destination, 2);
122  return false;//drop
123  break;
124 
126  if (isGroupAddressInFilterTable(groupAddress))
127  ;//send
128  else
129  {
130  //printHex("2drop frame to 0x", (uint8_t*)destination, 2);
131  return false;//drop
132  }
133 
134  break;
135 
136  default: // LCGRPCONFIG::GROUP_6FFFUNLOCK
137  ;//send
138  }
139  }
140  else // Main group 14-31
141  {
142  // PID_SUB_LCGRPCONFIG Bit 2-3 LCGRPCONFIG::GROUP_7000
143  switch (lcgrpconfig & LCGRPCONFIG::GROUP_7000)
144  {
146  //printHex("3drop frame to 0x", (uint8_t*)destination, 2);
147  return false;//drop
148  break;
149 
151  if (isGroupAddressInFilterTable(groupAddress))
152  ;//send
153  else
154  {
155  //printHex("4drop frame to 0x", (uint8_t*)destination, 2);
156  return false;//drop
157  }
158 
159  break;
160 
161  default: // LCGRPCONFIG::GROUP_7000UNLOCK
162  ;//send
163  }
164  }
165 
166  return true;
167 }
168 
169 bool NetworkLayerCoupler::isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex)
170 {
171  // TODO: improve: we have to be notified about anything that might affect routing decision
172  // Ugly: we could ALWAYS evaluate coupler type for every received frame
173  if (_currentAddress != _deviceObj.individualAddress())
174  {
175  evaluateCouplerType();
176  }
177 
178  // See KNX spec.: Network Layer (03/03/03) and AN161 (Coupler model 2.0)
179  /*
180  * C hop count value contained in the N-protocol header
181  * D low order octet of the Destination Address, i.e. Device Address part
182  * G Group Address
183  * SD low nibble of high order octet plus low order octet, i.e. Line Address + Device Address
184  * Z high nibble of high order octet of the Destination Address, i.e. Area Address
185  * ZS high order octet of the Destination Address, i.e. hierarchy information part: Area Address + Line Address
186  */
187  uint16_t ownSNA = _deviceObj.individualAddress() & 0xFF00; // Own subnetwork address (area + line)
188  uint16_t ownAA = _deviceObj.individualAddress() & 0xF000; // Own area address
189  uint16_t ZS = individualAddress & 0xFF00; // destination subnetwork address (area + line)
190  uint16_t Z = individualAddress & 0xF000; // destination area address
191 
192 
193  if (_couplerType == LineCoupler)
194  {
195  // Main line to sub line routing
196  if (srcIfIndex == kPrimaryIfIndex)
197  {
198  if (ZS != ownSNA)
199  {
200  // IGNORE_TOTALLY
201  return false;
202  }
203 
204  return true;
205  }
206  else if (srcIfIndex == kSecondaryIfIndex) // Sub line to main line routing
207  {
208  if (ZS != ownSNA)
209  {
210  // ROUTE_XXX
211  return true;
212  }
213  else
214  {
215  return false;
216  }
217  }
218  else
219  {
220  //not from primiary not from sec if, should not happen
221  return false;
222  }
223  }
224  else if (_couplerType == BackboneCoupler)
225  {
226  // Backbone line to main line routing
227  if (srcIfIndex == kPrimaryIfIndex)
228  {
229  if (Z != ownAA)
230  {
231  return false;
232  }
233 
234  return true;
235  }
236  else if (srcIfIndex == kSecondaryIfIndex) // Main line to backbone line routing
237  {
238  if (Z != ownAA)
239  {
240  return true;
241  }
242  else
243  {
244  return false;
245  }
246  }
247  else
248  {
249  //not from primiary not from sec if, should not happen
250  return false;
251  }
252  }
253  else
254  {
255  //unknown coupler type, should not happen
256  return false;
257  }
258 }
259 
260 void NetworkLayerCoupler::sendMsgHopCount(AckType ack, AddressType addrType, uint16_t destination, NPDU& npdu, Priority priority,
261  SystemBroadcast broadcastType, uint8_t sourceInterfaceIndex, uint16_t source)
262 {
263  uint8_t interfaceIndex = (sourceInterfaceIndex == kSecondaryIfIndex) ? kPrimaryIfIndex : kSecondaryIfIndex;
264 
265  uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
266  uint8_t lcgrpconfig = LCGRPCONFIG::GROUP_6FFFROUTE | LCGRPCONFIG::GROUP_7000UNLOCK | LCGRPCONFIG::GROUP_REPEAT; // default value from spec. in case prop is not availible.
267  Property* prop_lcgrpconfig;
268  Property* prop_lcconfig;
269 
270  if (sourceInterfaceIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP)
271  {
272  prop_lcgrpconfig = _rtObjPrimary->property(PID_MAIN_LCGRPCONFIG);
273  prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG);
274  }
275  else // direction Sec -> Prim ( e.g. TP -> IP)
276  {
277  prop_lcgrpconfig = _rtObjPrimary->property(PID_SUB_LCGRPCONFIG);
278  prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG);
279  }
280 
281  if (prop_lcgrpconfig)
282  prop_lcgrpconfig->read(lcgrpconfig);
283 
284  if (prop_lcconfig)
285  prop_lcconfig->read(lcconfig);
286 
287 
288  if (addrType == AddressType::GroupAddress && destination != 0) // destination == 0 means broadcast and must not be filtered with the GroupAddresses
289  {
290  if (!isRoutedGroupAddress(destination, sourceInterfaceIndex))
291  return; // drop;
292  }
293 
294 
295  // If we have a frame from open medium on secondary side (e.g. RF) to primary side, then shall use the hop count of the primary router object
296  if ((_rtObjPrimary != nullptr) && (_rtObjSecondary != nullptr) && (sourceInterfaceIndex == kSecondaryIfIndex))
297  {
298  DptMedium mediumType = getSecondaryInterface().mediumType();
299 
300  if (mediumType == DptMedium::KNX_RF) // Probably also KNX_PL110, but this is not specified, PL110 is also an open medium
301  {
302  uint16_t hopCount = 0;
303 
304  if (_rtObjPrimary->property(PID_HOP_COUNT)->read(hopCount) == 1)
305  {
306  npdu.hopCount(hopCount);
307  }
308  }
309  }
310  else // Normal hopCount between main and sub line and vice versa
311  {
312  if (npdu.hopCount() == 0)
313  {
314  // IGNORE_ACKED
315  return;
316  }
317 
318  if (npdu.hopCount() < 7)
319  {
320  // ROUTE_DECREMENTED
321  npdu.hopCount(npdu.hopCount() - 1);
322  }
323  else if (npdu.hopCount() == 7)
324  {
325  // ROUTE_UNMODIFIED
326  }
327  }
328 
329  // Use other interface
330 #ifdef KNX_LOG_COUPLER
331 
332  if (sourceInterfaceIndex == 0)
333  print("Routing from P->S: ");
334  else
335  print("Routing from S->P: ");
336 
337  print(source, HEX);
338  print(" -> ");
339  print(destination, HEX);
340  print(" - ");
341  npdu.frame().apdu().printPDU();
342 #endif
343 
344  //evaluiate PHYS_REPEAT, BROADCAST_REPEAT and GROUP_REPEAT
345  bool doNotRepeat = false;
346 
347  if ((addrType == AddressType::GroupAddress && !(lcgrpconfig & LCGRPCONFIG::GROUP_REPEAT)) ||
348  (addrType == AddressType::IndividualAddress && !(lcconfig & LCCONFIG::PHYS_REPEAT)) ||
349  (addrType == AddressType::GroupAddress && destination == 0 && !(lcconfig & LCCONFIG::BROADCAST_REPEAT)))
350  doNotRepeat = true;
351 
352  _netLayerEntities[interfaceIndex].sendDataRequest(npdu, ack, destination, source, priority, addrType, broadcastType, doNotRepeat);
353 }
354 
355 // TODO: for later: improve by putting routing algorithms in its own class/functions and only instantiate required algorithm (line vs. coupler)
356 // TODO: we could also do the sanity checks here, i.e. check if sourceAddress is really coming in from correct srcIfIdx, etc. (see PID_COUPL_SERV_CONTROL: EN_SNA_INCONSISTENCY_CHECK)
357 void NetworkLayerCoupler::routeDataIndividual(AckType ack, uint16_t destination, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIndex)
358 {
359  //print("NetworkLayerCoupler::routeDataIndividual dest 0x");
360  //print(destination, HEX);
361  //print(" own addr 0x");
362  //println(_deviceObj.individualAddress(), HEX);
363 
364  if (destination == _deviceObj.individualAddress())
365  {
366  // FORWARD_LOCALLY
367  //println("NetworkLayerCoupler::routeDataIndividual locally");
369  _transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu());
370  return;
371  }
372 
373  // Local to main or sub line
374  if (srcIfIndex == kLocalIfIndex)
375  {
376  uint16_t netaddr;
377  uint16_t Z;
378 
379  if (_couplerType == CouplerType::BackboneCoupler)
380  {
381  netaddr = _deviceObj.individualAddress() & 0xF000;
382  Z = destination & 0xF000;
383  }
384  else if (_couplerType == CouplerType::LineCoupler)
385  {
386  netaddr = _deviceObj.individualAddress() & 0xFF00;
387  Z = destination & 0xFF00;
388  }
389  else
390  {
391  //unknown coupler type, should not happen
392  return ;
393  }
394 
395 
396  // if destination is not within our scope then send via primary interface, else via secondary interface
397  uint8_t destIfidx = (Z != netaddr) ? kPrimaryIfIndex : kSecondaryIfIndex;
398 #ifdef KNX_TUNNELING
399 
400  if (destIfidx == kPrimaryIfIndex)
401  if (isTunnelAddress(destination))
402  destIfidx = kSecondaryIfIndex;
403 
404 #endif
405  //print("NetworkLayerCoupler::routeDataIndividual local to s or p: ");
406  //println(destIfidx);
407  _netLayerEntities[destIfidx].sendDataRequest(npdu, ack, destination, source, priority, AddressType::IndividualAddress, Broadcast);
408  return;
409  }
410 
411  uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
412  Property* prop_lcconfig;
413 
414  if (srcIfIndex == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP)
415  prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG);
416  else // direction Sec -> Prim ( e.g. TP -> IP)
417  prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG);
418 
419  if (prop_lcconfig)
420  prop_lcconfig->read(lcconfig);
421 
423  {
424  // IGNORE_TOTALLY
425  //println("NetworkLayerCoupler::routeDataIndividual locked");
426  return;
427  }
428  else if ((lcconfig & LCCONFIG::PHYS_FRAME) == LCCONFIG::PHYS_FRAME_UNLOCK)
429  {
430  // ROUTE_XXX
431  //println("NetworkLayerCoupler::routeDataIndividual unlocked");
432  sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source);
433  return;
434  }
435  else // LCCONFIG::PHYS_FRAME_ROUTE or 0
436  {
437  if (isRoutedIndividualAddress(destination, srcIfIndex))
438  {
439  //println("NetworkLayerCoupler::routeDataIndividual routed");
440  sendMsgHopCount(ack, AddressType::IndividualAddress, destination, npdu, priority, Broadcast, srcIfIndex, source); // ROUTE_XXX
441  }
442  else
443  {
444  //println("NetworkLayerCoupler::routeDataIndividual not routed");
445  ; // IGNORE_TOTALLY
446  }
447  }
448 }
449 
450 void NetworkLayerCoupler::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx)
451 {
452  // routing for individual addresses
453  if (addrType == IndividualAddress)
454  {
455  //printHex("NetworkLayerCoupler::dataIndication to IA ", (uint8_t*)&destination, 2);
456  //npdu.frame().valid();
457  routeDataIndividual(ack, destination, npdu, priority, source, srcIfIdx);
458  return;
459  }
460 
461  //printHex("NetworkLayerCoupler::dataIndication to GA ", (uint8_t*)&destination, 2);
462  // routing for group addresses
463  // TODO: check new AN189
464  // "AN189 only makes that group messages with hop count 7 cannot bypass the Filter Table unfiltered,
465  // what made the Security Proxy(AN192) useless; now, hc 7 Telegrams are filtered as any other and the value is decremented.
466 
467  // ROUTE_XXX
468  sendMsgHopCount(ack, addrType, destination, npdu, priority, Broadcast, srcIfIdx, source);
469  return;
470 }
471 
472 void NetworkLayerCoupler::dataConfirm(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx)
473 {
474  //println("NetworkLayerCoupler::dataConfirm");
476 
477  // Check if received frame is an echo from our sent frame, we are a normal device in this case
478  if (source == _deviceObj.individualAddress())
479  {
480  if (addrType == IndividualAddress)
481  {
482  _transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status);
483  return;
484  }
485 
486  // else: we do not have any local group communication, so do not handle this
487  }
488 
489  // Do not process the frame any further if it was a routed frame sent from network layer
490 }
491 
492 void NetworkLayerCoupler::broadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx)
493 {
494  // Send it to our local stack first
495  {
497  DptMedium mediumType = _netLayerEntities[srcIfIdx].mediumType();
498 
499  // for closed media like TP1 and IP
500  if ( ((mediumType == DptMedium::KNX_TP1) || (mediumType == DptMedium::KNX_IP)) &&
501  isApciSystemBroadcast(npdu.tpdu().apdu()))
502  {
504  _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu());
505  return;
506  }
507 
508  _transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu());
509  }
510 
511  uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
512  Property* prop_lcconfig;
513 
514  if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP)
515  prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG);
516  else // direction Sec -> Prim ( e.g. TP -> IP)
517  prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG);
518 
519  if (prop_lcconfig)
520  prop_lcconfig->read(lcconfig);
521 
522  // Route to other interface
523  if (!(lcconfig & LCCONFIG::BROADCAST_LOCK))
524  sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, Broadcast, srcIfIdx, source);
525 }
526 
527 void NetworkLayerCoupler::broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx)
528 {
530 
531  // Check if received frame is an echo from our sent frame, we are a normal device in this case
532  if (source == _deviceObj.individualAddress())
533  {
534  _transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status);
535  }
536 
537  // Do not process the frame any further
538 }
539 
540 void NetworkLayerCoupler::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source, uint8_t srcIfIdx)
541 {
542  // Send it to our local stack first
543  {
545  _transportLayer.dataSystemBroadcastIndication(hopType, priority, source, npdu.tpdu());
546  }
547 
548  uint8_t lcconfig = LCCONFIG::PHYS_FRAME_ROUT | LCCONFIG::PHYS_REPEAT | LCCONFIG::BROADCAST_REPEAT | LCCONFIG::GROUP_IACK_ROUT | LCCONFIG::PHYS_IACK_NORMAL; // default value from spec. in case prop is not availible.
549  Property* prop_lcconfig;
550 
551  if (srcIfIdx == kPrimaryIfIndex) // direction Prim -> Sec ( e.g. IP -> TP)
552  prop_lcconfig = _rtObjPrimary->property(PID_MAIN_LCCONFIG);
553  else // direction Sec -> Prim ( e.g. TP -> IP)
554  prop_lcconfig = _rtObjPrimary->property(PID_SUB_LCCONFIG);
555 
556  if (prop_lcconfig)
557  prop_lcconfig->read(lcconfig);
558 
559  // Route to other interface
560  if (!(lcconfig & LCCONFIG::BROADCAST_LOCK))
561  sendMsgHopCount(ack, GroupAddress, 0, npdu, priority, SysBroadcast, srcIfIdx, source);
562 }
563 
564 void NetworkLayerCoupler::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status, uint8_t srcIfIdx)
565 {
566  // Check if received frame is an echo from our sent frame, we are a normal device in this case
567  if (source == _deviceObj.individualAddress())
568  {
570  _transportLayer.dataSystemBroadcastConfirm(ack, hopType, npdu.tpdu(), priority, status);
571  }
572 
573  // Do not process the frame any further
574 }
575 
576 void NetworkLayerCoupler::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
577 {
578  NPDU& npdu = tpdu.frame().npdu();
579 
580  if (hopType == UnlimitedRouting)
581  npdu.hopCount(7);
582  else
583  npdu.hopCount(hopCount());
584 
585  //if (tpdu.apdu().length() > 0)
586  //{
587  // print.print("-> NL ");
588  // tpdu.apdu().printPDU();
589  //}
590  routeDataIndividual(ack, destination, npdu, priority, _deviceObj.individualAddress(), kLocalIfIndex);
591 }
592 
593 void NetworkLayerCoupler::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
594 {
595  NPDU& npdu = tpdu.frame().npdu();
596 
597  if (hopType == UnlimitedRouting)
598  npdu.hopCount(7);
599  else
600  npdu.hopCount(hopCount());
601 
602  // If the group address is in the filter table, then we route it to the primary side too
603  if (isGroupAddressInFilterTable(destination))
604  {
605  _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast);
606  }
607 
608  // We send it to our sub line in any case
609  _netLayerEntities[kSecondaryIfIndex].sendDataRequest(npdu, ack, destination, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast);
610 }
611 
613 {
614  NPDU& npdu = tpdu.frame().npdu();
615 
616  if (hopType == UnlimitedRouting)
617  npdu.hopCount(7);
618  else
619  npdu.hopCount(hopCount());
620 
621  CemiFrame tmpFrame(tpdu.frame());
622 
623  _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast);
624  _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, Broadcast);
625 }
626 
628 {
629  NPDU& npdu = tpdu.frame().npdu();
630 
631  if (hopType == UnlimitedRouting)
632  npdu.hopCount(7);
633  else
634  npdu.hopCount(hopCount());
635 
636 
637  CemiFrame tmpFrame(tpdu.frame());
638 
639  // for closed media like TP1 and IP
640  bool isClosedMedium = (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kPrimaryIfIndex].mediumType() == DptMedium::KNX_IP);
641  SystemBroadcast broadcastType = (isClosedMedium && isApciSystemBroadcast(tpdu.apdu()) ? Broadcast : SysBroadcast);
642  _netLayerEntities[kPrimaryIfIndex].sendDataRequest(npdu, ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType);
643 
644  isClosedMedium = (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_TP1) || (_netLayerEntities[kSecondaryIfIndex].mediumType() == DptMedium::KNX_IP);
645  broadcastType = (isClosedMedium && isApciSystemBroadcast(tmpFrame.apdu()) ? Broadcast : SysBroadcast);
646  println(broadcastType);
647  _netLayerEntities[kSecondaryIfIndex].sendDataRequest(tmpFrame.npdu(), ack, 0, _deviceObj.individualAddress(), priority, GroupAddress, broadcastType);
648 }
649 
650 #ifdef KNX_TUNNELING
651 bool NetworkLayerCoupler::isTunnelAddress(uint16_t destination)
652 {
653  // tunnels are managed within the IpDataLinkLayer - kPrimaryIfIndex
654  return _netLayerEntities[kPrimaryIfIndex].dataLinkLayer().isTunnelAddress(destination);
655 }
656 #endif
void print(const char *s)
void println(const char *s)
void printPDU()
Print the contents of the APDU to console.
Definition: apdu.cpp:43
SystemBroadcast systemBroadcast() const
Definition: cemi_frame.cpp:237
NPDU & npdu()
Definition: cemi_frame.cpp:357
APDU & apdu()
Definition: cemi_frame.cpp:367
uint16_t individualAddress()
Property * property(PropertyID id)
Gets property with PropertyID id if it exists and nullptr otherwise.
Definition: npdu.h:9
TPDU & tpdu()
Definition: npdu.cpp:41
CemiFrame & frame()
Definition: npdu.cpp:36
uint8_t hopCount() const
Definition: npdu.cpp:26
NetworkLayerEntity & getSecondaryInterface()
void rtObjSecondary(RouterObject &rtObjSecondary)
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU &tpdu) override
void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU &tpdu) override
bool isRoutedIndividualAddress(uint16_t individualAddress, uint8_t srcIfIndex)
void rtObjPrimary(RouterObject &rtObjPrimary)
NetworkLayerCoupler(DeviceObject &deviceObj, TransportLayer &layer)
void rtObj(RouterObject &rtObj)
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU &tpdu) override
NetworkLayerEntity & getPrimaryInterface()
bool isRoutedGroupAddress(uint16_t groupAddress, uint8_t sourceInterfaceIndex)
void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU &tpdu) override
void dataLinkLayer(DataLinkLayer &layer)
DptMedium mediumType() const
DeviceObject & _deviceObj
Definition: network_layer.h:29
uint8_t hopCount() const
bool isApciSystemBroadcast(APDU &apdu)
TransportLayer & _transportLayer
Definition: network_layer.h:30
virtual uint8_t read(uint16_t start, uint8_t count, uint8_t *data) const =0
bool isGroupAddressInFilterTable(uint16_t groupAddress)
Definition: tpdu.h:9
APDU & apdu()
Definition: tpdu.cpp:111
CemiFrame & frame()
Definition: tpdu.cpp:116
void dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU &tpdu, Priority priority, bool status)
void dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU &tpdu)
void dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU &tpdu, bool status)
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU &tpdu)
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU &tpdu, bool status)
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU &tpdu)
@ GROUP_7000ROUTE
Definition: knx_types.h:273
@ GROUP_6FFFROUTE
Definition: knx_types.h:270
@ GROUP_6FFF
Definition: knx_types.h:265
@ GROUP_7000
Definition: knx_types.h:266
@ GROUP_REPEAT
Definition: knx_types.h:267
@ GROUP_6FFFLOCK
Definition: knx_types.h:269
@ GROUP_7000UNLOCK
Definition: knx_types.h:271
@ GROUP_7000LOCK
Definition: knx_types.h:272
HopCountType
Definition: knx_types.h:124
@ UnlimitedRouting
NPDU::hopCount is set to 7. This means that the frame never expires. This could be a problem if your ...
Definition: knx_types.h:125
@ NetworkLayerParameter
use NetworkLayer::hopCount as NPDU::hopCount
Definition: knx_types.h:126
Priority
Definition: knx_types.h:10
FrameFormat
Definition: knx_types.h:4
AckType
Definition: knx_types.h:18
DptMedium
Definition: knx_types.h:254
@ KNX_IP
Definition: knx_types.h:260
@ KNX_TP1
Definition: knx_types.h:257
@ KNX_RF
Definition: knx_types.h:259
@ BROADCAST_LOCK
Definition: knx_types.h:283
@ PHYS_FRAME_UNLOCK
Definition: knx_types.h:279
@ PHYS_REPEAT
Definition: knx_types.h:282
@ PHYS_FRAME
Definition: knx_types.h:278
@ PHYS_FRAME_LOCK
Definition: knx_types.h:280
@ GROUP_IACK_ROUT
Definition: knx_types.h:285
@ BROADCAST_REPEAT
Definition: knx_types.h:284
@ PHYS_IACK_NORMAL
Definition: knx_types.h:287
@ PHYS_FRAME_ROUT
Definition: knx_types.h:281
AddressType
Definition: knx_types.h:33
@ GroupAddress
Definition: knx_types.h:35
@ IndividualAddress
Definition: knx_types.h:34
SystemBroadcast
Definition: knx_types.h:112
@ Broadcast
Definition: knx_types.h:114
@ SysBroadcast
Definition: knx_types.h:113
@ PID_MAIN_LCCONFIG
Definition: property.h:182
@ PID_SUB_LCGRPCONFIG
Definition: property.h:185
@ PID_SUB_LCCONFIG
Definition: property.h:183
@ PID_HOP_COUNT
Definition: property.h:190
@ PID_MAIN_LCGRPCONFIG
Definition: property.h:184