From ddc6396f2f80e2b6f3163139de26b9263384b6ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Anian=20B=C3=BChler?=
 <anian.buehler@reutlingen-university.de>
Date: Fri, 15 Nov 2024 11:08:18 +0100
Subject: [PATCH] separated classes into different files

---
 src/Detector.cpp            |  43 +++
 src/Detector.h              |  29 ++
 src/DidacticNet.cpp         | 751 +-----------------------------------
 src/DidacticNet.h           | 243 +-----------
 src/DidacticNetPSN.cpp      | 473 +++++++++++++++++++++++
 src/DidacticNetPSN.h        | 124 ++++++
 src/DidacticNetTransmit.cpp | 167 ++++++++
 src/DidacticNetTransmit.h   |  65 ++++
 src/SerialUI.cpp            |  74 ++++
 src/SerialUI.h              |  48 +++
 src/UnblockingTimer.cpp     |  23 ++
 src/UnblockingTimer.h       |  22 ++
 12 files changed, 1076 insertions(+), 986 deletions(-)
 create mode 100644 src/Detector.cpp
 create mode 100644 src/Detector.h
 create mode 100644 src/DidacticNetPSN.cpp
 create mode 100644 src/DidacticNetPSN.h
 create mode 100644 src/DidacticNetTransmit.cpp
 create mode 100644 src/DidacticNetTransmit.h
 create mode 100644 src/SerialUI.cpp
 create mode 100644 src/SerialUI.h
 create mode 100644 src/UnblockingTimer.cpp
 create mode 100644 src/UnblockingTimer.h

diff --git a/src/Detector.cpp b/src/Detector.cpp
new file mode 100644
index 0000000..eb6b41e
--- /dev/null
+++ b/src/Detector.cpp
@@ -0,0 +1,43 @@
+/**************************************************************************/
+/*!
+    @file     ChangeDetector.cpp
+    @author   anian buehler @ letsgoING.org
+*/
+/**************************************************************************/
+
+#include "Detector.h"
+
+EdgeDetector::EdgeDetector() {};
+EdgeDetector::~EdgeDetector() {};
+
+int EdgeDetector::edgeDetected(bool currentState)
+{
+    static bool lastState = false;
+    int edEdge = 0;
+
+    if (currentState && !lastState)
+    {
+        edEdge = RISING;
+    }
+    else if (!currentState && lastState)
+    {
+        edEdge = FALLING;
+    }
+    lastState = currentState;
+    return edEdge;
+}
+
+ChangeDetector::ChangeDetector() {}
+ChangeDetector::~ChangeDetector() {}
+
+bool ChangeDetector::valueChanged(int value, int threshold)
+{
+    static int lastValue = 0;
+
+    if (abs(value - lastValue) > threshold)
+    {
+        lastValue = value;
+        return true;
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/Detector.h b/src/Detector.h
new file mode 100644
index 0000000..e86e7e3
--- /dev/null
+++ b/src/Detector.h
@@ -0,0 +1,29 @@
+/**************************************************************************
+    @file     ChangeDetector.h
+    @author   anian buehler @ letsgoING
+**************************************************************************/
+
+#ifndef _LGI_DETECTOR_
+#define _LGI_DETECTOR_
+
+#include "Arduino.h"
+
+class EdgeDetector
+{
+private:
+public:
+    EdgeDetector();
+    ~EdgeDetector();
+    int edgeDetected(bool);
+};
+
+class ChangeDetector
+{
+private:
+public:
+    ChangeDetector();
+    ~ChangeDetector();
+    bool valueChanged(int, int);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/DidacticNet.cpp b/src/DidacticNet.cpp
index a673d40..a3cf43c 100644
--- a/src/DidacticNet.cpp
+++ b/src/DidacticNet.cpp
@@ -3,753 +3,4 @@
     @file     DidacticNet.cpp
     @author   anian buehler @ letsgoING.org
 */
-/**************************************************************************/
-
-#include "Arduino.h"
-#include "DidacticNet.h"
-
-//**************************************************************************
-// ROOT
-//**************************************************************************
-DidacticPSNet::DidacticPSNet() {}
-
-DidacticPSNet::~DidacticPSNet() {}
-
-void DidacticPSNet::begin(Stream &_port)
-{
-  setStream(_port);
-}
-
-void DidacticPSNet::begin(Stream &_port, PSNET_CALLBACK_SIGNATURE)
-{
-  setStream(_port);
-  setCallback(callback);
-}
-
-DidacticPSNet &DidacticPSNet::setCallback(PSNET_CALLBACK_SIGNATURE)
-{
-  this->callback = callback;
-  return *this;
-}
-
-void DidacticPSNet::setStream(Stream &stream)
-{
-  _port = &stream;
-}
-
-bool DidacticPSNet::handleNetwork()
-{
-  if (checkData())
-  {
-    if (recieveData())
-    {
-      if (getMessageFilter(_readBufferMessage[1]))
-      {
-        handleData();
-      }
-    }
-    _waitingTimeCSMA = millis() + random(CSMA_MIN_DELAY_MS, CSMA_MAX_DELAY_MS);
-  }
-  if (_dataToSend && _waitingTimeSend <= millis() && _waitingTimeCSMA <= millis())
-  {
-    // send data to network
-    unsigned long delayStartTime = micros();
-    while (micros() < delayStartTime + CSMA_CHECK_DELAY_US)
-      ;
-    if (!checkData())
-    {
-      if (sendData())
-      {
-        _dataToSend = false;
-        _waitingTimeSend = millis() + _intervalTime;
-      }
-    }
-  }
-  return !_dataToSend; // return true if sending is done
-}
-
-bool DidacticPSNet::isDataToSend()
-{
-  return _dataToSend;
-}
-
-bool DidacticPSNet::sendData()
-{
-  int counter = 0;
-  bool messageSent = false;
-  while (!messageSent)
-  {
-    if (counter >= MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD - 1)
-    {
-      _sendBufferMessage[counter] = MSG_DELIMITER; // cut message and stop sending
-      messageSent = true;
-    }
-    else if (_sendBufferMessage[counter] == MSG_DELIMITER)
-    {
-      messageSent = true;
-    }
-
-    _port->write(_sendBufferMessage[counter]);
-    counter++;
-  }
-  return true;
-}
-
-int DidacticPSNet::extractData(int startCounter, int maxLength, char *buffer, char limiter)
-{
-  int counter = startCounter;
-  while (_readBufferMessage[counter] != limiter)
-  {
-    buffer[counter - startCounter] = _readBufferMessage[counter];
-    counter++;
-    if ((counter - startCounter) > maxLength)
-    {
-      counter--;
-      break; // if > maxLenght -> leave while and return
-    }
-  }
-  buffer[counter - startCounter] = '\0';
-  return counter - startCounter; // length
-}
-
-int DidacticPSNet::checkData()
-{
-  return (int)_port->available();
-}
-
-bool DidacticPSNet::recieveData()
-{
-  static int msgCounter = 0;
-  static int topicCounter = 0;
-  static int payloadCounter = 0;
-
-  while (checkData())
-  {
-    char localBuffer = _port->read();
-    if (localBuffer == MSG_PRELIMITER)
-    {
-      msgCounter = 0;
-      topicCounter = 0;
-      payloadCounter = 0;
-      _readBufferMessage[msgCounter] = localBuffer;
-    }
-    else if (localBuffer == MSG_DELIMITER && _readBufferMessage[0] == MSG_PRELIMITER)
-    {
-      msgCounter++;
-      _readBufferMessage[msgCounter] = localBuffer;
-      _readBufferMessage[msgCounter + 1] = '0';
-      msgCounter = 0;
-      return true;
-    }
-    else if (localBuffer == MSG_SEPARATOR && _readBufferMessage[0] == MSG_PRELIMITER)
-    {
-      topicCounter = msgCounter - 2;
-      msgCounter++;
-      _readBufferMessage[msgCounter] = localBuffer;
-    }
-    else if (_readBufferMessage[0] == MSG_PRELIMITER && localBuffer != MSG_DELIMITER)
-    {
-      if (msgCounter > LEN_OVERHEAD + MAX_LEN_TOPICS + MAX_LEN_PAYLOAD)
-      {
-        msgCounter == 0;
-        _readBufferMessage[0] = '\0';
-      }
-      else
-      {
-        msgCounter++;
-        _readBufferMessage[msgCounter] = localBuffer;
-      }
-    }
-  }
-  return false;
-}
-
-void DidacticPSNet::setInterval(long intervalTime)
-{
-  _intervalTime = intervalTime;
-}
-
-//**************************************************************************
-// CLIENT
-//**************************************************************************
-DidacticPSNetClient::~DidacticPSNetClient() {}
-
-// NEW easy interface for non advanced users
-// ##########################################
-void DidacticPSNetClient::begin(Stream &_port) // TODO: check if CLientMode is necessary or an unset callback ist not a problem
-{
-  DidacticPSNet::begin(_port);
-  _clientMode = CLIENT_MODE_BASIC;
-}
-
-void DidacticPSNetClient::begin(Stream &_port, PSNET_CALLBACK_SIGNATURE)
-{
-  DidacticPSNet::begin(_port, callback);
-}
-
-bool DidacticPSNetClient::available()
-{
-  return _newMessageAvailable;
-}
-
-int DidacticPSNetClient::readLatestTopicNr()
-{
-  return _newMessageTopicNr;
-}
-
-void DidacticPSNetClient::readTopic(int topicNr, char *topic)
-{
-  strcpy(topic, _topic[topicNr]);
-}
-
-void DidacticPSNetClient::readTopic(char *topic)
-{
-  readTopic(_newMessageTopicNr, topic);
-}
-
-void DidacticPSNetClient::readPayload(int topicNr, char *payload)
-{
-  strcpy(payload, _payload[topicNr]);
-
-  if (topicNr == _newMessageTopicNr)
-  {
-    _newMessageAvailable = false;
-  }
-}
-
-void DidacticPSNetClient::readPayload(char *payload)
-{
-  readPayload(_newMessageTopicNr, payload);
-}
-
-void DidacticPSNetClient::readPayload(char *topic, char *payload)
-{
-  int topicNr = getTopicNr(topic);
-  if (topicNr == _newMessageTopicNr)
-  {
-    _newMessageAvailable = false;
-  }
-  readPayload(topicNr, payload);
-}
-
-bool DidacticPSNetClient::readBooleanPayload()
-{
-  _newMessageAvailable = false;
-  return _payload[_newMessageTopicNr][0] == '1';
-}
-
-int DidacticPSNetClient::readIntegerPayload()
-{
-  _newMessageAvailable = false;
-  return atoi(_payload[_newMessageTopicNr]);
-}
-// ##########################################
-
-DidacticPSNetClient::DidacticPSNetClient()
-{
-  _intervalTime = INTERVAL_CLIENT;
-}
-
-int DidacticPSNetClient::publish(char *topic, char *payload)
-{
-  return publish(topic, strlen(topic), payload, strlen(payload));
-}
-
-int DidacticPSNetClient::publish(char *topic, int topicLength, char *payload, int payloadLength)
-{
-  int error = DN_PUBLISH_SUCCESSULL;
-
-  _sendBufferMessage[0] = MSG_PRELIMITER;
-  _sendBufferMessage[1] = MSG_PUBLISH;
-  _sendBufferMessage[2 + topicLength] = MSG_SEPARATOR;
-  _sendBufferMessage[2 + topicLength + 1 + payloadLength] = MSG_DELIMITER;
-  _sendBufferMessage[2 + topicLength + 1 + payloadLength + 1] = '\0';
-
-  // TODO: check
-  if (topicLength > MAX_LEN_TOPICS)
-  {
-    topicLength = MAX_LEN_TOPICS;
-    error += DN_ERROR_TOPIC_LEN;
-  }
-  if (payloadLength > MAX_LEN_PAYLOAD)
-  {
-    payloadLength = MAX_LEN_PAYLOAD;
-    error += DN_ERROR_PAYLOAD_LEN;
-  }
-
-  for (int i = 0; i < topicLength; i++)
-  {
-    _sendBufferMessage[2 + i] = topic[i];
-  }
-  for (int i = 0; i < payloadLength; i++)
-  {
-    _sendBufferMessage[2 + topicLength + 1 + i] = payload[i];
-  }
-
-  _dataToSend = true;
-  return error;
-}
-
-int DidacticPSNetClient::publish(char *topic, int data)
-{
-  char sendPayload[MAX_LEN_PAYLOAD];
-  itoa(data, sendPayload, 10);
-
-  return publish(topic, sendPayload);
-}
-
-int DidacticPSNetClient::publish(char *topic, bool data)
-{
-  char sendPayload[2];
-  itoa(data, sendPayload, 10);
-
-  return publish(topic, sendPayload);
-}
-
-int DidacticPSNetClient::publishOnChange(char *topic, bool input)
-{
-  if (!_dataToSend)
-  {
-    if (eDetector.edgeDetected(input))
-    {
-      return publish(topic, input);
-    }
-  }
-  return DN_ERROR_NO_ERROR;
-}
-
-int DidacticPSNetClient::publishOnChange(char *topic, int input, int threshold)
-{
-  if (!_dataToSend)
-  {
-    if (cDetector.valueChanged(input, threshold))
-    {
-      return publish(topic, input);
-    }
-  }
-  return DN_ERROR_NO_ERROR;
-}
-
-int DidacticPSNetClient::subscribe(char *topic)
-{
-  return subscribe(topic, strlen(topic));
-}
-
-int DidacticPSNetClient::subscribe(char *topic, int topicLength)
-{
-  int error = DN_ERROR_NO_ERROR;
-
-  if (topicLength > MAX_LEN_TOPICS)
-  {
-    topicLength = MAX_LEN_TOPICS;
-    error = DN_ERROR_TOPIC_LEN;
-  }
-
-  _sendBufferMessage[0] = MSG_PRELIMITER;
-  _sendBufferMessage[1] = MSG_SUBSCRIBE;
-  _sendBufferMessage[2 + topicLength] = MSG_DELIMITER;
-
-  int topicNumber = getTopicNr(topic);
-
-  if (topicNumber < 0)
-  {
-    topicNumber = getFreeTopicNr();
-    if (topicNumber < 0)
-    {
-      topicNumber = 0;
-    }
-    for (int i = 0; i < topicLength; i++)
-    {
-      _topic[topicNumber][i] = topic[i];
-      _sendBufferMessage[2 + i] = topic[i];
-    }
-    _topic[topicNumber][topicLength] = '\0';
-    _sendBufferMessage[2 + topicLength + 1] = '\0';
-    _dataToSend = true;
-  }
-  else
-  {
-    for (int i = 0; i < topicLength; i++)
-    {
-      _sendBufferMessage[2 + i] = topic[i];
-    }
-    _sendBufferMessage[2 + topicLength + 1] = '\0';
-    _dataToSend = true;
-  }
-  while (_dataToSend)
-  {
-    handleNetwork();
-  }
-  return error;
-}
-
-bool DidacticPSNetClient::unsubscribe(char *topic)
-{
-  return unsubscribe(topic, strlen(topic));
-}
-
-bool DidacticPSNetClient::unsubscribe(char *topic, int topicLength)
-{
-  int topicNumber = getTopicNr(topic);
-  if (topicNumber >= 0)
-  {
-    _topic[topicNumber][0] = '\0';
-    return true;
-  }
-  return false;
-}
-
-bool DidacticPSNetClient::getMessageFilter(char messageType)
-{
-  return messageType == MSG_UPDATE;
-}
-
-bool DidacticPSNetClient::savePayload(char *buffer, int position)
-{
-  strcpy(_payload[position], buffer);
-  return true;
-}
-
-bool DidacticPSNetClient::handleData()
-{
-  int currentTopicNr = 0;
-  int topicLength = 0;
-  int payloadLength = 0;
-  topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_SEPARATOR);
-  if (topicLength > 0)
-  {
-    currentTopicNr = getTopicNr(_bufferTopic);
-    payloadLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER);
-    if (currentTopicNr >= 0)
-    {
-      savePayload(_bufferPayload, currentTopicNr);
-      _newMessageAvailable = true;
-      _newMessageTopicNr = currentTopicNr;
-
-      if (_clientMode == CLIENT_MODE_ADVANCED)
-      {
-#ifdef CALLBACK_W_LENGTH
-        callback(_bufferTopic, topicLength, _bufferPayload, payloadLength);
-#else
-        callback(_bufferTopic, _bufferPayload);
-#endif
-      }
-    }
-  }
-  return true;
-}
-
-int DidacticPSNetClient::getTopicNr(char *topic)
-{
-  for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++)
-  {
-    if (strcmp(_topic[i], topic) == 0 || _topic[i][0] == MSG_TOPIC_MULTI)
-    {
-      return i;
-    }
-  }
-  return -1;
-}
-
-int DidacticPSNetClient::getFreeTopicNr()
-{
-  for (int i = 0; i < MAX_NR_TOPICS_CLIENT; i++)
-  {
-    if (strcmp(_topic[i], "") == 0)
-    {
-      return i;
-    }
-  }
-  return -1;
-}
-
-int DidacticPSNetClient::getSubscribedTopic(char *topic, int number)
-{
-  if (number > 0 && number < getMaxNrTopics())
-  {
-    strcpy(topic, _topic[number]);
-    return DN_ERROR_NO_ERROR;
-  }
-  return DN_ERROR_NO_TOPIC;
-}
-
-int DidacticPSNetClient::getMaxNrTopics()
-{
-  return getFreeTopicNr();
-}
-
-//**************************************************************************
-// Broker
-//**************************************************************************
-DidacticPSNetBroker::DidacticPSNetBroker()
-{
-  _intervalTime = INTERVAL_BROKER;
-}
-
-DidacticPSNetBroker::~DidacticPSNetBroker() {}
-
-bool DidacticPSNetBroker::getMessageFilter(char messageType)
-{
-  return (messageType == MSG_PUBLISH || messageType == MSG_SUBSCRIBE);
-}
-
-bool DidacticPSNetBroker::savePayload(char *buffer, int position)
-{
-  strcpy(_data[position], buffer);
-  return true;
-}
-
-void DidacticPSNetBroker::writeDataToTopic(int topicNumber, char *usedTopic, char *newData)
-{
-  if (strcmp(_topic[topicNumber], "") == 0)
-  {
-    strcpy(_topic[topicNumber], usedTopic);
-  }
-  strcpy(_data[topicNumber], newData);
-}
-
-bool DidacticPSNetBroker::handleData()
-{
-  int currentTopicNr = 0;
-  int topicLength = 0;
-  int dataLength = 0;
-
-  printVerbose(_readBufferMessage);
-
-  if (_readBufferMessage[1] == MSG_PUBLISH)
-  {
-    topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_SEPARATOR);
-    if (topicLength > 0)
-    {
-      currentTopicNr = getTopicNr(_bufferTopic);
-      dataLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, MSG_DELIMITER);
-      if (currentTopicNr >= 0)
-      {
-        writeDataToTopic(currentTopicNr, _bufferTopic, _bufferPayload);
-        update(_topic[currentTopicNr], topicLength, _data[currentTopicNr], dataLength);
-      }
-    }
-  }
-  else if (_readBufferMessage[1] == MSG_SUBSCRIBE)
-  {
-    topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, MSG_DELIMITER);
-    if (topicLength > 0)
-    {
-      currentTopicNr = getTopicNr(_bufferTopic);
-      if (currentTopicNr >= 0)
-      {
-        update(_topic[currentTopicNr], strlen(_topic[currentTopicNr]), _data[currentTopicNr], strlen(_data[currentTopicNr]));
-      }
-    }
-  }
-  return true;
-}
-
-bool DidacticPSNetBroker::update(char *topic, int topicLength, char *data, int dataLength)
-{
-  _sendBufferMessage[0] = MSG_PRELIMITER;
-  _sendBufferMessage[1] = MSG_UPDATE;
-  _sendBufferMessage[2 + topicLength] = MSG_SEPARATOR;
-  _sendBufferMessage[2 + topicLength + 1 + dataLength] = MSG_DELIMITER;
-  _sendBufferMessage[2 + topicLength + 1 + dataLength + 1] = '\0';
-
-  if (topicLength <= MAX_LEN_TOPICS)
-  {
-    for (int i = 0; i < topicLength; i++)
-    {
-      _sendBufferMessage[2 + i] = topic[i];
-    }
-  }
-  else
-  {
-    _dataToSend = false;
-    return false;
-  }
-  if (dataLength <= MAX_LEN_PAYLOAD)
-  {
-    for (int i = 0; i < dataLength; i++)
-    {
-      _sendBufferMessage[2 + topicLength + 1 + i] = data[i];
-    }
-  }
-  else
-  {
-    _dataToSend = false;
-    return false;
-  }
-  _dataToSend = true;
-  return true;
-}
-
-int DidacticPSNetBroker::getTopicNr(char *topic)
-{
-  for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++)
-  {
-    if (strcmp(_topic[i], topic) == 0)
-    {
-      return i;
-    }
-  }
-  return getFreeTopicNr();
-}
-
-int DidacticPSNetBroker::getFreeTopicNr()
-{
-  for (int i = 0; i < MAX_NR_TOPICS_BROKER; i++)
-  {
-    if (strcmp(_topic[i], "") == 0)
-    {
-      return i;
-    }
-  }
-  return -1;
-}
-
-void DidacticPSNetBroker::setVerbose(Stream &verbosePort)
-{
-  _isVerbose = true;
-  _verbosePort = &verbosePort;
-}
-
-void DidacticPSNetBroker::setNoneVerbose()
-{
-  _isVerbose = false;
-}
-
-bool DidacticPSNetBroker::printVerbose(char *recievedData)
-{
-  char signBuffer = 0;
-  int signCounter = 0;
-
-  if (_isVerbose)
-  {
-    while (signBuffer != MSG_DELIMITER)
-    {
-      signBuffer = recievedData[signCounter];
-      _verbosePort->write(signBuffer);
-      signCounter++;
-    }
-    _verbosePort->write('\n');
-  }
-  return _isVerbose;
-}
-
-//**************************************************************************
-// LITTLE HELPERS FOR CLIENTS ;-)
-//*************************************************************************
-
-EdgeDetector::EdgeDetector(){};
-EdgeDetector::~EdgeDetector(){};
-
-int EdgeDetector::edgeDetected(bool currentState)
-{
-  static bool lastState = false;
-  int edEdge = 0;
-
-  if (currentState && !lastState)
-  {
-    edEdge = RISING;
-  }
-  else if (!currentState && lastState)
-  {
-    edEdge = FALLING;
-  }
-  lastState = currentState;
-  return edEdge;
-}
-
-ChangeDetector::ChangeDetector() {}
-ChangeDetector::~ChangeDetector() {}
-
-bool ChangeDetector::valueChanged(int value, int threshold)
-{
-  static int lastValue = 0;
-
-  if (abs(value - lastValue) > threshold)
-  {
-    lastValue = value;
-    return true;
-  }
-  return false;
-}
-
-UnblockingTimer::UnblockingTimer() {}
-UnblockingTimer::~UnblockingTimer() {}
-
-bool UnblockingTimer::timeElapsed(long delayTime)
-{
-  long currentTime = millis();
-
-  if (lastTime + (delayTime - 1) < currentTime)
-  {
-    lastTime = currentTime;
-    return true;
-  }
-  return false;
-}
-
-SerialReader::SerialReader() {}
-SerialReader::~SerialReader() {}
-
-void SerialReader::begin(Stream &rsStream)
-{
-  _port = &rsStream;
-}
-
-int SerialReader::readSerialData(char *rsDataArray, char rsEndSign)
-{
-
-  if (_port->available())
-  {
-    char charBuffer = _port->read();
-    rsDataArray[charCounter] = charBuffer;
-
-    if (charBuffer == rsEndSign)
-    {
-      rsDataArray[charCounter] = '\0';
-      int nrOfChars = charCounter;
-      charCounter = 0;
-      return nrOfChars;
-    }
-    else
-    {
-      charCounter++;
-    }
-  }
-  return 0;
-}
-
-serialMonitorUI::serialMonitorUI() {}
-serialMonitorUI::~serialMonitorUI() {}
-
-char serialMonitorUI::extractCommand(char *userInput)
-{
-  if ((userInput[0] >= 33 && userInput[0] <= 47) || ((userInput[0] >= 58 && userInput[0] <= 64))) // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @
-  {
-    char command = userInput[0];
-    strcpy(userInput, &userInput[1]);
-    return command;
-  }
-  return DN_ASCII_EOS;
-}
-
-bool serialMonitorUI::available()
-{
-  if (SerialReader::readSerialData(_currentInput, DN_ASCII_CR) > 0)
-  {
-    _currentCommand = extractCommand(_currentInput);
-    return true;
-  }
-
-  return false;
-}
-
-char serialMonitorUI::readCommand()
-{
-  return _currentCommand;
-}
-
-void serialMonitorUI::readUserInput(char *inputData)
-{
-  strcpy(inputData, _currentInput);
-}
\ No newline at end of file
+/**************************************************************************/
\ No newline at end of file
diff --git a/src/DidacticNet.h b/src/DidacticNet.h
index 38643b4..2b6458a 100644
--- a/src/DidacticNet.h
+++ b/src/DidacticNet.h
@@ -8,242 +8,13 @@
 
 #include "Arduino.h"
 
-#ifdef CALLBACK_W_LENGTH
-// callback(topic, topicLength, payload, payloadLength)
-#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, int, char *, int)
-#else
-// callback(topic, payload)
-#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, char *)
-#endif
-
-#define CLIENT_MODE_BASIC false
-#define CLIENT_MODE_ADVANCED true
-
-#define MSG_PRELIMITER '<'
-#define MSG_DELIMITER '>'
-#define MSG_SEPARATOR '|'
-
-//@ publish   → on publish check topic, then send topic-update
-//? subscribe → subscribe starts update, topic filter @client
-// # update    → update to specific topic Broker to client
-#define MSG_PUBLISH '@'
-#define MSG_SUBSCRIBE '?'
-#define MSG_UPDATE '#'
-#define MSG_TOPIC_MULTI '*'
+#define DN_MSG_PRELIMITER '<'
+#define DN_MSG_DELIMITER '>'
+#define DN_MSG_SEPARATOR '|'
 
 //<@topic|payload>
-#define LEN_OVERHEAD 4
-
-#define CSMA_CHECK_DELAY_US 400
-#define CSMA_MIN_DELAY_MS 10
-#define CSMA_MID_DELAY_MS 20
-#define CSMA_MAX_DELAY_MS 30
-
-#define INTERVAL_CLIENT 500L
-#define INTERVAL_BROKER 0L
-
-#define MAX_NR_TOPICS_CLIENT 10
-#define MAX_NR_TOPICS_BROKER 20
-#define MAX_LEN_TOPICS 10
-#define MAX_LEN_PAYLOAD 20
-#define MAX_LEN_USERINPUT 41
-
-#define DN_PUBLISH_SUCCESSULL 1
-#define DN_ERROR_NO_ERROR 0
-#define DN_ERROR_TOPIC_LEN -1
-#define DN_ERROR_PAYLOAD_LEN -2
-#define DN_ERROR_NO_TOPIC -3
-
-// little helpers
-#define DN_ASCII_EOS 0
-#define DN_ASCII_CR 13
-#define DN_ASCII_NL 10
-#define DN_ASCII_DEL 127
-
-class EdgeDetector
-{
-private:
-public:
-	EdgeDetector();
-	~EdgeDetector();
-	int edgeDetected(bool);
-};
-
-class ChangeDetector
-{
-private:
-public:
-	ChangeDetector();
-	~ChangeDetector();
-	bool valueChanged(int, int);
-};
-
-class UnblockingTimer
-{
-private:
-	long lastTime = 0L;
-
-public:
-	UnblockingTimer();
-	~UnblockingTimer();
-	bool timeElapsed(long);
-};
-class SerialReader
-{
-protected:
-	Stream *_port;
-	int charCounter = 0;
-
-public:
-	SerialReader();
-	~SerialReader();
-	void begin(Stream &);
-	int readSerialData(char *, char);
-};
-
-class serialMonitorUI : public SerialReader
-{
-protected:
-	char _currentCommand = '\0';
-	char _currentInput[MAX_LEN_USERINPUT + 1] = {'\0'};
-
-	char extractCommand(char *);
-
-public:
-	serialMonitorUI();
-	~serialMonitorUI();
-	bool available();
-	char readCommand();
-	void readUserInput(char *);
-};
-
-class DidacticPSNet
-{
-protected:
-	Stream *_port;
-
-	PSNET_CALLBACK_SIGNATURE;
-
-	char _bufferTopic[MAX_LEN_TOPICS + 1] = {0};
-	char _bufferPayload[MAX_LEN_PAYLOAD + 1] = {0};
-	char _readBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD + 1];
-	char _sendBufferMessage[MAX_LEN_TOPICS + MAX_LEN_PAYLOAD + LEN_OVERHEAD + 1];
-
-	bool _dataToSend = false; // int Data to send for queue?
-	unsigned long _waitingTimeSend = 0L;
-	unsigned long _waitingTimeCSMA = 0L;
-	unsigned long _intervalTime = 0L;
-	int _currentTopicLength = 0;
-	int _currentPayloadLength = 0;
-
-	DidacticPSNet &setCallback(PSNET_CALLBACK_SIGNATURE);
-
-	void setStream(Stream &_port);
-
-	int checkData();
-	bool recieveData();
-	bool sendData();
-	int extractData(int, int, char *, char);
-	void writeDataToTopic(char *, char *);
-	virtual int getTopicNr(char *) = 0;
-	virtual int getFreeTopicNr() = 0;
-	virtual bool getMessageFilter(char) = 0;
-	virtual bool savePayload(char *, int) = 0;
-	virtual bool handleData() = 0;
-
-public:
-	DidacticPSNet();
-	~DidacticPSNet();
-
-	void begin(Stream &_port);
-	void begin(Stream &_port, PSNET_CALLBACK_SIGNATURE);
-
-	bool handleNetwork();
-	bool isDataToSend();
-
-	void setInterval(long);
-};
-
-class DidacticPSNetClient : public DidacticPSNet
-{
-private:
-	EdgeDetector eDetector;
-	ChangeDetector cDetector;
-
-	char _topic[MAX_NR_TOPICS_CLIENT][MAX_LEN_TOPICS + 1] = {{0}};
-	char _payload[MAX_NR_TOPICS_CLIENT][MAX_LEN_PAYLOAD + 1] = {{0}};
-
-	bool _clientMode = CLIENT_MODE_ADVANCED;
-	bool _newMessageAvailable = false;
-	int _newMessageTopicNr = 0;
-	char _currentTopic[MAX_LEN_TOPICS + 1] = {0};
-	char _currentPayload[MAX_LEN_PAYLOAD + 1] = {0};
-
-	bool savePayload(char *, int);
-	bool getMessageFilter(char);
-	bool handleData();
-	int getTopicNr(char *);
-	int getFreeTopicNr();
-
-	int edgeDetected(bool);
-	bool valueChanged(int, int);
-
-public:
-	DidacticPSNetClient();
-	~DidacticPSNetClient();
-
-	void begin(Stream &_port);
-	void begin(Stream &_port, PSNET_CALLBACK_SIGNATURE);
-
-	bool available();
-	int readLatestTopicNr();
-	void readTopic(char *);
-	void readTopic(int, char *);
-	void readPayload(char *);
-	void readPayload(int, char *);
-	void readPayload(char *, char *);
-	bool readBooleanPayload();
-	int readIntegerPayload();
-
-	int getMaxNrTopics();
-	int getSubscribedTopic(char *, int);
-
-	int publish(char *, char *);
-	int publish(char *, int, char *, int);
-	int publish(char *, int);
-	int publish(char *, bool);
-	int publishOnChange(char *, bool);
-	int publishOnChange(char *, int, int);
-	int subscribe(char *);
-	int subscribe(char *, int);
-	bool unsubscribe(char *);
-	bool unsubscribe(char *, int);
-};
-
-class DidacticPSNetBroker : public DidacticPSNet
-{
-private:
-	Stream *_verbosePort;
-	char _topic[MAX_NR_TOPICS_BROKER][MAX_LEN_TOPICS + 1] = {{0}};
-	char _data[MAX_NR_TOPICS_BROKER][MAX_LEN_PAYLOAD + 1] = {{0}};
-
-	bool _isVerbose = false;
-
-	bool savePayload(char *, int);
-	bool getMessageFilter(char);
-	void writeDataToTopic(int, char *, char *);
-	bool handleData();
-	int getTopicNr(char *);
-	int getFreeTopicNr();
-	bool update(char *, int, char *, int);
-	bool printVerbose(char *);
-
-public:
-	DidacticPSNetBroker();
-	~DidacticPSNetBroker();
-
-	void setVerbose(Stream &_port);
-	void setNoneVerbose();
-};
+#define DN_LEN_OVERHEAD 4
+#define DN_MAX_LEN_TELEGRAM 40
 
-#endif
+#include "DidacticNetTransmit.h"
+#include "DidacticNetPSN.h"
diff --git a/src/DidacticNetPSN.cpp b/src/DidacticNetPSN.cpp
new file mode 100644
index 0000000..64c1f39
--- /dev/null
+++ b/src/DidacticNetPSN.cpp
@@ -0,0 +1,473 @@
+/**************************************************************************/
+/*!
+    @file     DidacticNetPSN.cpp
+    @author   anian buehler @ letsgoING.org
+*/
+/**************************************************************************/
+
+#include "Arduino.h"
+
+//**************************************************************************
+// CLIENT
+//**************************************************************************
+DidacticNetPSNClient::~DidacticNetPSNClient() {}
+
+// NEW easy interface for non advanced users
+// ##########################################
+void DidacticNetPSNClient::begin(Stream &_port) // TODO: check if CLientMode is necessary or an unset callback ist not a problem
+{
+    DidacticNetTransmit::begin(_port);
+    _clientMode = CLIENT_MODE_BASIC;
+}
+
+void DidacticNetPSNClient::begin(Stream &_port, PSNET_CALLBACK_SIGNATURE)
+{
+    DidacticNetTransmit::begin(_port, callback);
+}
+
+bool DidacticNetPSNClient::available()
+{
+    return _newMessageAvailable;
+}
+
+int DidacticNetPSNClient::readLatestTopicNr()
+{
+    return _newMessageTopicNr;
+}
+
+void DidacticNetPSNClient::readTopic(int topicNr, char *topic)
+{
+    strcpy(topic, _topic[topicNr]);
+}
+
+void DidacticNetPSNClient::readTopic(char *topic)
+{
+    readTopic(_newMessageTopicNr, topic);
+}
+
+void DidacticNetPSNClient::readPayload(int topicNr, char *payload)
+{
+    strcpy(payload, _payload[topicNr]);
+
+    if (topicNr == _newMessageTopicNr)
+    {
+        _newMessageAvailable = false;
+    }
+}
+
+void DidacticNetPSNClient::readPayload(char *payload)
+{
+    readPayload(_newMessageTopicNr, payload);
+}
+
+void DidacticNetPSNClient::readPayload(char *topic, char *payload)
+{
+    int topicNr = getTopicNr(topic);
+    if (topicNr == _newMessageTopicNr)
+    {
+        _newMessageAvailable = false;
+    }
+    readPayload(topicNr, payload);
+}
+
+bool DidacticNetPSNClient::readBooleanPayload()
+{
+    _newMessageAvailable = false;
+    return _payload[_newMessageTopicNr][0] == '1';
+}
+
+int DidacticNetPSNClient::readIntegerPayload()
+{
+    _newMessageAvailable = false;
+    return atoi(_payload[_newMessageTopicNr]);
+}
+// ##########################################
+
+DidacticNetPSNClient::DidacticNetPSNClient()
+{
+    _intervalTime = PS_INTERVAL_CLIENT;
+}
+
+int DidacticNetPSNClient::publish(char *topic, char *payload)
+{
+    return publish(topic, strlen(topic), payload, strlen(payload));
+}
+
+int DidacticNetPSNClient::publish(char *topic, int topicLength, char *payload, int payloadLength)
+{
+    int error = DN_PUBLISH_SUCCESSULL;
+
+    _sendBufferMessage[0] = DN_MSG_PRELIMITER;
+    _sendBufferMessage[1] = PS_MSG_PUBLISH;
+    _sendBufferMessage[2 + topicLength] = DN_MSG_SEPARATOR;
+    _sendBufferMessage[2 + topicLength + 1 + payloadLength] = DN_MSG_DELIMITER;
+    _sendBufferMessage[2 + topicLength + 1 + payloadLength + 1] = '\0';
+
+    // TODO: check
+    if (topicLength > MAX_LEN_TOPICS)
+    {
+        topicLength = MAX_LEN_TOPICS;
+        error += PS_ERROR_TOPIC_LEN;
+    }
+    if (payloadLength > MAX_LEN_PAYLOAD)
+    {
+        payloadLength = MAX_LEN_PAYLOAD;
+        error += PS_ERROR_PAYLOAD_LEN;
+    }
+
+    for (int i = 0; i < topicLength; i++)
+    {
+        _sendBufferMessage[2 + i] = topic[i];
+    }
+    for (int i = 0; i < payloadLength; i++)
+    {
+        _sendBufferMessage[2 + topicLength + 1 + i] = payload[i];
+    }
+
+    _dataToSend = true;
+    return error;
+}
+
+int DidacticNetPSNClient::publish(char *topic, int data)
+{
+    char sendPayload[MAX_LEN_PAYLOAD];
+    itoa(data, sendPayload, 10);
+
+    return publish(topic, sendPayload);
+}
+
+int DidacticNetPSNClient::publish(char *topic, bool data)
+{
+    char sendPayload[2];
+    itoa(data, sendPayload, 10);
+
+    return publish(topic, sendPayload);
+}
+
+int DidacticNetPSNClient::publishOnChange(char *topic, bool input)
+{
+    if (!_dataToSend)
+    {
+        if (eDetector.edgeDetected(input))
+        {
+            return publish(topic, input);
+        }
+    }
+    return PS_ERROR_NO_ERROR;
+}
+
+int DidacticNetPSNClient::publishOnChange(char *topic, int input, int threshold)
+{
+    if (!_dataToSend)
+    {
+        if (cDetector.valueChanged(input, threshold))
+        {
+            return publish(topic, input);
+        }
+    }
+    return PS_ERROR_NO_ERROR;
+}
+
+int DidacticNetPSNClient::subscribe(char *topic)
+{
+    return subscribe(topic, strlen(topic));
+}
+
+int DidacticNetPSNClient::subscribe(char *topic, int topicLength)
+{
+    int error = PS_ERROR_NO_ERROR;
+
+    if (topicLength > MAX_LEN_TOPICS)
+    {
+        topicLength = MAX_LEN_TOPICS;
+        error = PS_ERROR_TOPIC_LEN;
+    }
+
+    _sendBufferMessage[0] = DN_MSG_PRELIMITER;
+    _sendBufferMessage[1] = PS_MSG_SUBSCRIBE;
+    _sendBufferMessage[2 + topicLength] = DN_MSG_DELIMITER;
+
+    int topicNumber = getTopicNr(topic);
+
+    if (topicNumber < 0)
+    {
+        topicNumber = getFreeTopicNr();
+        if (topicNumber < 0)
+        {
+            topicNumber = 0;
+        }
+        for (int i = 0; i < topicLength; i++)
+        {
+            _topic[topicNumber][i] = topic[i];
+            _sendBufferMessage[2 + i] = topic[i];
+        }
+        _topic[topicNumber][topicLength] = '\0';
+        _sendBufferMessage[2 + topicLength + 1] = '\0';
+        _dataToSend = true;
+    }
+    else
+    {
+        for (int i = 0; i < topicLength; i++)
+        {
+            _sendBufferMessage[2 + i] = topic[i];
+        }
+        _sendBufferMessage[2 + topicLength + 1] = '\0';
+        _dataToSend = true;
+    }
+    while (_dataToSend)
+    {
+        handleNetwork();
+    }
+    return error;
+}
+
+bool DidacticNetPSNClient::unsubscribe(char *topic)
+{
+    return unsubscribe(topic, strlen(topic));
+}
+
+bool DidacticNetPSNClient::unsubscribe(char *topic, int topicLength)
+{
+    int topicNumber = getTopicNr(topic);
+    if (topicNumber >= 0)
+    {
+        _topic[topicNumber][0] = '\0';
+        return true;
+    }
+    return false;
+}
+
+bool DidacticNetPSNClient::getMessageFilter(char messageType)
+{
+    return messageType == PS_MSG_UPDATE;
+}
+
+bool DidacticNetPSNClient::savePayload(char *buffer, int position)
+{
+    strcpy(_payload[position], buffer);
+    return true;
+}
+
+bool DidacticNetPSNClient::handleData()
+{
+    int currentTopicNr = 0;
+    int topicLength = 0;
+    int payloadLength = 0;
+    topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, DN_MSG_SEPARATOR);
+    if (topicLength > 0)
+    {
+        currentTopicNr = getTopicNr(_bufferTopic);
+        payloadLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, DN_MSG_DELIMITER);
+        if (currentTopicNr >= 0)
+        {
+            savePayload(_bufferPayload, currentTopicNr);
+            _newMessageAvailable = true;
+            _newMessageTopicNr = currentTopicNr;
+
+            if (_clientMode == CLIENT_MODE_ADVANCED)
+            {
+#ifdef CALLBACK_W_LENGTH
+                callback(_bufferTopic, topicLength, _bufferPayload, payloadLength);
+#else
+                callback(_bufferTopic, _bufferPayload);
+#endif
+            }
+        }
+    }
+    return true;
+}
+
+int DidacticNetPSNClient::getTopicNr(char *topic)
+{
+    for (int i = 0; i < PS_MAX_NR_TOPICS_CLIENT; i++)
+    {
+        if (strcmp(_topic[i], topic) == 0 || _topic[i][0] == PS_MSG_TOPIC_MULTI)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int DidacticNetPSNClient::getFreeTopicNr()
+{
+    for (int i = 0; i < PS_MAX_NR_TOPICS_CLIENT; i++)
+    {
+        if (strcmp(_topic[i], "") == 0)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int DidacticNetPSNClient::getSubscribedTopic(char *topic, int number)
+{
+    if (number > 0 && number < getMaxNrTopics())
+    {
+        strcpy(topic, _topic[number]);
+        return PS_ERROR_NO_ERROR;
+    }
+    return PS_ERROR_NO_TOPIC;
+}
+
+int DidacticNetPSNClient::getMaxNrTopics()
+{
+    return getFreeTopicNr();
+}
+
+//**************************************************************************
+// Broker
+//**************************************************************************
+DidacticNetPSNBroker::DidacticNetPSNBroker()
+{
+    _intervalTime = PS_INTERVAL_BROKER;
+}
+
+DidacticNetPSNBroker::~DidacticNetPSNBroker() {}
+
+bool DidacticNetPSNBroker::getMessageFilter(char messageType)
+{
+    return (messageType == PS_MSG_PUBLISH || messageType == PS_MSG_SUBSCRIBE);
+}
+
+bool DidacticNetPSNBroker::savePayload(char *buffer, int position)
+{
+    strcpy(_data[position], buffer);
+    return true;
+}
+
+void DidacticNetPSNBroker::writeDataToTopic(int topicNumber, char *usedTopic, char *newData)
+{
+    if (strcmp(_topic[topicNumber], "") == 0)
+    {
+        strcpy(_topic[topicNumber], usedTopic);
+    }
+    strcpy(_data[topicNumber], newData);
+}
+
+bool DidacticNetPSNBroker::handleData()
+{
+    int currentTopicNr = 0;
+    int topicLength = 0;
+    int dataLength = 0;
+
+    printVerbose(_readBufferMessage);
+
+    if (_readBufferMessage[1] == PS_MSG_PUBLISH)
+    {
+        topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, DN_MSG_SEPARATOR);
+        if (topicLength > 0)
+        {
+            currentTopicNr = getTopicNr(_bufferTopic);
+            dataLength = extractData(topicLength + 3, MAX_LEN_PAYLOAD, _bufferPayload, DN_MSG_DELIMITER);
+            if (currentTopicNr >= 0)
+            {
+                writeDataToTopic(currentTopicNr, _bufferTopic, _bufferPayload);
+                update(_topic[currentTopicNr], topicLength, _data[currentTopicNr], dataLength);
+            }
+        }
+    }
+    else if (_readBufferMessage[1] == PS_MSG_SUBSCRIBE)
+    {
+        topicLength = extractData(2, MAX_LEN_TOPICS, _bufferTopic, DN_MSG_DELIMITER);
+        if (topicLength > 0)
+        {
+            currentTopicNr = getTopicNr(_bufferTopic);
+            if (currentTopicNr >= 0)
+            {
+                update(_topic[currentTopicNr], strlen(_topic[currentTopicNr]), _data[currentTopicNr], strlen(_data[currentTopicNr]));
+            }
+        }
+    }
+    return true;
+}
+
+bool DidacticNetPSNBroker::update(char *topic, int topicLength, char *data, int dataLength)
+{
+    _sendBufferMessage[0] = DN_MSG_PRELIMITER;
+    _sendBufferMessage[1] = PS_MSG_UPDATE;
+    _sendBufferMessage[2 + topicLength] = DN_MSG_SEPARATOR;
+    _sendBufferMessage[2 + topicLength + 1 + dataLength] = DN_MSG_DELIMITER;
+    _sendBufferMessage[2 + topicLength + 1 + dataLength + 1] = '\0';
+
+    if (topicLength <= MAX_LEN_TOPICS)
+    {
+        for (int i = 0; i < topicLength; i++)
+        {
+            _sendBufferMessage[2 + i] = topic[i];
+        }
+    }
+    else
+    {
+        _dataToSend = false;
+        return false;
+    }
+    if (dataLength <= MAX_LEN_PAYLOAD)
+    {
+        for (int i = 0; i < dataLength; i++)
+        {
+            _sendBufferMessage[2 + topicLength + 1 + i] = data[i];
+        }
+    }
+    else
+    {
+        _dataToSend = false;
+        return false;
+    }
+    _dataToSend = true;
+    return true;
+}
+
+int DidacticNetPSNBroker::getTopicNr(char *topic)
+{
+    for (int i = 0; i < PS_MAX_NR_TOPICS_BROKER; i++)
+    {
+        if (strcmp(_topic[i], topic) == 0)
+        {
+            return i;
+        }
+    }
+    return getFreeTopicNr();
+}
+
+int DidacticNetPSNBroker::getFreeTopicNr()
+{
+    for (int i = 0; i < PS_MAX_NR_TOPICS_BROKER; i++)
+    {
+        if (strcmp(_topic[i], "") == 0)
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+void DidacticNetPSNBroker::setVerbose(Stream &verbosePort)
+{
+    _isVerbose = true;
+    _verbosePort = &verbosePort;
+}
+
+void DidacticNetPSNBroker::setNoneVerbose()
+{
+    _isVerbose = false;
+}
+
+bool DidacticNetPSNBroker::printVerbose(char *recievedData)
+{
+    char signBuffer = 0;
+    int signCounter = 0;
+
+    if (_isVerbose)
+    {
+        while (signBuffer != DN_MSG_DELIMITER)
+        {
+            signBuffer = recievedData[signCounter];
+            _verbosePort->write(signBuffer);
+            signCounter++;
+        }
+        _verbosePort->write('\n');
+    }
+    return _isVerbose;
+}
diff --git a/src/DidacticNetPSN.h b/src/DidacticNetPSN.h
new file mode 100644
index 0000000..726bef7
--- /dev/null
+++ b/src/DidacticNetPSN.h
@@ -0,0 +1,124 @@
+/**************************************************************************
+    @file     DidacticNet.h
+    @author   anian buehler @ letsgoING
+**************************************************************************/
+
+#include "Detector.h"
+
+// PubSub
+#ifdef CALLBACK_W_LENGTH
+// callback(topic, topicLength, payload, payloadLength)
+#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, int, char *, int)
+#else
+// callback(topic, payload)
+#define PSNET_CALLBACK_SIGNATURE void (*callback)(char *, char *)
+#endif
+
+#define PS_CLIENT_MODE_BASIC false
+#define PS_CLIENT_MODE_ADVANCED true
+
+//@ publish   → on publish check topic, then send topic-update
+//? subscribe → subscribe starts update, topic filter @client
+// # update    → update to specific topic Broker to client
+#define PS_MSG_PUBLISH '@'
+#define PS_MSG_SUBSCRIBE '?'
+#define PS_MSG_UPDATE '#'
+#define PS_MSG_TOPIC_MULTI '*'
+
+#define PS_MAX_NR_TOPICS_CLIENT 10
+#define PS_MAX_NR_TOPICS_BROKER 20
+#define PS_MAX_LEN_TOPICS 10
+#define PS_MAX_LEN_PAYLOAD 20
+
+#define PS_PUBLISH_SUCCESSULL 1
+#define PS_ERROR_NO_ERROR 0
+#define PS_ERROR_TOPIC_LEN -1
+#define PS_ERROR_PAYLOAD_LEN -2
+#define PS_ERROR_NO_TOPIC -3
+
+#define PS_INTERVAL_CLIENT 500L
+#define PS_INTERVAL_BROKER 0L
+
+class DidacticPSNetClient : public DidacticNetTransmit
+{
+private:
+    EdgeDetector eDetector;
+    ChangeDetector cDetector;
+
+    char _topic[PS_MAX_NR_TOPICS_CLIENT][PS_MAX_LEN_TOPICS + 1] = {{0}};
+    char _payload[PS_MAX_NR_TOPICS_CLIENT][PS_MAX_LEN_PAYLOAD + 1] = {{0}};
+
+    bool _clientMode = PS_CLIENT_MODE_ADVANCED;
+    bool _newMessageAvailable = false;
+    int _newMessageTopicNr = 0;
+    char _currentTopic[MAX_LEN_TOPICS + 1] = {0};
+    char _currentPayload[MAX_LEN_PAYLOAD + 1] = {0};
+
+    bool savePayload(char *, int);
+    bool getMessageFilter(char);
+    bool handleData();
+    int getTopicNr(char *);
+    int getFreeTopicNr();
+
+    int edgeDetected(bool);
+    bool valueChanged(int, int);
+
+public:
+    DidacticPSNetClient();
+    ~DidacticPSNetClient();
+
+    void begin(Stream &_port);
+    void begin(Stream &_port, PSNET_CALLBACK_SIGNATURE);
+
+    bool available();
+    int readLatestTopicNr();
+    void readTopic(char *);
+    void readTopic(int, char *);
+    void readPayload(char *);
+    void readPayload(int, char *);
+    void readPayload(char *, char *);
+    bool readBooleanPayload();
+    int readIntegerPayload();
+
+    int getMaxNrTopics();
+    int getSubscribedTopic(char *, int);
+
+    int publish(char *, char *);
+    int publish(char *, int, char *, int);
+    int publish(char *, int);
+    int publish(char *, bool);
+    int publishOnChange(char *, bool);
+    int publishOnChange(char *, int, int);
+    int subscribe(char *);
+    int subscribe(char *, int);
+    bool unsubscribe(char *);
+    bool unsubscribe(char *, int);
+};
+
+class DidacticPSNetBroker : public DidacticNetTransmit
+{
+private:
+    Stream *_verbosePort;
+    char _topic[MAX_NR_TOPICS_BROKER][MAX_LEN_TOPICS + 1] = {{0}};
+    char _data[MAX_NR_TOPICS_BROKER][MAX_LEN_PAYLOAD + 1] = {{0}};
+
+    bool _isVerbose = false;
+
+    bool savePayload(char *, int);
+    bool getMessageFilter(char);
+    void writeDataToTopic(int, char *, char *);
+    bool handleData();
+    int getTopicNr(char *);
+    int getFreeTopicNr();
+    bool update(char *, int, char *, int);
+    bool printVerbose(char *);
+
+public:
+    DidacticPSNetBroker();
+    ~DidacticPSNetBroker();
+
+    void setVerbose(Stream &_port);
+    void setNoneVerbose();
+};
+
+#endif
diff --git a/src/DidacticNetTransmit.cpp b/src/DidacticNetTransmit.cpp
new file mode 100644
index 0000000..d5b7747
--- /dev/null
+++ b/src/DidacticNetTransmit.cpp
@@ -0,0 +1,167 @@
+/**************************************************************************/
+/*!
+    @file     DidacticNetTransmit.cpp
+    @author   anian buehler @ letsgoING.org
+*/
+/**************************************************************************/
+
+#include "DidacticNetTransmit.h"
+
+DidacticNetTransmit::DidacticNetTransmit() {}
+DidacticNetTransmit::~DidacticNetTransmit() {}
+
+void DidacticNetTransmit::begin(Stream &_port)
+{
+    setStream(_port);
+}
+
+void DidacticNetTransmit::begin(Stream &_port, PSNET_CALLBACK_SIGNATURE)
+{
+    setStream(_port);
+    setCallback(callback);
+}
+
+DidacticNetTransmit &DidacticNetTransmit::setCallback(PSNET_CALLBACK_SIGNATURE)
+{
+    this->callback = callback;
+    return *this;
+}
+
+void DidacticNetTransmit::setStream(Stream &stream)
+{
+    _port = &stream;
+}
+
+bool DidacticNetTransmit::handleNetwork()
+{
+    if (dataAvailable())
+    {
+        if (recieveData())
+        {
+            if (getMessageFilter(_readBufferMessage[1]))
+            {
+                handleData();
+            }
+        }
+        _waitingTimeCSMA = millis() + random(CSMA_MIN_DELAY_MS, CSMA_MAX_DELAY_MS);
+    }
+    if (_dataToSend && _waitingTimeSend <= millis() && _waitingTimeCSMA <= millis())
+    {
+        // send data to network
+        unsigned long delayStartTime = micros();
+        while (micros() < delayStartTime + CSMA_CHECK_DELAY_US)
+            ;
+        if (!dataAvailable())
+        {
+            if (sendData())
+            {
+                _dataToSend = false;
+                _waitingTimeSend = millis() + _intervalTime;
+            }
+        }
+    }
+    return !_dataToSend; // return true if sending is done
+}
+
+bool DidacticNetTransmit::isDataToSend()
+{
+    return _dataToSend;
+}
+
+bool DidacticNetTransmit::sendData()
+{
+    int counter = 0;
+    bool messageSent = false;
+    while (!messageSent)
+    {
+        if (counter >= DN_MAX_LEN_TELEGRAM - 1)
+        {
+            _sendBufferMessage[counter] = DN_MSG_DELIMITER; // cut message and stop sending
+            messageSent = true;
+        }
+        else if (_sendBufferMessage[counter] == DN_MSG_DELIMITER)
+        {
+            messageSent = true;
+        }
+
+        _port->write(_sendBufferMessage[counter]);
+        counter++;
+    }
+    return true;
+}
+
+int DidacticNetTransmit::extractData(int startCounter, int maxLength, char *buffer, char limiter)
+{
+    int counter = startCounter;
+    while (_readBufferMessage[counter] != limiter)
+    {
+        buffer[counter - startCounter] = _readBufferMessage[counter];
+        counter++;
+        if ((counter - startCounter) > maxLength)
+        {
+            counter--;
+            break; // if > maxLenght -> leave while and return
+        }
+    }
+    buffer[counter - startCounter] = '\0';
+    return counter - startCounter; // length
+}
+
+int DidacticNetTransmit::dataAvailable()
+{
+    return (int)_port->available();
+}
+
+bool DidacticNetTransmit::recieveData()
+{
+
+    static int msgCounter = 0;
+    static int topicCounter = 0;   // check if needed?
+    static int payloadCounter = 0; // check if needed?
+
+    while (dataAvailable())
+    {
+        char localBuffer = _port->read();
+        if (localBuffer == DN_MSG_PRELIMITER)
+        {
+            msgCounter = 0;
+            topicCounter = 0;
+            payloadCounter = 0;
+            _readBufferMessage[msgCounter] = localBuffer;
+        }
+        else if (localBuffer == DN_MSG_DELIMITER && _readBufferMessage[0] == DN_MSG_PRELIMITER)
+        {
+            msgCounter++;
+            _readBufferMessage[msgCounter] = localBuffer;
+            _readBufferMessage[msgCounter + 1] = '0';
+            msgCounter = 0;
+            return true;
+        }
+        // check if needed? Don't think so...
+        else if (localBuffer == DN_MSG_SEPARATOR && _readBufferMessage[0] == DN_MSG_PRELIMITER)
+        {
+            topicCounter = msgCounter - 2;
+            msgCounter++;
+            _readBufferMessage[msgCounter] = localBuffer;
+        }
+        else if (_readBufferMessage[0] == DN_MSG_PRELIMITER && localBuffer != DN_MSG_DELIMITER)
+        {
+            if (msgCounter > DN_MAX_LEN_TELEGRAM)
+            {
+                msgCounter == 0;
+                _readBufferMessage[0] = '\0';
+            }
+            else
+            {
+                msgCounter++;
+                _readBufferMessage[msgCounter] = localBuffer;
+            }
+        }
+    }
+    return false;
+}
+
+void DidacticNetTransmit::setInterval(long intervalTime)
+{
+    _intervalTime = intervalTime;
+}
\ No newline at end of file
diff --git a/src/DidacticNetTransmit.h b/src/DidacticNetTransmit.h
new file mode 100644
index 0000000..6abbce5
--- /dev/null
+++ b/src/DidacticNetTransmit.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+    @file     DidacticNetTransmit.h
+    @author   anian buehler @ letsgoING
+**************************************************************************/
+
+#ifndef _DIDACTICNETTRANSMIT_
+#define _DIDACTICNETTRANSMIT_
+
+#include "Arduino.h"
+
+#define DN_LEN_OVERHEAD 4
+
+#define DNT_CSMA_CHECK_DELAY_US 400
+#define DNT_CSMA_MIN_DELAY_MS 10
+#define DNT_CSMA_MID_DELAY_MS 20
+#define DNT_CSMA_MAX_DELAY_MS 30
+
+class DidacticNetTransmit
+{
+protected:
+    Stream *_port;
+
+    PSNET_CALLBACK_SIGNATURE;
+
+    char _bufferTopic[MAX_LEN_TOPICS + 1] = {0};
+    char _bufferPayload[MAX_LEN_PAYLOAD + 1] = {0};
+    char _readBufferMessage[DN_MAX_LEN_TELEGRAM + 1];
+    char _sendBufferMessage[DN_MAX_LEN_TELEGRAM + 1];
+
+    bool _dataToSend = false; // int Data to send for queue?
+    unsigned long _waitingTimeSend = 0L;
+    unsigned long _waitingTimeCSMA = 0L;
+    unsigned long _intervalTime = 0L;
+    int _currentTopicLength = 0;
+    int _currentPayloadLength = 0;
+
+    DidacticNetTransmit &setCallback(PSNET_CALLBACK_SIGNATURE);
+
+    void setStream(Stream &_port);
+
+    int checkData();
+    bool recieveData();
+    bool sendData();
+    int extractData(int, int, char *, char);
+    void writeDataToTopic(char *, char *);
+    virtual int getTopicNr(char *) = 0;
+    virtual int getFreeTopicNr() = 0;
+    virtual bool getMessageFilter(char) = 0;
+    virtual bool savePayload(char *, int) = 0;
+    virtual bool handleData() = 0;
+
+public:
+    DidacticNetTransmit();
+    ~DidacticNetTransmit();
+
+    void begin(Stream &_port);
+    void begin(Stream &_port, PSNET_CALLBACK_SIGNATURE);
+
+    bool handleNetwork();
+    bool isDataToSend();
+
+    void setInterval(long);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/SerialUI.cpp b/src/SerialUI.cpp
new file mode 100644
index 0000000..5365fe8
--- /dev/null
+++ b/src/SerialUI.cpp
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/*!
+    @file     SerialReader.cpp
+    @author   anian buehler @ letsgoING.org
+*/
+/**************************************************************************/
+
+#include SerialUI.h
+
+SerialReader::SerialReader() {}
+SerialReader::~SerialReader() {}
+
+void SerialReader::begin(Stream &rsStream)
+{
+    _port = &rsStream;
+}
+
+int SerialReader::readSerialData(char *rsDataArray, char rsEndSign)
+{
+
+    if (_port->available())
+    {
+        char charBuffer = _port->read();
+        rsDataArray[charCounter] = charBuffer;
+
+        if (charBuffer == rsEndSign)
+        {
+            rsDataArray[charCounter] = '\0';
+            int nrOfChars = charCounter;
+            charCounter = 0;
+            return nrOfChars;
+        }
+        else
+        {
+            charCounter++;
+        }
+    }
+    return 0;
+}
+
+serialMonitorUI::serialMonitorUI() {}
+serialMonitorUI::~serialMonitorUI() {}
+
+char serialMonitorUI::extractCommand(char *userInput)
+{
+    if ((userInput[0] >= 33 && userInput[0] <= 47) || ((userInput[0] >= 58 && userInput[0] <= 64))) // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @
+    {
+        char command = userInput[0];
+        strcpy(userInput, &userInput[1]);
+        return command;
+    }
+    return DN_ASCII_EOS;
+}
+
+bool serialMonitorUI::available()
+{
+    if (SerialReader::readSerialData(_currentInput, DN_ASCII_CR) > 0)
+    {
+        _currentCommand = extractCommand(_currentInput);
+        return true;
+    }
+
+    return false;
+}
+
+char serialMonitorUI::readCommand()
+{
+    return _currentCommand;
+}
+
+void serialMonitorUI::readUserInput(char *inputData)
+{
+    strcpy(inputData, _currentInput);
+}
\ No newline at end of file
diff --git a/src/SerialUI.h b/src/SerialUI.h
new file mode 100644
index 0000000..0b26e49
--- /dev/null
+++ b/src/SerialUI.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+	@file     SerialReader.h
+	@author   anian buehler @ letsgoING
+**************************************************************************/
+
+#ifndef _LGI_SERIALUI_
+#define _LGI_SERIALUI_
+
+#include "Arduino.h"
+
+#define SUI_MAX_LEN_USERINPUT 41
+
+// little helpers
+#define SUI_ASCII_EOS 0
+#define SUI_ASCII_CR 13
+#define SUI_ASCII_NL 10
+#define SUI_ASCII_DEL 127
+
+class SerialReader
+{
+protected:
+	Stream *_port;
+	int charCounter = 0;
+
+public:
+	SerialReader();
+	~SerialReader();
+	void begin(Stream &);
+	int readSerialData(char *, char);
+};
+
+class serialMonitorUI : public SerialReader
+{
+protected:
+	char _currentCommand = SUI_ASCII_EOS;
+	char _currentInput[SUI_MAX_LEN_USERINPUT + 1] = {SUI_ASCII_EOS};
+
+	char extractCommand(char *);
+
+public:
+	serialMonitorUI();
+	~serialMonitorUI();
+	bool available();
+	char readCommand();
+	void readUserInput(char *);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/UnblockingTimer.cpp b/src/UnblockingTimer.cpp
new file mode 100644
index 0000000..2685229
--- /dev/null
+++ b/src/UnblockingTimer.cpp
@@ -0,0 +1,23 @@
+/**************************************************************************/
+/*!
+    @file     UnblockingTimer.cpp
+    @author   anian buehler @ letsgoING.org
+*/
+/**************************************************************************/
+
+#include UnblockingTimer.h
+
+UnblockingTimer::UnblockingTimer() {}
+UnblockingTimer::~UnblockingTimer() {}
+
+bool UnblockingTimer::timeElapsed(long delayTime)
+{
+    long currentTime = millis();
+
+    if (lastTime + (delayTime - 1) < currentTime)
+    {
+        lastTime = currentTime;
+        return true;
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/UnblockingTimer.h b/src/UnblockingTimer.h
new file mode 100644
index 0000000..63530aa
--- /dev/null
+++ b/src/UnblockingTimer.h
@@ -0,0 +1,22 @@
+/**************************************************************************
+    @file     UnblockingTimer.h
+    @author   anian buehler @ letsgoING
+**************************************************************************/
+
+#ifndef _LGI_UNBLOCKINGTIMER_
+#define _LGI_UNBLOCKINGTIMER_
+
+#include "Arduino.h"
+
+class UnblockingTimer
+{
+private:
+    long lastTime = 0L;
+
+public:
+    UnblockingTimer();
+    ~UnblockingTimer();
+    bool timeElapsed(long);
+};
+
+#endif
\ No newline at end of file
-- 
GitLab