knx
ETS configurable knx-stack
tpuart_data_link_layer.cpp
Go to the documentation of this file.
1 #include "config.h"
2 #ifdef USE_TP
3 #pragma GCC optimize("O3")
4 
5 #include "address_table_object.h"
6 #include "bits.h"
7 #include "cemi_frame.h"
8 #include "device_object.h"
9 #include "platform.h"
10 #include "tpuart_data_link_layer.h"
11 
12 /*
13  * A new implementation of the tpuart connection.
14  * Author Marco Scholl <develop@marco-scholl.de>
15  *
16  */
17 
18 // services Host -> Controller :
19 // internal commands, device specific
20 #define U_RESET_REQ 0x01
21 #define U_STATE_REQ 0x02
22 #define U_SET_BUSY_REQ 0x03
23 #define U_QUIT_BUSY_REQ 0x04
24 #define U_BUSMON_REQ 0x05
25 #define U_SET_ADDRESS_REQ 0xF1 // different on TP-UART
26 #define U_L_DATA_OFFSET_REQ 0x08 //-0x0C
27 #define U_SYSTEM_MODE 0x0D
28 #define U_STOP_MODE_REQ 0x0E
29 #define U_EXIT_STOP_MODE_REQ 0x0F
30 #define U_ACK_REQ 0x10 //-0x17
31 #define U_ACK_REQ_NACK 0x04
32 #define U_ACK_REQ_BUSY 0x02
33 #define U_ACK_REQ_ADRESSED 0x01
34 #define U_POLLING_STATE_REQ 0xE0
35 
36 // Only on NCN51xx available
37 #ifdef NCN5120
38  #define U_CONFIGURE_REQ 0x18
39  #define U_CONFIGURE_MARKER_REQ 0x1
40  #define U_CONFIGURE_CRC_CCITT_REQ 0x2
41  #define U_CONFIGURE_AUTO_POLLING_REQ 0x4
42  #define U_SET_REPETITION_REQ 0xF2
43 #else
44  #define U_MXRSTCNT 0x24
45 #endif
46 
47 // knx transmit data commands
48 #define U_L_DATA_START_REQ 0x80
49 #define U_L_DATA_CONT_REQ 0x80 //-0xBF
50 #define U_L_DATA_END_REQ 0x40 //-0x7F
51 
52 // serices to host controller
53 
54 // DLL services (device is transparent)
55 #define L_DATA_STANDARD_IND 0x90
56 #define L_DATA_EXTENDED_IND 0x10
57 #define L_DATA_MASK 0xD3
58 #define L_POLL_DATA_IND 0xF0
59 
60 // acknowledge services (device is transparent in bus monitor mode)
61 #define L_ACKN_IND 0x00
62 #define L_ACKN_MASK 0x33
63 #define L_ACKN_BUSY_MASK 0x0C
64 #define L_ACKN_NACK_MASK 0xC0
65 #define L_DATA_CON 0x0B
66 #define L_DATA_CON_MASK 0x7F
67 #define SUCCESS 0x80
68 
69 // control services, device specific
70 #define U_RESET_IND 0x03
71 #define U_STATE_MASK 0x07
72 #define U_STATE_IND 0x07
73 #define SLAVE_COLLISION 0x80
74 #define RECEIVE_ERROR 0x40
75 #define TRANSMIT_ERROR 0x20
76 #define PROTOCOL_ERROR 0x10
77 #define TEMPERATURE_WARNING 0x08
78 #define U_FRAME_STATE_IND 0x13
79 #define U_FRAME_STATE_MASK 0x17
80 #define PARITY_BIT_ERROR 0x80
81 #define CHECKSUM_LENGTH_ERROR 0x40
82 #define TIMING_ERROR 0x20
83 #define U_CONFIGURE_IND 0x01
84 #define U_CONFIGURE_MASK 0x83
85 #define AUTO_ACKNOWLEDGE 0x20
86 #define AUTO_POLLING 0x10
87 #define CRC_CCITT 0x80
88 #define FRAME_END_WITH_MARKER 0x40
89 #define U_FRAME_END_IND 0xCB
90 #define U_STOP_MODE_IND 0x2B
91 #define U_SYSTEM_STAT_IND 0x4B
92 
93 /*
94  * NCN51xx Register handling
95  */
96 // write internal registers
97 #define U_INT_REG_WR_REQ_WD 0x28
98 #define U_INT_REG_WR_REQ_ACR0 0x29
99 #define U_INT_REG_WR_REQ_ACR1 0x2A
100 #define U_INT_REG_WR_REQ_ASR0 0x2B
101 // read internal registers
102 #define U_INT_REG_RD_REQ_WD 0x38
103 #define U_INT_REG_RD_REQ_ACR0 0x39
104 #define U_INT_REG_RD_REQ_ACR1 0x3A
105 #define U_INT_REG_RD_REQ_ASR0 0x3B
106 // Analog Control Register 0 - Bit values
107 #define ACR0_FLAG_V20VEN 0x40
108 #define ACR0_FLAG_DC2EN 0x20
109 #define ACR0_FLAG_XCLKEN 0x10
110 #define ACR0_FLAG_TRIGEN 0x08
111 #define ACR0_FLAG_V20VCLIMIT 0x04
112 
113 enum
114 {
116  TX_FRAME
117 };
118 
119 enum
120 {
121  // In this state, the system waits for new control commands.
123 
124  // In this state, all bytes are regarded as bytes for a frame.
126 
127  // In this state, all bytes are discarded
129 
130  // Monitoring is still waiting for an ACk
132 };
133 
134 void printFrame(TpFrame* tpframe)
135 {
136  print(tpframe->humanSource().c_str());
137  print(" -> ");
138  print(tpframe->humanDestination().c_str());
139  print(" [");
140  print((tpframe->flags() & TP_FRAME_FLAG_INVALID) ? 'I' : '_'); // Invalid
141  print((tpframe->flags() & TP_FRAME_FLAG_EXTENDED) ? 'E' : '_'); // Extended
142  print((tpframe->flags() & TP_FRAME_FLAG_REPEATED) ? 'R' : '_'); // Repeat
143  print((tpframe->flags() & TP_FRAME_FLAG_ECHO) ? 'T' : '_'); // Send by me
144  print((tpframe->flags() & TP_FRAME_FLAG_ADDRESSED) ? 'D' : '_'); // Recv for me
145  print((tpframe->flags() & TP_FRAME_FLAG_ACK_NACK) ? 'N' : '_'); // ACK + NACK
146  print((tpframe->flags() & TP_FRAME_FLAG_ACK_BUSY) ? 'B' : '_'); // ACK + BUSY
147  print((tpframe->flags() & TP_FRAME_FLAG_ACK) ? 'A' : '_'); // ACK
148  print("] ");
149  printHex("( ", tpframe->data(), tpframe->size(), false);
150  print(")");
151 }
152 
153 /*
154  * Processes all bytes.
155  */
156 void __isr __time_critical_func(TpUartDataLinkLayer::processRx)(bool isr)
157 {
158  if (!isrLock())
159  return;
160 
161  /*
162  * Some platforms support the detection of whether the hardware buffer has overflowed.
163  * Theoretically, you could now discard the buffer, but then a valid frame may be lost.
164  * Therefore, only one piece of information is output later in the loop and byte processing "tries" to respond to it.
165  */
166  if (_platform.overflowUart())
167  _rxOverflow = true;
168 
169  // process data
170  while (_platform.uartAvailable())
171  {
172  processRxByte();
173  }
174 
175  isrUnlock();
176 }
177 
178 /*
179  * Processes 1 incoming byte (if available)
180  */
181 void TpUartDataLinkLayer::processRxByte()
182 {
183  int byte = _platform.readUart();
184 
185  // RxBuffer empty
186  if (byte < 0)
187  return;
188 
189  /*
190  * If I am in RX_INVALID mode
191  * and the last byte was processed more than 2ms ago (i.e. pause >2ms)
192  * and there are no more bytes in the buffer,
193  * then I can discard the INVALID state.
194  */
195  if (_rxState == RX_INVALID && (millis() - _rxLastTime) > 2 && !_platform.uartAvailable())
196  {
197  processRxFrameComplete();
198  _rxState = RX_IDLE;
199  }
200 
201  if (_rxState == RX_INVALID)
202  {
203  /*
204  * As soon as a frame has been processed invalidly or an unknown command arrives, the status changes to RX_INVALID.
205  * From now on I must assume that there has been a transmission error and the current bytes are invalid.
206  * The same applies if a HW overflow is detected.
207  *
208  * The time of the last frame is 3ms past and there is no more data in the buffer. (Is checked by me)
209  * - If the marker mode is active and a U_FRAME_END_IND has been detected correctly. (Checked here)
210  *
211  * Otherwise this section does nothing and thus discards the invalid bytes
212  */
213  if (markerMode())
214  {
215  if (!_rxMarker && byte == U_FRAME_END_IND)
216  {
217  _rxMarker = true;
218  }
219  else if (_rxMarker && byte == U_FRAME_END_IND)
220  {
221  // double byte found so reset marker - no frame end
222  _rxMarker = false;
223  }
224  else if (_rxMarker)
225  {
226  // frame end found. -> RX_IDLE
227  _rxMarker = false;
228  _rxState = RX_IDLE;
229  }
230  }
231  }
232  else if (_rxState == RX_FRAME)
233  {
234  processRxFrameByte(byte);
235  }
236  else if ((byte & L_DATA_MASK) == L_DATA_STANDARD_IND || (byte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
237  {
238  /*
239  * Process a previous frame if still available. This should normally only occur in the bus monitor because an ACK is also being waited for here
240  */
241  processRxFrameComplete();
242  _rxFrame->addByte(byte);
243 
244  // Provoke invalid frames for tests
245  // if (millis() % 20 == 0)
246  // _rxFrame->addByte(0x1);
247 
248  _rxMarker = false;
249  _rxState = RX_FRAME;
250 
251  /*
252  * Here an ack is set inital without Addressed. This is used if an Ack is still set from the previous frame,
253  * is set back. This happens if processing is delayed too much (e.g. because no DMA/IRQ is used).
254  * The ACK can be sent as often as required because it is only stored in the BCU and is only used / sent when required.
255  *
256  * Of course, you can only do this if you are not sending yourself, as you do not ACK your own frames. The BCU may ignore this,
257  * but I wanted to be on the safe side here.
258  */
259  if (_txState == TX_IDLE)
260  {
261  _platform.writeUart(U_ACK_REQ);
262  }
263  }
264  else
265  {
266  // The commands are evaluated here, if this has already happened.
267 
268  if (byte == U_RESET_IND)
269  {
270  // println("U_RESET_IND");
271  }
272  else if ((byte & U_STATE_MASK) == U_STATE_IND)
273  {
274  _tpState |= (byte ^ U_STATE_MASK);
275 #ifndef NCN5120
276  /*
277  * Filter "Protocol errors" because this is set on other BCUs such as the Siements when the timing is not correct.
278  * Unfortunately, perfect timing is not possible, so this error must be ignored. Also has no known effects.
279  */
280  _tpState &= 0b11101000;
281 #endif
282  }
283  else if ((byte & U_CONFIGURE_MASK) == U_CONFIGURE_IND)
284  {
285  // println("U_CONFIGURE_IND");
286  }
287  else if (byte == U_STOP_MODE_IND)
288  {
289  // println("U_STOP_MODE_IND");
290  }
291  else if ((byte & L_ACKN_MASK) == L_ACKN_IND)
292  {
293  /*
294  * If a frame has not yet been closed and an Ack comes in.
295  * then set the ACK.
296  */
297  if (_rxFrame->size() > 0)
298  {
299  if (!(byte & L_ACKN_BUSY_MASK))
300  _rxFrame->addFlags(TP_FRAME_FLAG_ACK_BUSY);
301 
302  if (!(byte & L_ACKN_NACK_MASK))
303  _rxFrame->addFlags(TP_FRAME_FLAG_ACK_NACK);
304 
305  _rxFrame->addFlags(TP_FRAME_FLAG_ACK);
306  processRxFrameComplete();
307  }
308 
309  // println("L_ACKN_IND");
310  }
311  else if ((byte & L_DATA_CON_MASK) == L_DATA_CON)
312  {
313  if (_txState == TX_FRAME)
314  {
315  const bool success = ((byte ^ L_DATA_CON_MASK) >> 7);
316  processTxFrameComplete(success);
317  }
318  else
319  {
320  // This byte was not expected because nothing was sent.
321  _rxUnkownControlCounter++;
322  _rxState = RX_INVALID;
323  // println("L_DATA_CON");
324  }
325  }
326  else if (byte == L_POLL_DATA_IND)
327  {
328  // println("L_POLL_DATA_IND");
329  }
330  else if ((byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
331  {
332  // println("U_FRAME_STATE_IND");
333  }
334  else
335  {
336  _rxUnkownControlCounter++;
337  // print("Unknown Controlbyte: ");
338  // println(byte, HEX);
339  _rxState = RX_INVALID;
340  }
341  }
342 
343  _rxLastTime = millis();
344 }
345 
346 /*
347  * Process incoming byte of a frame
348  */
349 void TpUartDataLinkLayer::processRxFrameByte(uint8_t byte)
350 {
351  /*
352  * If the maker is active, the first U_FRAME_END_IND must be ignored and a subsequent byte must be waited for.
353  * The subsequent byte is therefore decisive for how this byte is to be evaluated.
354  */
355  if (markerMode() && (byte == U_FRAME_END_IND && !_rxMarker))
356  {
357  _rxMarker = true;
358  }
359 
360  /*
361  * If the previous byte was a U_FRAME_END_IND and the new byte is a U_FRAME_STATE_IND,
362  * then the reception is cleanly completed and the frame can be processed.
363  */
364  else if (_rxMarker && (byte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
365  {
366  _rxMarker = false;
367  processRxFrameComplete();
368 
369  /*
370  * Set the status to RX_IDLE, as the marker ensures,
371  * that the frame has been processed successfully. Subsequent bytes are therefore clean again Control commands,
372  * even if the frame was discarded due to an invalid checksum (which would mean RX_INVAID)
373  */
374  _rxState = RX_IDLE;
375  }
376 
377  /*
378  * This is a hypothetical case in which the frames are sent without markers even though marker mode is active.
379  * Here the current frame is processed and RX_INVALID is set, as the current byte is not processed.
380  * This case can occur if the marker mode is not supported by the TPUart (NCN51xx feature) but has been activated.
381  */
382  else if (markerMode() && _rxFrame->isFull())
383  {
384  processRxFrameComplete();
385  /*
386  * RX_INVALID because theoretically the frame could have been processed as valid.
387  * However, since the current byte has already been "started" to be processed, it is missing in the processing chain
388  * and therefore the subsequent bytes cannot be used.
389  */
390  _rxState = RX_INVALID;
391  }
392 
393  /*
394  * If marker mode is active, the byte should be processed normally.
395  * If marker mode is active, a U_FRAME_END_IND byte may only be processed if the previous byte was also a U_FRAME_END_IND.
396  */
397  else if (!markerMode() || byte != U_FRAME_END_IND || (byte == U_FRAME_END_IND && _rxMarker))
398  {
399  // Reset the marker if active
400  _rxMarker = false;
401  // Accept the byte
402  _rxFrame->addByte(byte);
403 
404  // If the bus monitor has been started, no processing takes place - i.e. no ACKing
405  if (!_monitoring)
406  {
407  // If more than 7 bytes are available, you can check whether the frame is intended for "me".
408  if (_rxFrame->size() == 7)
409  {
410  // Check whether I am responsible for the frame
411  TPAckType ack = _cb.isAckRequired(_rxFrame->destination(), _rxFrame->isGroupAddress());
412 
413  if (_forceAck || ack)
414  {
415  /*
416  * Save the responsibility that this frame is to be processed further.
417  * Since there is no extra function apart from the isAckRequired, this is initially treated the same.
418  * A later differentiation (possibly for router mode) must then be looked at.
419  */
420 
421  _rxFrame->addFlags(TP_FRAME_FLAG_ADDRESSED);
422 
423  // Of course, this is only allowed if I am not sending myself, as you cannot ACK your own frames
424  if (_txState == TX_IDLE)
425  {
426  // Save that Acking should take place
427  _rxFrame->addFlags(TP_FRAME_FLAG_ACK);
428 
429  // and in the TPUart so that it can send the ACK
430  _platform.writeUart(U_ACK_REQ | ack);
431  }
432  }
433  }
434 
435 #ifdef USE_TP_RX_QUEUE
436 
437  // Now check whether the RxQueue still has space for Frame + Size (2) + Flags(1)
438  if (_rxFrame->size() == 8 && (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED))
439  {
440  if (availableInRxQueue() < (_rxFrame->size() + 3))
441  {
442  // Only if I am not sending myself
443  if (_txState == TX_IDLE)
444  {
445  _platform.writeUart(U_ACK_REQ | U_ACK_REQ_ADRESSED | U_ACK_REQ_BUSY);
446  }
447  }
448  }
449 
450 #endif
451  }
452  }
453 
454  /*
455  * If no marker mode is active, the frame must be checked to see if it is complete.
456  * isFull checks here whether the maxSize or the length specification of the frame has been exceeded!
457  * In both cases, the frame must be processed.
458  */
459  if (!markerMode() && (_rxFrame->isFull()))
460  {
461  processRxFrameComplete();
462  }
463 }
464 
465 /*
466  * Processes the current frame and checks whether it is complete and valid (checksum).
467  * If a frame is complete and valid, it is placed in the queue if it is intended for "me" and the mode is RX_IDLE again.
468  * Otherwise the frame is discarded as invalid and the status is RX_INVALID, as it is not guaranteed that subsequent bytes are control codes again.
469  * Exception in marker mode, here the status RX_INVALID is changed directly back to RX_IDLE at another point because
470  * it is then ensured that the frame has been broken at TP level.
471  */
472 void TpUartDataLinkLayer::processRxFrameComplete()
473 {
474  // If no frame is currently being edited, then cancel
475  if (!_rxFrame->size())
476  return;
477 
478  // Is the frame complete and valid
479  if (_rxFrame->isValid())
480  {
481  // When a frame has been sent
482  if (_txState == TX_FRAME)
483  {
484  // check whether the receive corresponds to this: comparison of the source address and destination address and start byte without taking the retry bit into account
485  if (!((_rxFrame->data(0) ^ _txFrame->data(0)) & ~0x20) && _rxFrame->destination() == _txFrame->destination() && _rxFrame->source() == _txFrame->source())
486  {
487  // and mark this accordingly
488  // println("MATCH");
489  _rxFrame->addFlags(TP_FRAME_FLAG_ECHO);
490  }
491 
492  // Now wait for the L_DATA_CON
493  }
494 
495  // if the frame is for me or i am in busmonitor mode then i want to process it further
496  if (_rxFrame->flags() & TP_FRAME_FLAG_ADDRESSED || _monitoring)
497  {
498  /*
499  * In bus monitor mode, you still have to wait for an Ack.
500  * Therefore, the status is changed here and jumps back before the real completion.
501  * As soon as another call is made (regardless of whether or not the frame has been acked), the frame is closed.
502  */
503  if (_monitoring && _rxState != RX_AWAITING_ACK)
504  {
505  _rxState = RX_AWAITING_ACK;
506  return;
507  }
508 
509  _rxProcessdFrameCounter++;
510  }
511  else
512  {
513  // Otherwise, discard the package and release the memory -> as it is not packed into the queue
514  _rxIgnoredFrameCounter++;
515  }
516 
517  // And ready for control codes again
518  _rxState = RX_IDLE;
519  }
520  else
521  {
522  /*
523  * If the frame is incomplete or invalid then switch to RX_INVALID mode as I cannot distinguish,
524  * whether it is a TPBus error or a UART error or a Timming error.
525  */
526  _rxInvalidFrameCounter++;
527  _rxFrame->addFlags(TP_FRAME_FLAG_INVALID);
528  _rxState = RX_INVALID; // ignore bytes
529  }
530 
531 #ifdef USE_TP_RX_QUEUE
532  pushRxFrameQueue();
533 #else
534  processRxFrame(_rxFrame);
535 #endif
536 
537  // resets the current frame pointer
538  _rxFrame->reset();
539 }
540 
541 void TpUartDataLinkLayer::clearTxFrame()
542 {
543  if (_txFrame != nullptr)
544  {
545  delete _txFrame;
546  _txFrame = nullptr;
547  }
548 }
549 
550 void TpUartDataLinkLayer::clearTxFrameQueue()
551 {
552 }
553 
554 void TpUartDataLinkLayer::processTxFrameComplete(bool success)
555 {
556  uint8_t* cemiData = _txFrame->cemiData();
557  CemiFrame cemiFrame(cemiData, _txFrame->cemiSize());
558  dataConReceived(cemiFrame, success);
559  free(cemiData);
560  clearTxFrame();
561  _txProcessdFrameCounter++;
562  _txState = TX_IDLE;
563 }
564 
565 /*
566  * Puts the frame to be sent into a queue, as the TpUart may not yet be ready to send.
567  */
568 void TpUartDataLinkLayer::pushTxFrameQueue(TpFrame* tpFrame)
569 {
570  knx_tx_queue_entry_t* entry = new knx_tx_queue_entry_t(tpFrame);
571 
572  if (_txFrameQueue.back == nullptr)
573  {
574  _txFrameQueue.front = _txFrameQueue.back = entry;
575  }
576  else
577  {
578  _txFrameQueue.back->next = entry;
579  _txFrameQueue.back = entry;
580  }
581 
582  _txQueueCount++;
583 }
584 
585 void TpUartDataLinkLayer::setRepetitions(uint8_t nack, uint8_t busy)
586 {
587  _repetitions = (nack & 0b111) | ((busy & 0b111) << 4);
588 }
589 
590 // Alias
591 void TpUartDataLinkLayer::setFrameRepetition(uint8_t nack, uint8_t busy)
592 {
593  setRepetitions(nack, busy);
594 }
595 
596 bool TpUartDataLinkLayer::sendFrame(CemiFrame& cemiFrame)
597 {
598  _txFrameCounter++;
599 
600  if (!_connected || _monitoring || _txQueueCount > MAX_TX_QUEUE)
601  {
602  if (_txQueueCount > MAX_TX_QUEUE)
603  {
604  println("Ignore frame because transmit queue is full!");
605  }
606 
607  dataConReceived(cemiFrame, false);
608  return false;
609  }
610 
611  TpFrame* tpFrame = new TpFrame(cemiFrame);
612  // printHex(" TP>: ", tpFrame->data(), tpFrame->size());
613  pushTxFrameQueue(tpFrame);
614  return true;
615 }
616 
617 /*
618  * The status should be queried regularly to detect a disconnect of the TPUart and its status.
619  * In addition, the current config or mode should be transmitted regularly so that after a disconnect,
620  * the TPUart is in the correct state.
621  */
622 void TpUartDataLinkLayer::requestState(bool force /* = false */)
623 {
624  if (!force)
625  {
626  if (!(_rxState == RX_IDLE || _rxState == RX_INVALID))
627  return;
628 
629  // Only 1x per second
630  if ((millis() - _lastStateRequest) < 1000)
631  return;
632  }
633 
634  // println("requestState");
635 
636  // Send configuration or mode
637  if (_monitoring)
638  _platform.writeUart(U_BUSMON_REQ);
639  else
640  requestConfig();
641 
642  // Question status on - if monitoring inactive
643  if (!_monitoring)
644  _platform.writeUart(U_STATE_REQ);
645 
646  _lastStateRequest = millis();
647 }
648 
649 /*
650  * Sends the current config to the chip
651  */
652 void TpUartDataLinkLayer::requestConfig()
653 {
654  // println("requestConfig");
655 #ifdef NCN5120
656  if (markerMode())
657  _platform.writeUart(U_CONFIGURE_REQ | U_CONFIGURE_MARKER_REQ);
658 
659 #endif
660 
661  // Set Address for AutoACK Unicast
662  const uint16_t address = _deviceObject.individualAddress();
663  _platform.writeUart(U_SET_ADDRESS_REQ);
664  _platform.writeUart((address >> 8) & 0xFF);
665  _platform.writeUart(address & 0xFF);
666 #ifdef NCN5120
667  _platform.writeUart(0xFF); // Dummy Byte needed by NCN only
668 #endif
669 
670  // Deviating Config
671  if (_repetitions != 0b00110011)
672  {
673 #ifdef NCN5120
674  _platform.writeUart(U_SET_REPETITION_REQ);
675  _platform.writeUart(_repetitions);
676  _platform.writeUart(0x0); // dummy, see NCN5120 datasheet
677  _platform.writeUart(0x0); // dummy, see NCN5120 datasheet
678 #else
679  _platform.writeUart(U_MXRSTCNT);
680  _platform.writeUart(((_repetitions & 0xF0) << 1) | (_repetitions & 0x0F));
681 #endif
682  }
683 }
684 
685 /*
686  * A simplified lock mechanism that only works on the same core.
687  * Perfect for ISR
688  */
689 bool TpUartDataLinkLayer::isrLock(bool blocking /* = false */)
690 {
691  if (blocking)
692  while (_rxProcessing)
693  ;
694  else if (_rxProcessing)
695  return false;
696 
697  _rxProcessing = true;
698  return true;
699 }
700 
701 void TpUartDataLinkLayer::isrUnlock()
702 {
703  _rxProcessing = false;
704 }
705 
706 void TpUartDataLinkLayer::clearUartBuffer()
707 {
708  // Clear rx queue
709  while (_platform.uartAvailable())
710  _platform.readUart();
711 }
712 
713 void TpUartDataLinkLayer::connected(bool state /* = true */)
714 {
715  if (state)
716  println("TP is connected");
717  else
718  println("TP is disconnected");
719 
720  _connected = state;
721 }
722 
724 {
725  _rxProcessdFrameCounter = 0;
726  _rxIgnoredFrameCounter = 0;
727  _rxInvalidFrameCounter = 0;
728  _rxInvalidFrameCounter = 0;
729  _rxUnkownControlCounter = 0;
730  _txFrameCounter = 0;
731  _txProcessdFrameCounter = 0;
732 }
733 
735 {
736  // println("Reset TP");
737  if (!_initialized)
738  {
739  _platform.setupUart();
740  _initialized = true;
741  }
742 
743  // Wait for isr & block isr
744  isrLock(true);
745 
746  // Reset
747  resetStats();
748  clearTxFrame();
749  clearTxFrameQueue();
750 
751  if (_rxFrame != nullptr)
752  {
753  _rxFrame->reset();
754  }
755 
756  _rxState = RX_IDLE;
757  _connected = false;
758  _stopped = false;
759  _monitoring = false;
760  _rxLastTime = 0;
761 
762  clearUartBuffer();
763 
764  _platform.writeUart(U_RESET_REQ);
765  bool success = false;
766 
767  const uint32_t start = millis();
768 
769  // During startup answer took up to 2ms and normal 1ms
770  do
771  {
772  const int byte = _platform.readUart();
773 
774  if (byte == -1)
775  continue; // empty
776 
777  if (byte & U_RESET_IND)
778  {
779  success = true;
780  break; // next run for U_CONFIGURE_IND
781  }
782  } while (!((millis() - start) >= 10));
783 
784  connected(success);
785 
786  if (success)
787  {
788  _lastStateRequest = 0; // Force
789  requestState(true);
790  _rxLastTime = millis();
791  }
792 
793  isrUnlock();
794  return success;
795 }
796 
798 {
799  _forceAck = true;
800 }
801 
803 {
804  if (!_initialized)
805  return;
806 
807  if (state && !_stopped)
808  _platform.writeUart(U_STOP_MODE_REQ);
809  else if (!state && _stopped)
810  _platform.writeUart(U_EXIT_STOP_MODE_REQ);
811 
812  _stopped = state;
813 }
814 
816 {
817  if (state && !_busy)
818  _platform.writeUart(U_SET_BUSY_REQ);
819  else if (!state && _busy)
820  _platform.writeUart(U_QUIT_BUSY_REQ);
821 
822  _busy = state;
823 }
824 
826 {
827  if (!_initialized || _monitoring)
828  return;
829 
830  // println("busmonitor");
831  _monitoring = true;
832  _platform.writeUart(U_BUSMON_REQ);
833  resetStats();
834 }
835 
837 {
838  // After an unusual device restart, perform a reset, as the TPUart may still be in an incorrect state.
839  if (!_initialized)
840  reset();
841 
842  stop(!value);
843 }
844 
846 {
847  return _initialized && _connected;
848 }
849 
850 /*
851  * If a TxFrame has been sent, a confirmation for the transmission is expected.
852  * However, if there was an invalid frame or bus disconnect, the confirmation is not received and the STack is stuck in the TX_FRAME.
853  * The wait must therefore be ended after a short waiting time.
854  */
855 void TpUartDataLinkLayer::clearOutdatedTxFrame()
856 {
857  if (_txState == TX_FRAME && (millis() - _txLastTime) > 1000)
858  processTxFrameComplete(false);
859 }
860 
861 /*
862  * Here the outgoing frames are taken from the queue and sent.
863  * This only happens one at a time, as after each frame it is necessary to wait until the frame has come in again and the L_DATA_CON comes in.
864  *
865  */
866 void TpUartDataLinkLayer::processTxQueue()
867 {
868  if (_txState != TX_IDLE)
869  return;
870 
871  if (_txFrameQueue.front != nullptr)
872  {
873  knx_tx_queue_entry_t* entry = _txFrameQueue.front;
874  _txFrameQueue.front = entry->next;
875 
876  if (_txFrameQueue.front == nullptr)
877  {
878  _txFrameQueue.back = nullptr;
879  }
880 
881  _txQueueCount--;
882 
883  clearTxFrame();
884 
885  // use frame from queue and delete queue entry
886  _txFrame = entry->frame;
887  delete entry;
888 
889  _txState = TX_FRAME;
890  _txLastTime = millis();
891 
892 #ifdef DEBUG_TP_FRAMES
893  print("Outbound: ");
894  printFrame(_txFrame);
895  println();
896 #endif
897 
898  processTxFrameBytes();
899  }
900 }
901 
902 /*
903  * Check whether I have not received any data for too long and set the status to not connected.
904  * In normal mode, the status is requested every second. A short time can therefore be selected here.
905  * In monitoring mode there are actual frames, so a longer time is used here.
906  * Nevertheless, there are suspected disconnects with larger data volumes, so the RxQueue is also taken into account.
907  */
908 void TpUartDataLinkLayer::checkConnected()
909 {
910  if (!isrLock())
911  return;
912 
913  const uint32_t current = millis();
914 
915  if (_connected)
916  {
917  // 5000 instead 3000 because siemens tpuart
918  const uint32_t timeout = _monitoring ? 10000 : 5000;
919 
920  if ((current - _rxLastTime) > timeout)
921  {
922  connected(false);
923  }
924  }
925  else
926  {
927  if (_rxLastTime > 0 && (current - _rxLastTime) < 1000)
928  connected();
929  }
930 
931  isrUnlock();
932 }
933 
935 {
936  if (!_initialized)
937  return;
938 
939  /*
940  * If an overflow has been detected, change to RX_INVALID.
941  * However, this only applies in the loop and not in ISR. But when using ISR and DMA, this should never happen.
942  */
943  if (_rxOverflow)
944  {
945  println("TPUart overflow detected!");
946  _rxOverflow = false;
947  _rxState = RX_INVALID;
948  }
949 
950  if (_tpState)
951  {
952  print("TPUart state error: ");
953  println(_tpState, 2);
954  _tpState = 0;
955  }
956 
957  processRx();
958 #ifdef USE_TP_RX_QUEUE
959  processRxQueue();
960 #endif
961 
962  requestState();
963  clearOutdatedTxFrame();
964  processTxQueue();
965  checkConnected();
966 }
967 
968 void TpUartDataLinkLayer::rxFrameReceived(TpFrame* tpFrame)
969 {
970  uint8_t* cemiData = tpFrame->cemiData();
971  CemiFrame cemiFrame(cemiData, tpFrame->cemiSize());
972  // printHex(" TP<: ", tpFrame->data(), tpFrame->size());
973  // printHex(" CEMI<: ", cemiFrame.data(), cemiFrame.dataLength());
974 
975 #ifdef KNX_ACTIVITYCALLBACK
976 
977  if (_dllcb)
978  _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_RECV << KNX_ACTIVITYCALLBACK_DIR));
979 
980 #endif
981 
982  frameReceived(cemiFrame);
983  free(cemiData);
984 }
985 
987 {
988  return DptMedium::KNX_TP1;
989 }
990 
991 /*
992  * This can be used to switch the power supply to the V20V (VCC2)
993  */
994 #ifdef NCN5120
996 {
997  _platform.writeUart(U_INT_REG_WR_REQ_ACR0);
998 
999  if (state)
1000  _platform.writeUart(ACR0_FLAG_DC2EN | ACR0_FLAG_V20VEN | ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT);
1001  else
1002  _platform.writeUart(ACR0_FLAG_XCLKEN | ACR0_FLAG_V20VCLIMIT);
1003 }
1004 #endif
1005 
1006 bool TpUartDataLinkLayer::processTxFrameBytes()
1007 {
1008  // println("processTxFrameBytes");
1009 
1010  /*
1011  * Each frame must be introduced with a U_L_DATA_START_REQ and each subsequent byte with a further position byte (6bit).
1012  * Since the position byte consists of the U_L_DATA_START_REQ + position and we start with 0 anyway, a further distinction is not necessary.
1013  * distinction is not necessary.
1014  *
1015  * However, the last byte (checksum) uses the U_L_DATA_END_REQ + position!
1016  * In addition, there is another special feature for extended frames up to 263 bytes long, the 6 bits are no longer sufficient.
1017  * Here a U_L_DATA_OFFSET_REQ + Position (3bit) must be prefixed. This means that 9 bits are available for the position.
1018  */
1019  for (uint16_t i = 0; i < _txFrame->size(); i++)
1020  {
1021  uint8_t offset = (i >> 6);
1022  uint8_t position = (i & 0x3F);
1023 
1024  if (offset)
1025  {
1026  // position++;
1027  _platform.writeUart(U_L_DATA_OFFSET_REQ | offset);
1028  }
1029 
1030  if (i == (_txFrame->size() - 1)) // Last bytes (checksum)
1031  _platform.writeUart(U_L_DATA_END_REQ | position);
1032  else
1033  _platform.writeUart(U_L_DATA_START_REQ | position);
1034 
1035  _platform.writeUart(_txFrame->data(i));
1036  }
1037 
1038 #ifdef KNX_ACTIVITYCALLBACK
1039 
1040  if (_dllcb)
1041  _dllcb->activity((_netIndex << KNX_ACTIVITYCALLBACK_NET) | (KNX_ACTIVITYCALLBACK_DIR_SEND << KNX_ACTIVITYCALLBACK_DIR));
1042 
1043 #endif
1044 
1045  return true;
1046 }
1047 
1049  NetworkLayerEntity& netLayerEntity,
1050  Platform& platform,
1051  ITpUartCallBacks& cb,
1052  DataLinkLayerCallbacks* dllcb)
1053  : DataLinkLayer(devObj, netLayerEntity, platform),
1054  _cb(cb),
1055  _dllcb(dllcb)
1056 {
1057  _rxFrame = new TpFrame(MAX_KNX_TELEGRAM_SIZE);
1058 }
1059 
1060 /*
1061  * Returns the number of frames that could not be processed.
1062  */
1064 {
1065  return _rxInvalidFrameCounter;
1066 }
1067 
1068 /*
1069  * Returns the number of frames that are valid and intended for the device
1070  */
1072 {
1073  return _rxProcessdFrameCounter;
1074 }
1075 
1076 /*
1077  * Returns the number of frames that are valid but not intended for the device
1078  */
1080 {
1081  return _rxIgnoredFrameCounter;
1082 }
1083 
1084 /*
1085  * Returns the number of control bytes counted that were not recognized
1086  */
1088 {
1089  return _rxUnkownControlCounter;
1090 }
1091 
1092 /*
1093  * Returns the number of frames sent
1094  */
1096 {
1097  return _txFrameCounter;
1098 }
1099 /*
1100  * Returns the number of frames sent
1101  */
1103 {
1104  return _txProcessdFrameCounter;
1105 }
1106 
1108 {
1109  return _connected;
1110 }
1111 
1113 {
1114  return _stopped;
1115 }
1116 
1118 {
1119  return _busy;
1120 }
1121 
1123 {
1124  return _monitoring;
1125 }
1126 
1127 bool TpUartDataLinkLayer::markerMode()
1128 {
1129  if (_monitoring)
1130  return false;
1131 
1132 #ifdef NCN5120
1133  // return true;
1134 #endif
1135 
1136  return false;
1137 }
1138 
1139 void TpUartDataLinkLayer::processRxFrame(TpFrame* tpFrame)
1140 {
1141  if (_monitoring)
1142  {
1143  print("Monitor: ");
1144  printFrame(tpFrame);
1145  println();
1146  }
1147  else if (tpFrame->flags() & TP_FRAME_FLAG_INVALID)
1148  {
1149  print("\x1B[");
1150  print(31);
1151  print("m");
1152  print("Invalid: ");
1153  printFrame(tpFrame);
1154  print("\x1B[");
1155  print(0);
1156  println("m");
1157  }
1158  else if (tpFrame->flags() & TP_FRAME_FLAG_ADDRESSED)
1159  {
1160 #ifdef DEBUG_TP_FRAMES
1161  print("Inbound: ");
1162  printFrame(tpFrame);
1163  println();
1164 #endif
1165 
1166  if (!(tpFrame->flags() & TP_FRAME_FLAG_ECHO))
1167  rxFrameReceived(tpFrame);
1168  }
1169 }
1170 
1171 #ifdef USE_TP_RX_QUEUE
1172 /*
1173  * This method allows the processing of the incoming bytes to be handled additionally via an interrupt (ISR).
1174  * The prerequisite is that the interrupt runs on the same core as the knx.loop!
1175  *
1176  * With an RP2040 where the ISR is also locked when a block is erased,
1177  * processing can be caught up between the erases. This significantly minimizes the risk of frame losses.
1178  */
1179 void __isr __time_critical_func(TpUartDataLinkLayer::processRxISR)()
1180 {
1181  processRx(true);
1182 }
1183 
1184 /*
1185  * Puts the received frame into a queue. This queue is necessary,
1186  * because a frame can optionally be received via an ISR and processing must still take place normally in the knx.loop.
1187  * In addition, this queue is statically preallocated, as no malloc etc. can be made in an ISR.
1188  */
1189 void TpUartDataLinkLayer::pushRxFrameQueue()
1190 {
1191  if (availableInRxQueue() < (_rxFrame->size() + 3))
1192  return;
1193 
1194  // Payloadsize (2 byte)
1195  pushByteToRxQueue(_rxFrame->size() & 0xFF);
1196  pushByteToRxQueue(_rxFrame->size() >> 8);
1197  // Paylodflags (1 byte)
1198  pushByteToRxQueue(_rxFrame->flags());
1199 
1200  for (size_t i = 0; i < _rxFrame->size(); i++)
1201  {
1202  pushByteToRxQueue(_rxFrame->data(i));
1203  }
1204 
1205  asm volatile("" ::: "memory");
1206  _rxBufferCount++;
1207 }
1208 
1209 void TpUartDataLinkLayer::processRxQueue()
1210 {
1211  if (!isrLock())
1212  return;
1213 
1214  while (_rxBufferCount)
1215  {
1216  const uint16_t size = pullByteFromRxQueue() + (pullByteFromRxQueue() << 8);
1217  TpFrame tpFrame = TpFrame(size);
1218  tpFrame.addFlags(pullByteFromRxQueue());
1219 
1220  for (uint16_t i = 0; i < size; i++)
1221  tpFrame.addByte(pullByteFromRxQueue());
1222 
1223  processRxFrame(&tpFrame);
1224  asm volatile("" ::: "memory");
1225  _rxBufferCount--;
1226  }
1227 
1228  isrUnlock();
1229 }
1230 
1231 void TpUartDataLinkLayer::pushByteToRxQueue(uint8_t byte)
1232 {
1233  _rxBuffer[_rxBufferFront] = byte;
1234  _rxBufferFront = (_rxBufferFront + 1) % (MAX_RX_QUEUE_BYTES);
1235 }
1236 
1237 uint8_t TpUartDataLinkLayer::pullByteFromRxQueue()
1238 {
1239  uint8_t byte = _rxBuffer[_rxBufferRear];
1240  _rxBufferRear = (_rxBufferRear + 1) % (MAX_RX_QUEUE_BYTES);
1241  return byte;
1242 }
1243 
1244 uint16_t TpUartDataLinkLayer::availableInRxQueue()
1245 {
1246  return ((_rxBufferFront == _rxBufferRear) ? (MAX_RX_QUEUE_BYTES) : ((((MAX_RX_QUEUE_BYTES) - _rxBufferFront) + _rxBufferRear) % (MAX_RX_QUEUE_BYTES))) - 1;
1247 }
1248 #endif
1249 
1250 #endif
void print(const char *s)
void println(const char *s)
void printHex(const char *suffix, const uint8_t *data, size_t length, bool newline)
Definition: bits.cpp:12
uint32_t millis()
uint16_t individualAddress()
virtual TPAckType isAckRequired(uint16_t address, bool isGrpAddr)=0
virtual int readUart()
Definition: platform.cpp:34
virtual int uartAvailable()
Definition: platform.cpp:49
virtual size_t writeUart(const uint8_t data)
Definition: platform.cpp:44
virtual void setupUart()
Definition: platform.cpp:57
bool isGroupAddress()
Definition: tp_frame.h:238
std::string humanDestination()
Definition: tp_frame.h:186
uint16_t source()
Definition: tp_frame.h:173
bool isFull()
Definition: tp_frame.h:156
uint8_t * cemiData()
Creates a buffer and converts the TpFrame into a CemiFrame.
Definition: tp_frame.h:256
uint16_t cemiSize()
Definition: tp_frame.h:247
uint16_t flags()
Definition: tp_frame.h:113
void addByte(uint8_t byte)
Definition: tp_frame.h:89
uint8_t * data()
Definition: tp_frame.h:129
std::string humanSource()
Definition: tp_frame.h:178
bool isValid()
Definition: tp_frame.h:283
void addFlags(uint8_t flags)
Definition: tp_frame.h:121
uint16_t destination()
Definition: tp_frame.h:203
void reset()
Definition: tp_frame.h:145
uint16_t size()
Definition: tp_frame.h:105
DptMedium
Definition: knx_types.h:254
@ KNX_TP1
Definition: knx_types.h:257
TPAckType
Definition: knx_types.h:24