knx
ETS configurable knx-stack
data_link_layer.cpp
Go to the documentation of this file.
1 #include "data_link_layer.h"
2 
3 #include "bits.h"
4 #include "platform.h"
5 #include "device_object.h"
6 #include "cemi_server.h"
7 #include "cemi_frame.h"
8 
9 
11 {
13  _activityCallback(info);
14 }
15 
17 {
18  _activityCallback = activityCallback;
19 }
20 
22  _deviceObject(devObj), _networkLayerEntity(netLayerEntity), _platform(platform)
23 {
24 #ifdef KNX_ACTIVITYCALLBACK
25  _netIndex = netLayerEntity.getEntityIndex();
26 #endif
27 }
28 
29 #ifdef USE_CEMI_SERVER
30 
32 {
34 }
35 
36 #ifdef KNX_TUNNELING
38 {
39  println("default dataRequestToTunnel");
40 }
41 
43 {
44  println("default dataConfirmationToTunnel");
45 }
46 
48 {
49  println("default dataIndicationToTunnel");
50 }
51 
52 bool DataLinkLayer::isTunnelAddress(uint16_t addr)
53 {
54  println("default IsTunnelAddress");
55  return false;
56 }
57 #endif
58 
60 {
62 
63  frame.messageCode(L_data_ind);
64 
65  // Send to local stack ( => cemiServer for potential other tunnel and network layer for routing)
66  frameReceived(frame);
67 
68 #ifdef KNX_TUNNELING
69  // TunnelOpti
70  // Optimize performance when receiving unicast data over tunnel wich is not meant to be used on the physical TP line
71  // dont send to knx when
72  // frame is individual adressed AND
73  // destionation == PA of Tunnel-Server OR
74  // destination == PA of a Tunnel OR (TODO)
75  // destination is not the TP/secondary line/segment but IP/primary (TODO)
76 
78  {
80  return;
81 
82  if (isRoutedPA(frame.destinationAddress()))
83  return;
84 
85  if (isTunnelingPA(frame.destinationAddress()))
86  return;
87  }
88 
89 #endif
90 
91  // Send to KNX medium
92  sendFrame(frame);
93 }
94 #endif
95 
96 void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, uint16_t sourceAddr, FrameFormat format, Priority priority, NPDU& npdu)
97 {
98  // Normal data requests and broadcasts will always be transmitted as (domain) broadcast with domain address for open media (e.g. RF medium)
99  // The domain address "simulates" a closed medium (such as TP) on an open medium (such as RF or PL)
100  // See 3.2.5 p.22
101  sendTelegram(npdu, ack, destinationAddr, addrType, sourceAddr, format, priority, Broadcast);
102 }
103 
104 void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu, uint16_t sourceAddr)
105 {
106  // System Broadcast requests will always be transmitted as broadcast with KNX serial number for open media (e.g. RF medium)
107  // See 3.2.5 p.22
108  sendTelegram(npdu, ack, 0, GroupAddress, sourceAddr, format, priority, SysBroadcast);
109 }
110 
111 void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
112 {
113  MessageCode backupMsgCode = frame.messageCode();
114  frame.messageCode(L_data_con);
115  frame.confirm(success ? ConfirmNoError : ConfirmError);
116  AckType ack = frame.ack();
117  AddressType addrType = frame.addressType();
118  uint16_t destination = frame.destinationAddress();
119  uint16_t source = frame.sourceAddress();
120  FrameFormat type = frame.frameType();
121  Priority priority = frame.priority();
122  NPDU& npdu = frame.npdu();
123  SystemBroadcast systemBroadcast = frame.systemBroadcast();
124 
125 #ifdef USE_CEMI_SERVER
126 
127  // if the confirmation was caused by a tunnel request then
128  // do not send it to the local stack
129  if (frame.sourceAddress() == _cemiServer->clientAddress())
130  {
131  // Stop processing here and do NOT send it the local network layer
132  return;
133  }
134 
135 #endif
136 
137  if (addrType == GroupAddress && destination == 0)
138  if (systemBroadcast == SysBroadcast)
139  _networkLayerEntity.systemBroadcastConfirm(ack, type, priority, source, npdu, success);
140  else
141  _networkLayerEntity.broadcastConfirm(ack, type, priority, source, npdu, success);
142  else
143  _networkLayerEntity.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success);
144 
145  frame.messageCode(backupMsgCode);
146 }
147 
149 {
150  AckType ack = frame.ack();
151  AddressType addrType = frame.addressType();
152  uint16_t destination = frame.destinationAddress();
153  uint16_t source = frame.sourceAddress();
154  FrameFormat type = frame.frameType();
155  Priority priority = frame.priority();
156  NPDU& npdu = frame.npdu();
157  uint16_t ownAddr = _deviceObject.individualAddress();
158  SystemBroadcast systemBroadcast = frame.systemBroadcast();
159 
160 #ifdef USE_CEMI_SERVER
161  // Do not send our own message back to the tunnel
162 #ifdef KNX_TUNNELING
163 
164  //we dont need to check it here
165  // send inbound frames to the tunnel if we are the secondary (TP) interface
168 
169 #else
170 
171  if (frame.sourceAddress() != _cemiServer->clientAddress())
172  {
174  }
175 
176 #endif
177 #endif
178 
179  // print("Frame received destination: ");
180  // print(destination, 16);
181  // println();
182  // print("frameReceived: frame valid? :");
183  // println(npdu.frame().valid() ? "true" : "false");
184  if (source == ownAddr)
186 
187  if (addrType == GroupAddress && destination == 0)
188  {
189  if (systemBroadcast == SysBroadcast)
190  _networkLayerEntity.systemBroadcastIndication(ack, type, npdu, priority, source);
191  else
192  _networkLayerEntity.broadcastIndication(ack, type, npdu, priority, source);
193  }
194  else
195  {
196  _networkLayerEntity.dataIndication(ack, addrType, destination, type, npdu, priority, source);
197  }
198 }
199 
200 bool DataLinkLayer::sendTelegram(NPDU& npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, uint16_t sourceAddr, FrameFormat format, Priority priority, SystemBroadcast systemBroadcast, bool doNotRepeat)
201 {
202  CemiFrame& frame = npdu.frame();
203  // print("Send telegram frame valid ?: ");
204  // println(frame.valid()?"true":"false");
205  frame.messageCode(L_data_ind);
206  frame.destinationAddress(destinationAddr);
207  frame.sourceAddress(sourceAddr);
208  frame.addressType(addrType);
209  frame.priority(priority);
210  frame.repetition(doNotRepeat ? NoRepitiion : RepetitionAllowed);
211  frame.systemBroadcast(systemBroadcast);
212 
213  if (npdu.octetCount() <= 15)
214  frame.frameType(StandardFrame);
215  else
216  frame.frameType(format);
217 
218 
219  if (!frame.valid())
220  {
221  println("invalid frame");
222  return false;
223  }
224 
225  // if (frame.npdu().octetCount() > 0)
226  // {
227  // _print("<- DLL ");
228  // frame.apdu().printPDU();
229  // }
230 
231  bool sendTheFrame = true;
232  bool success = true;
233 
234 #ifdef KNX_TUNNELING
235  // TunnelOpti
236  // Optimize performance when sending unicast data over tunnel wich is not meant to be used on the physical TP line
237  // dont send to knx when
238  // a) we are the secondary interface (e.g. TP) AND
239  // b) destination == PA of a Tunnel (TODO)
240 
241  if (_networkLayerEntity.getEntityIndex() == 1 && addrType == AddressType::IndividualAddress) // don't send to tp if we are the secondary (TP) interface AND the destination is a tunnel-PA
242  {
243  if (isTunnelingPA(destinationAddr))
244  sendTheFrame = false;
245  }
246 
247 #endif
248 
249  // The data link layer might be an open media link layer
250  // and will setup rfSerialOrDoA, rfInfo and rfLfn that we also
251  // have to send through the cEMI server tunnel
252  // Thus, reuse the modified cEMI frame as "frame" is only passed by reference here!
253  if (sendTheFrame)
254  success = sendFrame(frame);
255 
256 #ifdef USE_CEMI_SERVER
257  CemiFrame tmpFrame(frame.data(), frame.totalLenght());
258  // We can just copy the pointer for rfSerialOrDoA as sendFrame() sets
259  // a pointer to const uint8_t data in either device object (serial) or
260  // RF medium object (domain address)
261 #ifdef USE_RF
262  tmpFrame.rfSerialOrDoA(frame.rfSerialOrDoA());
263  tmpFrame.rfInfo(frame.rfInfo());
264  tmpFrame.rfLfn(frame.rfLfn());
265 #endif
266  tmpFrame.confirm(ConfirmNoError);
267 
268  if (_networkLayerEntity.getEntityIndex() == 1) // only send to tunnel if we are the secondary (TP) interface
270 
271 #endif
272 
273  return success;
274 }
275 
277 {
278  return frame._data;
279 }
280 
281 #ifdef KNX_TUNNELING
283 {
284  uint8_t numAddresses = 0;
285  uint16_t* addresses = _ipParameters->additionalIndivualAddresses(numAddresses);
286 
287  for (uint8_t i = 0; i < numAddresses; i++)
288  {
289  if (pa == addresses[i])
290  return true;
291  }
292 
293  return false;
294 }
295 
296 bool DataLinkLayer::isRoutedPA(uint16_t pa)
297 {
298  uint16_t ownpa = _deviceObject.individualAddress();
299  uint16_t own_sm;
300 
301  if ((ownpa & 0x0F00) == 0x0)
302  own_sm = 0xF000;
303  else
304  own_sm = 0xFF00;
305 
306  return (pa & own_sm) != ownpa;
307 }
308 #endif
309 
void println(const char *s)
SystemBroadcast systemBroadcast() const
Definition: cemi_frame.cpp:237
NPDU & npdu()
Definition: cemi_frame.cpp:357
uint16_t sourceAddress() const
Definition: cemi_frame.cpp:303
uint8_t * rfSerialOrDoA() const
Definition: cemi_frame.cpp:327
bool valid() const
Definition: cemi_frame.cpp:372
uint8_t * data()
Definition: cemi_frame.cpp:195
AckType ack() const
Definition: cemi_frame.cpp:259
Repetition repetition() const
Definition: cemi_frame.cpp:226
uint8_t rfLfn() const
Definition: cemi_frame.cpp:347
uint8_t rfInfo() const
Definition: cemi_frame.cpp:337
uint16_t destinationAddress() const
Definition: cemi_frame.cpp:315
Confirm confirm() const
Definition: cemi_frame.cpp:270
MessageCode messageCode() const
Definition: cemi_frame.cpp:126
AddressType addressType() const
Definition: cemi_frame.cpp:281
FrameFormat frameType() const
Definition: cemi_frame.cpp:215
Priority priority() const
Definition: cemi_frame.cpp:248
uint16_t totalLenght() const
Definition: cemi_frame.cpp:136
This is an implementation of the cEMI server as specified in .
Definition: cemi_server.h:23
void dataConfirmationToTunnel(CemiFrame &frame)
Definition: cemi_server.cpp:49
void dataIndicationToTunnel(CemiFrame &frame)
Definition: cemi_server.cpp:73
uint16_t clientAddress() const
Definition: cemi_server.cpp:39
void individualAddressDuplication(bool value)
uint16_t individualAddress()
uint16_t * additionalIndivualAddresses(uint8_t &numAddresses)
Definition: npdu.h:9
uint8_t octetCount() const
Definition: npdu.cpp:11
CemiFrame & frame()
Definition: npdu.cpp:36
void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU &npdu, Priority priority, uint16_t source)
void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU &npdu, bool status)
void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU &npdu, bool status)
void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU &npdu, Priority priority, uint16_t source)
void broadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU &npdu, bool status)
void broadcastIndication(AckType ack, FrameFormat format, NPDU &npdu, Priority priority, uint16_t source)
@ ConfirmError
Definition: knx_types.h:120
@ ConfirmNoError
Definition: knx_types.h:119
@ RepetitionAllowed
Definition: knx_types.h:107
@ NoRepitiion
Definition: knx_types.h:105
Priority
Definition: knx_types.h:10
FrameFormat
Definition: knx_types.h:4
@ StandardFrame
Definition: knx_types.h:6
MessageCode
Definition: knx_types.h:39
@ L_data_con
Definition: knx_types.h:42
@ L_data_ind
Definition: knx_types.h:43
AckType
Definition: knx_types.h:18
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